Skip to content

Docker Compose

  1. Clone and enter the production stack

    Terminal window
    git clone https://github.com/mralaminahamed/tundra
    cd tundra/docs/09-deployment-bundle/prod
  2. Configure

    Terminal window
    cp .env.example .env
    # Edit .env — required values:
    # TUNDRA_HOSTNAME=panel.example.com
    # ACME_EMAIL=ops@example.com
    # TUNDRA_VERSION=1.0.0
  3. Generate secrets

    Terminal window
    bash scripts/generate-secrets.sh

    This creates secrets/postgres_password.txt, secrets/valkey_password.txt, and secrets/master_key.bin with mode 0400. Run once — the script guards against re-runs.

  4. Build and start

    Terminal window
    docker compose build
    docker compose up -d
    docker compose logs -f tundrad
  5. Complete setup

    Visit https://panel.example.com/setup to create your owner account.

ServiceImagePort
postgrespostgres:18-trixieinternal
valkeyvalkey/valkey:8-alpineinternal
tundradbuilt from sourceinternal
panel-uibuilt from sourceinternal
caddycaddy:2.10-alpine80, 443
workload-1built from sourceinternal

All services are on an internal Docker network. Only Caddy is exposed on the host.

The production stack applies:

  • read_only: true on the tundrad container
  • security_opt: no-new-privileges:true
  • cap_drop: ALL with only NET_BIND_SERVICE added back
  • Docker secrets for all credentials (never in environment variables)
  • Caddy: HSTS, CSP, X-Frame-Options, X-Content-Type-Options headers
Terminal window
# In docs/09-deployment-bundle/prod/
# 1. Update TUNDRA_VERSION in .env
# 2. Pull and rebuild
docker compose pull
docker compose up -d --build
docker compose logs -f tundrad

Migrations run automatically on startup.