Control plane and regions
The control plane
Section titled “The control plane”One deployment serves every region and every organisation. It is a plain web application:
- Console — Next.js, server-rendered, no state of its own.
- API — Hono on Node.js. Validates, authorises, allocates, writes intent and jobs, returns. It is the only writer to the database.
- Database — PostgreSQL. Intent, allocations, the job queue, the audit trail, and the cached reflection of infrastructure truth. There is no separate queue system; the queue is a table, which means a job and the intent that produced it commit together or not at all.
The control plane has no long-running connection to any region, and in agent mode it holds no hypervisor credentials at all.
Regions
Section titled “Regions”A region is one Proxmox VE cluster plus the network around it: storage, an edge router, address pools, machine image templates. Regions are independent. A private network, a public address, an image or a server belongs to exactly one region and cannot be used from another. There is no cross-region anything — not networking, not migration, not failover. That is a deliberate simplification, not a missing feature.
Each region is described by a configuration file the agent reads: which storage to use, which bridge, which VLAN range, which image template maps to which catalogue entry, which edge device to program. See Region configuration.
Two access modes
Section titled “Two access modes”Direct
Section titled “Direct”The control plane holds the Proxmox API token and calls the hypervisor itself.
Use it when the control plane and the cluster are operated by the same team on the same trusted network — typically a single-tenant installation, or development.
Agent (recommended)
Section titled “Agent (recommended)”A small virtual machine inside the region runs zone9-agent, a single Go binary. It
holds the Proxmox token and the edge router credentials in its own environment. It
opens the connection outward to the control plane, asks for work, does it, and
reports.
region control plane────── ─────────────zone9-agent ──── HTTPS (outbound) ─────────► POST /v1/agent/jobs/claim ◄─── one job for THIS region ─── ──── POST /v1/agent/jobs/{id}/steps (progress) ──── POST /v1/agent/healthThree properties follow, and each is worth stating separately:
Credentials do not travel. Compromising the control plane does not hand an attacker your hypervisor. The Proxmox token exists in exactly one place: the agent’s environment inside your datacentre.
No inbound hole. Your firewall needs no rule for zone9. The region needs outbound HTTPS and nothing else — no VPN, no port forward, no jump host.
A region can only claim its own work. The agent’s token identifies a region, and every endpoint verifies that the resource in question belongs to that region. An agent that misbehaves cannot reach into another region’s resources.
The agent also self-updates: it checks the published release, verifies the checksum, runs the new binary once to confirm it reports the expected version, swaps it in, and rolls back if the service does not come up.
The path of one request
Section titled “The path of one request”POST /v1/servers │ ├─ authenticate, check role ├─ validate the body (422 if wrong) ├─ check preconditions (409 if the world is not ready) ├─ allocate: private address, name, indices ← transactional SQL ├─ write intent: server row, status = creating ├─ write job: ServerCreate, region = ist1 ← same transaction └─ 202 Accepted { server, job }
…later, in the region…
zone9-agent claims the job ├─ Observe — does the VM already exist? look it up by tag ├─ Plan — what is missing? clone / configure / start ├─ Apply — each step idempotent, wait for the Proxmox task └─ Verify — read Proxmox back, write the result, record usageThe allocation and the job are written in one transaction. There is no window in which an address is reserved for a job that was never created, or a job exists for an address that was never allocated.
Multi-tenancy
Section titled “Multi-tenancy”Every region is multi-tenant. Isolation is layered and each layer is independently sufficient for its own scope:
- API scope. Every query is filtered by organisation. A resource that belongs to
someone else returns
404, not403— its existence is not disclosed. - Network. Private networks are separate layer-3 domains. Two organisations cannot route to each other even when they share a gateway appliance.
- Hypervisor. Resources are grouped and tagged per organisation so that a Proxmox operator sees ownership directly in the UI.
An installation can also restrict a region to specific organisations, for operators who want dedicated capacity for a customer.
- Intent, truth and reconciliation
- Tenant isolation — the same subject from the security angle
- Region agent — installing one