Skip to content

Docker Compose (Production)

This guide walks you through deploying ArchVault in production using Docker Compose. The pre-built image is published to GitHub Container Registry at ghcr.io/rubentalstra/archvault.

  • Docker Engine 24+ and Docker Compose v2
  • A server with at least 1 GB RAM and 10 GB disk
  • A domain name (recommended) with a reverse proxy for TLS
  1. Create a directory for your deployment:
Terminal window
mkdir archvault && cd archvault
  1. Download the production Compose file and environment template:
Terminal window
curl -O https://raw.githubusercontent.com/rubentalstra/Archvault/main/compose.prod.yaml
curl -o .env https://raw.githubusercontent.com/rubentalstra/Archvault/main/.env.production.example
  1. Edit .env and fill in the required values:
Terminal window
# Generate a secret key
openssl rand -base64 32

Set at minimum:

  • BETTER_AUTH_SECRET — paste the generated secret
  • BETTER_AUTH_URL — your public URL (e.g. https://archvault.example.com)
  • POSTGRES_PASSWORD — a strong database password
  1. Start the stack:
Terminal window
docker compose -f compose.prod.yaml up -d
  1. Verify the deployment:
Terminal window
curl http://localhost:3000/api/health

You should see {"status":"healthy","database":"connected",...}.

The production Compose stack consists of two services:

ServiceImagePurpose
appghcr.io/rubentalstra/archvault:latestArchVault application server
dbpostgres:18-alpinePostgreSQL database

Key characteristics:

  • The database is not exposed to the host — only accessible within the archvault bridge network
  • Data is persisted in a named Docker volume (pgdata)
  • The app waits for the database health check before starting
  • Database migrations run automatically on startup (configurable via AUTO_MIGRATE)

By default, the container runs pending database migrations on every start. This ensures your database schema stays in sync when upgrading to a new image version.

To disable auto-migration (e.g. if you prefer to run migrations manually):

environment:
AUTO_MIGRATE: "false"

Run migrations manually:

Terminal window
docker compose -f compose.prod.yaml exec app node migrate.mjs

The app listens on port 3000. In production, you should place a reverse proxy in front for TLS termination — never expose port 3000 directly to the internet.

The Compose file includes a built-in Traefik profile for automatic HTTPS — no config files needed:

Terminal window
# Set your domain and Let's Encrypt email in .env
DOMAIN=archvault.example.com
ACME_EMAIL=admin@example.com
# Start with the traefik profile
docker compose -f compose.prod.yaml --profile traefik up -d

Traefik automatically obtains and renews TLS certificates via Let’s Encrypt, redirects HTTP to HTTPS, and adds security headers.

See the Reverse Proxy guide for full configuration examples with Traefik, Nginx, and Caddy.

Instead of latest, pin to a specific version or commit SHA for reproducible deployments:

services:
app:
image: ghcr.io/rubentalstra/archvault:1.0.0

Available tag formats:

  • latest — latest build from main
  • 1.0.0 — exact semver release
  • 1.0 — latest patch in minor
  • 1 — latest minor in major
  • abc1234 — specific commit SHA
Terminal window
docker compose -f compose.prod.yaml exec db \
pg_dump -U archvault archvault > backup-$(date +%Y%m%d).sql
Terminal window
docker compose -f compose.prod.yaml exec -T db \
psql -U archvault archvault < backup-20260317.sql
  • The application runs as a non-root user (UID 1001) inside the container
  • The database has no exposed ports — it is only accessible via the internal Docker network
  • Always use a strong, unique POSTGRES_PASSWORD
  • Always use a strong, unique BETTER_AUTH_SECRET
  • Use TLS termination via a reverse proxy — never expose port 3000 directly to the internet