Deployment Guide
Deploy Vaultaris to production using Docker Compose, bare metal, or a managed container platform.
Production checklist
Before going live:
- Set a strong, random
JWT_SECRET(openssl rand -hex 32) - Set a strong, random
ENCRYPTION_KEY(openssl rand -hex 16) - Set
EXTERNAL_URLto your public HTTPS domain - Configure SMTP for transactional email
- Enable Redis (
REDIS_URL) for distributed rate limiting if running multiple nodes - Set up TLS termination (nginx, Caddy, or a load balancer)
- Configure backups for PostgreSQL
- Set
RUST_LOG=info(not debug) in production - Optionally set
GEOIP_DATABASE_PATHfor offline IP geolocation
Docker Compose (single node)
# docker-compose.yml
version: "3.9"
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: vaultaris
POSTGRES_USER: vaultaris
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "vaultaris"]
interval: 5s
retries: 10
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
vaultaris:
image: ghcr.io/rustlanges/vaultaris:latest
depends_on:
postgres:
condition: service_healthy
ports:
- "8080:8080"
environment:
DATABASE_URL: postgres://vaultaris:${POSTGRES_PASSWORD}@postgres:5432/vaultaris
REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379
JWT_SECRET: ${JWT_SECRET}
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
EXTERNAL_URL: ${EXTERNAL_URL}
EMAIL_ENABLED: "true"
SMTP_HOST: ${SMTP_HOST}
SMTP_USERNAME: ${SMTP_USERNAME}
SMTP_PASSWORD: ${SMTP_PASSWORD}
GEOIP_DATABASE_PATH: /data/GeoLite2-Country.mmdb
volumes:
- ./GeoLite2-Country.mmdb:/data/GeoLite2-Country.mmdb:ro
volumes:
postgres-data:
redis-data:
Create a .env file:
POSTGRES_PASSWORD=strong-db-password
REDIS_PASSWORD=strong-redis-password
JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 16)
EXTERNAL_URL=https://auth.example.com
SMTP_HOST=smtp.sendgrid.net
SMTP_USERNAME=apikey
SMTP_PASSWORD=SG.xxxxxxxxxx
Start:
docker compose up -d
TLS with Caddy
# Caddyfile
auth.example.com {
reverse_proxy localhost:8080
}
Caddy automatically obtains and renews Let's Encrypt certificates.
TLS with nginx
server {
listen 443 ssl;
server_name auth.example.com;
ssl_certificate /etc/letsencrypt/live/auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.example.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Multi-node deployment
- Provision a shared PostgreSQL instance (or managed service like RDS, Cloud SQL)
- Provision a shared Redis instance (or managed service like ElastiCache, Upstash)
- Run identical Vaultaris containers across nodes, all pointing to the same DB and Redis
- Load-balance with nginx, HAProxy, or your cloud LB
Each node gets a random node_id UUID at startup for log correlation. The X-Node-Id response header is emitted when NODE_ID_IN_HEADERS=true.
Database pool sizing: nodes × DATABASE_MAX_CONNECTIONS ≤ postgres max_connections.
Kubernetes
See the Kubernetes guide for the Helm chart.
Database backups
# Daily backup with pg_dump
pg_dump -Fc -U vaultaris vaultaris > backup-$(date +%Y%m%d).dump
# Restore
pg_restore -U vaultaris -d vaultaris backup-20260101.dump
For production, use managed snapshots (RDS automated backups, Cloud SQL point-in-time recovery, etc.) or a tool like pgBackRest.
Upgrading
Vaultaris auto-migrates on startup. To upgrade:
docker compose pull vaultaris
docker compose up -d vaultaris
Always back up the database before upgrading across major versions.
Health monitoring
# Liveness probe
curl http://localhost:8080/health
# Readiness (same endpoint, checks DB connectivity)
curl http://localhost:8080/health
# Prometheus scrape
curl http://localhost:8080/metrics
Configure your monitoring system (Prometheus + Grafana, Datadog, etc.) to alert on:
vaultaris_up = 0- HTTP 5xx rate > threshold
- PostgreSQL connection pool exhaustion
- JWT secret rotation lag