TurboPanel Docs
Architecture

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

Diagram will load when scrolled into view
PieceRole
ProxySQLOne compose project per managed server, with configuration under /etc/turbopanel/proxysql/. Inventory: system component managed-ingress, container <serviceId>-in, container role ingress
ListenersHost TCP 15432 (Postgres family) and 13306 (MySQL family)
BackendsEngine containers on the organization's managed Docker network, or private (site) / TurboFabric — or, as a last resort, public — addresses of remote members
UsersNon-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:

PortProtocolAudience
15432TCPPostgres-family clients through ProxySQL
13306TCPMySQL / MariaDB clients through ProxySQL
127.0.0.1:6032TCPProxySQL admin (loopback only)
45000–45999TCPMember 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.0 and 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 replication line scoped to the peer address (/32 or /128); MySQL / MariaDB replication grants carry REQUIRE 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:

  1. Instance materializes service-scoped variables (host, port, user, password, URL, CA paths) — secret values never reappear on later GETs.
  2. 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.
  3. Binding create/update/delete enqueues managed.ingress.reconcile for the consumer server and cluster member servers so frontend users and servers stay aligned with sealed principal passwords.

Replicas and failover

ConcernBehavior
PlacementMulti-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 splitWhen a replica is read_eligible, ProxySQL can route SELECTs to the reader hostgroup
ApplyPrimary managed.apply enqueues immediately; standby applies follow only after primary success (command consumer)
PromoteFence (stop) old primary, then promote replica — promote command is chained only after successful fence
Remove replicaMember stays applying until managed.destroy succeeds; destroy failure leaves the row failed and retryable

Commands

CommandWhoPurpose
managed.apply / .lifecycle / .destroy / .promoteMember hostEngine lifecycle
managed.ingress.reconcileEach server that needs a frontendProxySQL 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.

Edit on GitHub

Last updated on

On this page