Production Deployment
For production use docker-compose.prod.yml. It adds:
- Caddy as a reverse proxy with automatic TLS via Let's Encrypt
- Security headers — HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
- PostgreSQL and Ollama are not exposed to the host — only reachable inside the Docker network
- App healthcheck (
GET /api/health) wired to Docker restart policy
Requirements
- A server with Docker and Docker Compose
- A domain name pointing to your server (A record)
- Ports 80 and 443 open on your firewall
Step by step
1. Configure .env
bash
cp .env.example .envEdit .env and fill in all CHANGE_ME values:
env
# PostgreSQL — use strong random values
POSTGRES_USER=hypar
POSTGRES_PASSWORD=a_strong_random_password
POSTGRES_DB=hypar_db
# Caddy — your public domain
DOMAIN=hypar.yourdomain.com
# Auth
BETTER_AUTH_SECRET= # openssl rand -hex 32
BETTER_AUTH_URL=https://hypar.yourdomain.com
# Agent — llama3.1:8b is pulled by the Ollama service
OLLAMA_LLM_MODEL=llama3.1:8bThere is no embedding key and no ADMIN_API_KEY. Optional OAuth: set both GitHub or Google client id and secret.
2. Start
bash
docker compose -f docker-compose.prod.yml up -d --buildCaddy will automatically obtain a TLS certificate for your domain. The first start takes a couple of minutes while Caddy negotiates with Let's Encrypt and Ollama downloads its chat model.
3. Verify
bash
# App is up and database is reachable
curl https://hypar.yourdomain.com/api/health
# → {"status":"ok","checks":{"db":true},"ts":"..."}
# Container health
docker compose -f docker-compose.prod.yml psArchitecture in production
Internet
│ :443 / :80
▼
┌──────────┐
│ Caddy │ Automatic TLS, gzip, security headers
└──────────┘
│ :3000 (internal only)
▼
┌──────────┐ ┌──────────────┐ ┌────────┐
│ app │──▶│ postgres │ │ ollama │
└──────────┘ └──────────────┘ └────────┘
No host ports No host portsLogs
bash
docker compose -f docker-compose.prod.yml logs -f app
docker compose -f docker-compose.prod.yml logs -f caddyBackup
bash
# Dump the database to a local file
docker compose -f docker-compose.prod.yml exec postgres \
pg_dump -U $POSTGRES_USER $POSTGRES_DB > backup_$(date +%Y%m%d).sqlUpdate
bash
git pull
docker compose -f docker-compose.prod.yml up -d --buildPrisma migrations run automatically on startup.
Using a managed database
To use a managed PostgreSQL service (Railway, Supabase, Neon) instead of the Docker container:
- Remove the
postgresservice fromdocker-compose.prod.yml - Set
DATABASE_URLin.envto the connection string provided by your service - The
appservice will migrate and connect on startup
Customising Caddy
Edit Caddyfile to add rate limiting, basic auth, or a custom error page:
{$DOMAIN} {
reverse_proxy app:3000
encode gzip
}After editing, reload Caddy without restarting:
bash
docker compose -f docker-compose.prod.yml exec caddy caddy reload --config /etc/caddy/Caddyfile