Skip to content

Architecture

Mezzanine is a single SQLite-backed Express + Next.js panel that opens SSH connections out to your servers. Nothing about it is special-cased to a particular cloud — every provider integration is a thin API wrapper on top of the same primitives.

System architecture

Mezzanine system architecture

Three containers on a single Docker network:

ServiceWhat it doesImage
mezzanine-nginxTLS terminator + routingnginx:1.27-alpine
mezzanine-frontendNext.js SSR + static assetsLocal build (Dockerfile.frontend)
mezzanine-backendExpress + Socket.IO + SSH/Docker servicesLocal build (Dockerfile.backend)

State lives in one named volume (mezzanine_data) mounted at /data inside the backend container. That’s the only thing you need to back up — everything else is reproducible from git + a fresh docker compose build.

Out to your fleet

Mezzanine fleet topology

For each adopted server, the backend opens one SSH connection on demand (pooled, idle-timed) and runs commands as the configured user. For each provider, it holds OAuth2 / API-token credentials in the integrations table and makes signed HTTPS calls. The control plane never sits in the data path — it configures and observes, but in-pool traffic flows browser → LB → members directly.

Code layout

mezzanine/
├── backend/src/
│ ├── routes/ # /api/* — thin Express handlers
│ ├── services/ # business logic, SSH/Docker/provider clients
│ ├── websockets/ # Socket.IO namespaces (terminal, metrics, logs)
│ ├── middleware/ # auth, role-gate, response cache
│ └── db/index.ts # SQLite schema + migrations
├── frontend/
│ ├── app/ # Next.js App Router pages
│ ├── components/ # shared React components
│ ├── api/client.ts # axios client + per-resource API namespaces
│ └── lib/ # helpers (dialogs, workflow templates, transformers)
├── samples/ # reference apps + this docs site + landing page
└── deploy/ # Production artifacts (docker-compose, nginx.conf, INSTALL.md)

Why SQLite?

Single-file storage trades horizontal scalability for operational simplicity:

  • One file to back up. cp mezzanine.db /backup/ is your DR plan.
  • No DB server to provision, monitor, or upgrade
  • better-sqlite3 is synchronous → no async ceremony around every query
  • Easily handles 100K runs + 10K servers on a $5 VPS

If you outgrow it (>100 concurrent users, multi-region setup), swap for Postgres — the schema is portable.