AnswerLoopsAnswerLoops Docs
Self-Hosting

Production Deployment

Deploy AnswerLoops to a production server.

This assumes you've already worked through the self-host quickstart locally and know your setup works — production is the same app, just with real secrets, a real domain, and docker-compose.prod.yml instead of the dev compose file.

  • Server: Any Linux VPS (Ubuntu 22.04+)
  • Reverse proxy: Caddy (auto SSL) or nginx
  • Process: Docker Compose
  • Database: Docker Postgres with named volume, or managed Postgres (Neon, Supabase, Railway)

Get the code onto the server

Clone the repo on your server the same way you did locally, then create a production .env (not .env.local — that's the dev-only file):

git clone https://github.com/AnswerLoops/AnswerLoops.git
cd AnswerLoops
cp .env.local.example .env

Fill in .env with your production values — the checklist below covers what has to be different from your dev setup.

Environment checklist

Before going live, verify these are set in your production .env:

  • AUTH_URL set to your production domain (e.g. https://app.yourdomain.com)
  • AUTH_SECRET — unique 32-byte hex, not the same as dev
  • ENCRYPTION_KEY — unique 32-byte hex, not the same as dev
  • DATABASE_URL pointing to production database
  • OAuth callback URLs updated in GitHub/Google dashboards
  • OPENAI_API_KEY set
app.yourdomain.com {
    reverse_proxy localhost:3000
}

Run: caddy run --config Caddyfile

nginx

server {
    listen 443 ssl;
    server_name app.yourdomain.com;

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

Start in production

Use docker-compose.prod.yml, not the plain docker-compose.yml from local dev — it builds the multi-stage production image and runs the bot in bot:start mode instead of the dev watch mode:

docker compose -f docker-compose.prod.yml up -d --build

Drizzle migrations run automatically against your production database on first start, same as local dev — no separate migration step.

Health check

curl https://app.yourdomain.com/api/health
# → {"ok":true}

Alternative: Railway or another PaaS

If you'd rather not manage a VPS, reverse proxy, and TLS certs yourself, push the repo to Railway (or Fly.io) — it builds straight from the Dockerfile, handles HTTPS automatically, and you skip the Caddy/nginx section above entirely. You'll still need to set the same environment variables, and a managed Postgres (Neon, Railway's own Postgres) instead of the Docker-volume one.

On this page