Self-Hosting
Run KVM Fleet on your own infrastructure.
Requirements
- Linux server (Ubuntu 22.04+ or Debian 12+ recommended)
- 2 vCPUs, 4 GB RAM minimum (equivalent to Hetzner CX22)
- PostgreSQL 15+
- Redis 7+
- A domain with DNS pointing to your server
- Docker (optional, but recommended)
Docker Compose
The fastest way to self-host:
# docker-compose.yml
version: "3.8"
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: kvmfleet
POSTGRES_USER: kvmfleet
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
api:
image: ghcr.io/kvmfleet/api:latest
environment:
DATABASE_URL: postgresql://kvmfleet:${POSTGRES_PASSWORD}@postgres/kvmfleet
REDIS_URL: redis://redis:6379
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
JWT_SECRET: ${JWT_SECRET}
BASE_URL: https://${DOMAIN}
depends_on:
- postgres
- redis
restart: unless-stopped
caddy:
image: caddy:2
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
depends_on:
- api
restart: unless-stopped
volumes:
pgdata:
caddy_data:
Caddyfile
Caddy handles TLS automatically via Let's Encrypt.
Environment variables
Create a .env file:
DOMAIN=kvm.example.com
POSTGRES_PASSWORD=<generate-a-strong-password>
JWT_SECRET=<generate-a-strong-secret>
GOOGLE_CLIENT_ID=<from-google-cloud-console>
GOOGLE_CLIENT_SECRET=<from-google-cloud-console>
Google OAuth setup
- Go to Google Cloud Console
- Create an OAuth 2.0 Client ID (Web application)
- Add
https://your-domain.com/v1/auth/google/callbackas an authorized redirect URI - Copy the Client ID and Client Secret to your
.env
Database initialization
The init.sql script (included in the release) creates:
- Tables and indexes
- The
kvmfleet_approle with RLS policies - The audit log with append-only permissions
Run manually if not using Docker:
Start
Verify:
Agent configuration
When enrolling devices, point agents to your self-hosted instance:
curl -sSL https://your-domain.com/install | sh -s -- \
--token <token> \
--api https://your-domain.com
Backups
Back up Postgres regularly. The audit log hash chain makes it possible to verify backup integrity:
Upgrades
Database migrations run automatically on API startup.
Limitations vs hosted
| Feature | Self-hosted | Hosted (app.kvmfleet.io) |
|---|---|---|
| Automatic updates | Manual pull | Automatic |
| Transactional email | Bring your own SMTP | Included |
| Billing/plans | N/A (unlimited) | Stripe integration |
| Support | Community | Email support |