vaultaris /docs

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_URL to 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_PATH for 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

  1. Provision a shared PostgreSQL instance (or managed service like RDS, Cloud SQL)
  2. Provision a shared Redis instance (or managed service like ElastiCache, Upstash)
  3. Run identical Vaultaris containers across nodes, all pointing to the same DB and Redis
  4. 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