Technology stack
Each product page repeats the relevant part of this table in context. This page is the single place to see all of it at once.
Control plane
Section titled “Control plane”| Component | Technology | Notes |
|---|---|---|
| Console | Next.js 15, React 19, TypeScript | Server-rendered. No client state store; the API is the state. |
| API | Hono on Node.js, TypeScript | Plain functions and explicit SQL. No ORM magic — queries read like SQL because reviewers must be able to see exactly what is sent. |
| Database | PostgreSQL | Intent, allocations, job queue, audit trail. Schema evolves by forward-only numbered SQL migrations. |
| Query layer | Drizzle | Used as a typed query builder, not as an object mapper. Raw SQL where it is clearer. |
| API contract | OpenAPI 3 | Hand-written specification; TypeScript client types are generated from it. |
| Assistant interface | Model Context Protocol server, TypeScript | Calls the public HTTP API only. |
| Console access | noVNC (VNC) and xterm.js (serial) | Relayed through the panel; the hypervisor is never exposed. |
The API and the console are stateless and can be replicated. The database is the only stateful component, and the job queue lives inside it.
Region
Section titled “Region”| Component | Technology | Notes |
|---|---|---|
| Executor / agent | Go, single static binary | Standard library where possible. Claims jobs, calls Proxmox, reports back. Self-updating with checksum verification and rollback. |
| Hypervisor | Proxmox VE | Reached only over its REST API. No SSH, no qm, no writing under /etc/pve. |
| Networking | Proxmox SDN — VLAN or EVPN/VXLAN zones | Chosen per region. EVPN gives each private network its own VRF. |
| Storage | Whatever Proxmox offers — ZFS local with replication, or Ceph | zone9 places disks; it does not manage the storage backend. |
| Edge | FortiGate (adapter-based; others can be added) | Public block routing and policy. Programmed through the vendor API by the agent. |
Appliances
Section titled “Appliances”All appliance images are built from Ubuntu 24.04 LTS, hardened the same way: no SSH
daemon, no login shell, no user accounts, snapd removed. See
Appliances and the pull model.
| Appliance | Software | What it does |
|---|---|---|
| Load balancer | HAProxy + zone9-lb (Go) | TCP and HTTPS front ends, health checks, live counters. Configuration is rendered by the daemon from panel intent and reloaded without dropping connections. |
| Gateway | iptables NAT + Tailscale (optional) + zone9-gateway bootstrap | Source-NATs selected subnets out through your public address; optionally joins a Zero Trust network for private access. |
| Object storage | Garage + zone9-s3 (Go) | S3-compatible storage. The daemon owns the node’s configuration, cluster layout, buckets and access keys. |
Managed Kubernetes
Section titled “Managed Kubernetes”| Component | Technology |
|---|---|
| Node operating system | Talos Linux — immutable, API-driven, no shell and no SSH |
| Distribution | Upstream Kubernetes, version tied to the Talos release |
| Machine configuration delivery | Talos machine configuration, delivered as a cidata ISO attached to the VM |
| In-browser access | A kubectl pod inside your cluster, streamed to the panel console |
Talos was chosen for the same reason appliances are locked: a node with no shell has no configuration drift and nothing to log into. A cluster does not talk to the zone9 API; if the panel disappears, the cluster does not notice.
TLS and DNS
Section titled “TLS and DNS”| Function | Technology | Notes |
|---|---|---|
| Certificate issuance | ACME (Let’s Encrypt) with the DNS-01 challenge | The ACME client runs inside the API process as a locked scheduled scan. There is no separate certificate daemon. |
| DNS hosting | Cloudflare, through its API | Used both for user records and for the ACME challenge records. |
| Domain registration | NameSilo, through an adapter | Other registrars can be added behind the same interface. |
DNS-01 was chosen over HTTP-01 deliberately: it works for load balancers with no public
address at all, it is the only way to obtain wildcard certificates, it leaves port 80
free for your own use, and — because TXT records are never proxied — it keeps working
when a user turns on Cloudflare’s proxy to hide their origin address.
Distribution and deployment
Section titled “Distribution and deployment”| What | How |
|---|---|
| Control plane | Container images; production runs on Kubernetes, but nothing requires it |
| Database schema | Forward-only numbered SQL files, applied by a job before the API rolls out |
| Region agent | A published release; the agent updates itself from it |
| Appliance binaries | The same release; each appliance fetches the binary it needs |
| Machine images | Built once per region from a documented script, stored as Proxmox templates |
Deliberate absences
Section titled “Deliberate absences”Things a reader might expect to find, and why they are not here.
- No service mesh, no operator framework, no CRDs. The control plane is a web application talking to a database.
- No message broker. The job queue is a Postgres table, so a job and the intent that produced it commit together.
- No shared code between TypeScript and Go. They communicate through the OpenAPI contract and database tables. Sharing code would let business logic drift into whichever language happened to be convenient.
- No configuration management inside the product. Hypervisor nodes, switches and the edge router are provisioned once, out of band. A control plane that reconfigures the network is one whose bug takes the datacentre with it.