Architecture Overview
KVM Fleet is a multi-tenant platform for managing KVM-over-IP devices.
Stack
| Component | Technology |
|---|---|
| API server | FastAPI (Python) |
| Database | PostgreSQL with Row-Level Security |
| Cache / pubsub | Redis |
| Frontend | React (SPA) |
| Agent | Go (static binary) |
| Reverse proxy | Caddy (auto-TLS) |
| Hosting | Hetzner CX22 (Falkenstein, DE) |
System diagram
graph LR
subgraph "KVM Devices"
A1[Agent] -->|WSS outbound| C
A2[Agent] -->|WSS outbound| C
A3[Agent] -->|WSS outbound| C
end
subgraph "Hetzner CX22"
C[Caddy] --> API[FastAPI]
API --> PG[(Postgres)]
API --> R[(Redis)]
C --> FE[React SPA]
end
U[Browser] -->|HTTPS| C
MCP[MCP Client] -->|API key| C
Key design decisions
Outbound-only tunnels
Agents initiate outbound WebSocket connections to the platform. No inbound ports are opened on KVM devices. This works behind NATs, firewalls, and corporate networks without VPN configuration.
See WS Multiplex for the tunnel protocol.
Database-level multi-tenancy
All tenant isolation is enforced via Postgres RLS. The API connects as a non-superuser role (kvmfleet_app) with FORCE ROW LEVEL SECURITY. Even a bug in the API code cannot leak data across organizations.
See Row-Level Security for the policy design.
Tamper-evident audit log
Every auditable action (login, console open, device enroll, setting change) is recorded in an append-only table. Each row includes a SHA-256 hash of the previous row, forming a verifiable chain.
See Audit Chain for the hash chain design.
Device-agnostic agent
The agent doesn't know or care what KVM software is running. It tunnels HTTP traffic from the platform to the device's local web UI. This means any KVM with a web interface works — PiKVM, JetKVM, TinyPilot, or custom builds.
Data flow: console session
sequenceDiagram
participant User as Browser
participant API as FastAPI
participant Redis
participant Agent as Agent (on KVM)
participant KVM as KVM Web UI
User->>API: POST /v1/sessions (start console)
API->>API: Auth + RBAC check
API->>Redis: Publish "open session" to agent channel
Redis-->>Agent: Session request (via WS)
Agent->>KVM: HTTP request to localhost
KVM-->>Agent: HTTP response
Agent-->>API: Response over WS multiplex
API-->>User: Proxied response
Deployment
Single-server deployment on Hetzner CX22:
- Caddy handles TLS termination and routes traffic
- FastAPI runs via uvicorn behind Caddy
- Postgres and Redis run as local services
- All components managed by systemd