Managed database ingress
TurboPanel managed databases do not publish engine ports on the host. Client
SQL (operators, apps, binding-emitted DSNs) always dials a per-server ProxySQL
frontend that the daemon configures via managed.ingress.reconcile.
Topology
| Piece | Role |
|---|---|
| ProxySQL | One compose project per managed server, with configuration under /etc/turbopanel/proxysql/. Inventory: system component managed-ingress, container <serviceId>-in, container role ingress |
| Listeners | Host TCP 15432 (Postgres family) and 13306 (MySQL family) |
| Backends | Engine containers on the organization's managed Docker network, or private (site) / TurboFabric — or, as a last resort, public — addresses of remote members |
| Users | Non-replication managed principals resealed for that server — binding-created users included |
Replication principals never become ProxySQL frontend users.
Names you never have to type
TurboPanel allocates the Docker network that carries managed engine traffic —
one per organization — and the ProxySQL compose project on each managed server.
Both names are assigned by the platform and are not meant to be typed, guessed,
or referenced by an operator: you reach a managed database through its
connection panel or a binding, and you manage the stack through TurboPanel, not
through docker on the host. Nothing on a managed server is expected to carry a
human-readable Docker name. The one exception is the self-hosted TurboPanel
instance stack itself, whose compose project stays turbopanel-system because
operators do inspect it directly.
Ports and firewall
On each server that hosts a managed member or a placed compose service bound to a managed cluster:
| Port | Protocol | Audience |
|---|---|---|
| 15432 | TCP | Postgres-family clients through ProxySQL |
| 13306 | TCP | MySQL / MariaDB clients through ProxySQL |
| 127.0.0.1:6032 | TCP | ProxySQL admin (loopback only) |
| 45000–45999 | TCP | Member private listeners (replication + remote backends) |
Firewall guidance:
- Prefer site/datacenter private CIDRs (and TurboFabric) for server-to-server engine traffic.
- Restrict public exposure of 15432/13306 to operator IP ranges when exposure is
public. - Engine containers themselves never publish host ports for SQL.
Public replication transport
When a remote read replica shares no trusted datacenter subnet and no
TurboFabric mesh with its primary, the cluster falls back to the public
transport — the last rung of the local → datacenter → TurboFabric → public
ladder. The datacenter rung picks the lowest-priority shared trusted
datacenter (priority asc, then id); an untrusted shared datacenter is skipped
as if it were not shared. A failover pair whose only shared datacenters are
untrusted is refused with 422 failover_requires_trusted_datacenter rather
than silently falling through (see Datacenter
networks):
- The member publishes its replication/backend listener on one concrete public
address at the allocated private port — never
0.0.0.0and never loopback. - TLS is mandatory. The daemon refuses a public listener without
Organization CA material, so the engine only ever starts with its Organization
CA leaf (SANs include that public IP) and the trust bundle on disk. Postgres
accepts the peer through a
hostssl replicationline scoped to the peer address (/32or/128); MySQL / MariaDB replication grants carryREQUIRE SSL, so the server enforces TLS regardless of what the standby requests. - The daemon additionally installs address-scoped firewall rules that allow only the known peer address(es) to reach that published port and drop everything else. If no stable peer address is known, no rule is installed and no broad fallback is ever added.
See also Deployment security and Self-hosted overview.
Stable client endpoint
Promotion changes the ProxySQL writer hostgroup, never the host or port
operators and apps dial. The advertised endpoint stays host:15432 /
host:13306 on the placement server (member or bound consumer). There is no
DNS or floating-IP primary discovery and no ProxySQL-to-ProxySQL chaining.
Promote stays operator-triggered — there is no automatic failover.
Lazy placement and teardown
The ProxySQL stack exists on a server only when that server hosts a managed
member or a compose service bound to a managed cluster. Emptying a server
enqueues managed.ingress.reconcile with clusters: [], which runs
docker compose down --remove-orphans. Servers that never had a stack are left
untouched.
Rollout: listener port move
Already-running consumer containers keep injected *_PORT=5432/3306 until
their next deploy. Binding variables are recomputed in deploy-prepare.ts on
every deploy — after this ingress port move, consuming environments must be
redeployed to pick up 15432 / 13306. No schema migration is required.
TLS and Organization CA
- Managed engines default to TLS on; Postgres connection strings use
sslmode=verify-full(and MySQL-family equivalents with server verification). - ProxySQL frontend certificates are Organization CA leaves. SANs include the advertised listener host (connection panel / binding host), bind IP when applicable, and private peer endpoints used as backends — not only synthetic container names.
- Operators download the Organization CA trust bundle (active + retired) from
Connect → Download CA certificate (
GET /api/client/v1/tls/ca/download). Trust that bundle on clients; never ship private keys over the client API. Rotation, renewal, and the client-impact checklist live in Organization CA.
Bindings (credentials → compose)
A binding connects a managed database principal to a compose service:
- Instance materializes service-scoped variables (host, port, user, password, URL, CA paths) — secret values never reappear on later GETs.
- Host/port always resolve to the consuming service’s placement server ProxySQL listener (even when engine members live elsewhere). ProxySQL on that host is reconciled with routes to remote backends over the private path. ProxySQL may also join the consuming environment's spanning network so cross-host consumers resolve it by name.
- Binding create/update/delete enqueues
managed.ingress.reconcilefor the consumer server and cluster member servers so frontend users and servers stay aligned with sealed principal passwords.
Replicas and failover
| Concern | Behavior |
|---|---|
| Placement | Multi-member clusters walk the local → datacenter → TurboFabric → public ladder between servers; the datacenter rung is the lowest-priority shared trusted datacenter. Failover replicas stop at datacenter — an untrusted-only pair is 422 failover_requires_trusted_datacenter, never a silent fallback; only read replicas continue to TurboFabric and then to a TLS-mandatory, address-scoped public listener |
| Read split | When a replica is read_eligible, ProxySQL can route SELECTs to the reader hostgroup |
| Apply | Primary managed.apply enqueues immediately; standby applies follow only after primary success (command consumer) |
| Promote | Fence (stop) old primary, then promote replica — promote command is chained only after successful fence |
| Remove replica | Member stays applying until managed.destroy succeeds; destroy failure leaves the row failed and retryable |
Commands
| Command | Who | Purpose |
|---|---|---|
managed.apply / .lifecycle / .destroy / .promote | Member host | Engine lifecycle |
managed.ingress.reconcile | Each server that needs a frontend | ProxySQL compose, durable cnf, admin apply |
HTTP managed routes return command ids immediately; the UI polls Postgres command rows. Dependent follow-ups (standbys, promote after fence, primary re-apply after member destroy) are enqueued by the command consumer on success only.
Related
Last updated on
Server metrics architecture
Shared host-metrics contract (schema v6), Analytics Engine and DuckDB + Parquet storage, retention windows, the per-tier row inventory, and the dated Cloudflare cost model
Datacenter networks
A datacenter is a logical routing domain — priority and trust, the local → datacenter → fabric → public ladder, the CIDR collision matrix, reserved ranges, and why TurboPanel never configures a host interface