Production Deployment

Deploy PiSovereign for production use with TLS, monitoring, and hardened configuration

Overview

PiSovereign is deployed via Docker Compose. The stack includes Traefik for automatic TLS via Let’s Encrypt, Vault for secrets, Ollama for inference, and all supporting services.

Internet
    │
    ▼
┌─────────────┐
│   Traefik   │ ← TLS termination, Let's Encrypt
│  (Reverse   │
│   Proxy)    │
└─────────────┘
    │ HTTP (internal)
    ▼
┌─────────────┐     ┌─────────────┐
│ PiSovereign │ ──▶ │   Ollama    │
│   Server    │     │  (isolated) │
└─────────────┘     └─────────────┘
    │
    ▼
┌─────────────┐     ┌─────────────┐
│  Prometheus │ ──▶ │   Grafana   │
│   Metrics   │     │  Dashboard  │
└─────────────┘     └─────────────┘

Pre-Deployment Checklist

  • Docker Engine 24+ with Compose v2 installed
  • Vault initialized and secrets stored (Vault Setup)
  • Domain name with DNS A record pointing to your server
  • Firewall allows ports 80 and 443 (inbound)
  • Backup strategy defined (Backup & Restore)

Deployment

Refer to the Docker Setup guide for the step-by-step deployment process. The key commands are:

cd PiSovereign/docker

cp .env.example .env
nano .env  # Set PISOVEREIGN_DOMAIN and TRAEFIK_ACME_EMAIL

docker compose up -d
docker compose exec vault /vault/init.sh

Enable All Profiles

docker compose --profile monitoring --profile caldav up -d

Multi-Architecture Builds

PiSovereign images support both ARM64 (Raspberry Pi) and AMD64 (x86 servers):

docker pull --platform linux/arm64 ghcr.io/twohreichel/pisovereign:latest
docker pull --platform linux/amd64 ghcr.io/twohreichel/pisovereign:latest

TLS Configuration

Traefik with Let’s Encrypt

TLS is handled automatically by Traefik. The Docker Compose stack includes Traefik with HTTP challenge for Let’s Encrypt certificates. Key requirements:

  1. DNS A record pointing to your server’s public IP
  2. Ports 80 and 443 open in your firewall
  3. Valid email for Let’s Encrypt notifications (set in .env as TRAEFIK_ACME_EMAIL)

Certificate auto-renewal is handled by Traefik — no manual intervention required.

TLS Hardening

For stricter TLS settings, edit docker/traefik/dynamic.yml:

tls:
  options:
    default:
      minVersion: VersionTLS13
      cipherSuites:
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
      curvePreferences:
        - X25519
        - CurveP384
      sniStrict: true

Production Configuration

Key settings for production in docker/config/config.toml:

environment = "production"

[server]
host = "0.0.0.0"
port = 3000
log_format = "json"
cors_enabled = true
allowed_origins = ["https://your-domain.example.com"]
shutdown_timeout_secs = 30

[inference]
base_url = "http://ollama:11434"
default_model = "gemma3:12b"
timeout_ms = 120000

[security]
rate_limit_enabled = true
rate_limit_rpm = 120
min_tls_version = "1.3"
tls_verify_certs = true

[database]
url = "postgres://pisovereign:pisovereign@postgres:5432/pisovereign"
max_connections = 10
run_migrations = true

[cache]
enabled = true
ttl_short_secs = 300
ttl_medium_secs = 3600
ttl_long_secs = 86400
l1_max_entries = 10000

[vault]
address = "http://vault:8200"
mount_path = "secret"
timeout_secs = 5

[degraded_mode]
enabled = true
unavailable_message = "Service temporarily unavailable. Please try again."
failure_threshold = 3
success_threshold = 2

[health]
global_timeout_secs = 5

See the Configuration Reference for all available options.


Deployment Verification

After deployment, verify everything is working:

# 1. Check all containers are running
docker compose ps

# 2. Check health endpoint
curl https://your-domain.example.com/health

# 3. Check all services are ready
curl https://your-domain.example.com/ready/all | jq

# 4. Test chat endpoint
curl -X POST https://your-domain.example.com/v1/chat \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello"}' | jq

# 5. Check TLS certificate
openssl s_client -connect your-domain.example.com:443 -brief

# 6. Check metrics
curl http://localhost:3000/metrics/prometheus | head -20

Expected results:

  • Health returns {"status": "ok"}
  • Ready shows all services healthy
  • Chat returns an AI response
  • TLS shows a valid certificate

Advanced: Non-Docker Deployment

For advanced users who prefer running PiSovereign without Docker, you can build the binary directly:

cargo build --release
# Binaries: target/release/pisovereign-server, target/release/pisovereign-cli

You are responsible for managing Ollama, Vault, Signal-CLI, Whisper, Piper, and reverse proxy setup yourself. The Docker Compose stack in docker/compose.yml serves as the reference architecture.


Next Steps