Self-Hosting

Sirr is designed to be self-hosted. This guide covers everything you need to run Sirr in production with proper security, persistence, and monitoring.

Production checklist

Before exposing Sirr to production traffic, verify each item:

  • Strong master key — Generate a cryptographically random key with at least 32 bytes of entropy: openssl rand -hex 32. Never reuse keys across environments.
  • TLS everywhere — Sirr itself does not terminate TLS. Place it behind a reverse proxy with TLS or use a service mesh. Without TLS, secrets are transmitted in plaintext over the network.
  • Persistent storage — Mount a volume to /data so sirr.db and sirr.salt survive container restarts and redeployments.
  • Backup both filessirr.db and sirr.salt are both required for decryption. Back them up together.
  • Log level — Set SIRR_LOG_LEVEL=info for production. Use debug or trace only for troubleshooting.
  • Resource limits — Set memory and CPU limits on the container to prevent runaway resource usage.
  • Restart policy — Use restart: unless-stopped or restart: always to recover from crashes.

Reverse proxy

Sirr listens on port 39999 by default and expects a reverse proxy to handle TLS termination, rate limiting, and public-facing traffic.

Nginx

nginx.conf

upstream sirr {
    server 127.0.0.1:39999;
}

server {
    listen 443 ssl http2;
    server_name sirr.example.com;

    ssl_certificate     /etc/letsencrypt/live/sirr.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sirr.example.com/privkey.pem;

    location / {
        proxy_pass http://sirr;
        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;
    }
}

Caddy

Caddy provides automatic TLS via Let's Encrypt with zero configuration:

Caddyfile

sirr.example.com {
    reverse_proxy localhost:39999
}

That is it. Caddy automatically obtains and renews TLS certificates.


TLS termination

Sirr does not handle TLS itself. You have two main options:

Let's Encrypt with Certbot (Nginx)

Certbot setup

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d sirr.example.com

Certbot automatically configures Nginx and sets up certificate renewal via a cron job.

Caddy auto-TLS

Caddy handles TLS automatically when you provide a domain name in the Caddyfile. No additional setup is required — certificates are obtained and renewed automatically via the ACME protocol.


Backups

Sirr stores all data in two files inside the data directory:

FilePurpose
sirr.dbredb embedded database containing all encrypted secrets and metadata
sirr.saltArgon2id salt used to derive the encryption key from your master key

Backup script example

#!/bin/bash
BACKUP_DIR="/backups/sirr/$(date +%Y%m%d-%H%M%S)"
DATA_DIR="/data"

mkdir -p "$BACKUP_DIR"
cp "$DATA_DIR/sirr.db" "$BACKUP_DIR/"
cp "$DATA_DIR/sirr.salt" "$BACKUP_DIR/"

# Optional: compress and encrypt the backup
tar -czf "$BACKUP_DIR.tar.gz" -C "$(dirname "$BACKUP_DIR")" "$(basename "$BACKUP_DIR")"
rm -rf "$BACKUP_DIR"

Schedule this with cron or your preferred task scheduler. Test restores regularly — a backup you have never restored is a backup you do not have.


Monitoring

Health checks

The GET /health endpoint requires no authentication and returns {"status":"ok"} when the server is ready:

Health check

curl -f http://localhost:39999/health

Use this endpoint with your uptime monitoring tool (Uptime Kuma, Pingdom, AWS ALB health checks, Kubernetes liveness probes, etc.).

Log levels

Control log verbosity with the SIRR_LOG_LEVEL environment variable:

LevelUse case
errorOnly critical failures
warnWarnings and errors
infoRecommended for production — request logs and lifecycle events
debugVerbose output for troubleshooting
traceMaximum verbosity — includes internal state

Production Docker Compose

A production-ready Compose file with named volumes, restart policies, resource limits, and a Caddy reverse proxy:

docker-compose.production.yml

services:
  sirrd:
    image: ghcr.io/sirrvault/sirrd  # or sirrvault/sirrd (Docker Hub)
    volumes:
      - sirrd-data:/data
    environment:
      SIRR_MASTER_KEY: "${SIRR_MASTER_KEY}"
      SIRR_DATA_DIR: /data
      SIRR_LOG_LEVEL: info
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 256M
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:39999/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  caddy:
    image: caddy:2-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy-data:/data
      - caddy-config:/config
    restart: unless-stopped

volumes:
  sirrd-data:
  caddy-data:
  caddy-config:

Pair it with a Caddyfile:

Caddyfile

sirr.example.com {
    reverse_proxy sirrd:39999
}

Start the stack:

Deploy

export SIRR_MASTER_KEY="your-production-master-key"
docker compose -f docker-compose.production.yml up -d

Was this page helpful?