Production Deployment
This guide covers deploying BatAudit on a Linux server (VPS, EC2, bare metal) using Docker Compose with PostgreSQL. For a simpler single-file setup, see the SQLite guide.
Prerequisites
- Docker Engine 24+ and Docker Compose v2
- A domain name pointing to your server
- A reverse proxy (Caddy or Nginx) for HTTPS
1. Clone and configure
git clone https://github.com/joaovrmoraes/bataudit.git
cd bataudit
cp .env.example .env # or create .env from scratch
Edit .env with production values:
# Auth
JWT_SECRET=<random 32+ char string>
INITIAL_OWNER_NAME=Your Name
INITIAL_OWNER_EMAIL=you@yourdomain.com
INITIAL_OWNER_PASSWORD=<strong password>
# Database (PostgreSQL)
DB_DRIVER=postgres
DB_HOST=postgres
DB_PORT=5432
DB_USER=batuser
DB_PASSWORD=<strong password>
DB_NAME=batdb
# Redis
REDIS_ADDRESS=redis:6379
QUEUE_NAME=bataudit:events
# Runtime
GIN_MODE=release
LOG_LEVEL=info
# Web Push (optional — generate with: go run ./cmd/tools/gen-vapid)
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
VAPID_SUBJECT=mailto:you@yourdomain.com
Generate a strong JWT_SECRET:
openssl rand -base64 32
Generate VAPID keys for Web Push notifications:
go run ./cmd/tools/gen-vapid
2. Start the stack
docker compose up -d
Services start in order: PostgreSQL → Redis → Writer → Reader + Worker. Migrations run automatically on first startup.
Verify everything is up:
docker compose ps
curl http://localhost:8082/health
3. Reverse proxy (HTTPS)
Never expose PostgreSQL or Redis ports publicly. Only proxy ports 8081 (Writer API) and 8082 (Reader + dashboard).
Caddy
bataudit.yourdomain.com {
reverse_proxy localhost:8082
}
writer.bataudit.yourdomain.com {
reverse_proxy localhost:8081
}
Caddy handles TLS automatically via Let's Encrypt.
Nginx + Certbot
server {
listen 443 ssl;
server_name bataudit.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/bataudit.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bataudit.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:8082;
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;
}
}
server {
listen 443 ssl;
server_name writer.bataudit.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/writer.bataudit.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/writer.bataudit.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
4. Coolify
BatAudit ships with docker-compose.coolify.yml for one-click Coolify deploys.
- Create a new resource → Docker Compose
- Paste
docker-compose.coolify.yml - Set environment variables in Coolify's UI
- Deploy
5. Health checks
Both services expose /health:
curl http://localhost:8081/health # Writer
curl http://localhost:8082/health # Reader
# → {"status":"ok"}
6. Backups
# Dump PostgreSQL to file
docker exec bat_postgres pg_dump -U batuser batdb > backup-$(date +%Y%m%d).sql
# Restore
cat backup-20260101.sql | docker exec -i bat_postgres psql -U batuser batdb
For automated backups, pipe pg_dump to S3, R2, or Backblaze on a cron schedule.
7. Upgrading
git pull origin main
docker compose pull
docker compose up -d
Migrations run automatically on startup — no manual steps required.
Security checklist
-
JWT_SECRETis a strong random value (≥32 chars), not the default -
INITIAL_OWNER_PASSWORDchanged from default - Only ports
8081and8082exposed — PostgreSQL and Redis are internal only - HTTPS enabled via reverse proxy
-
GIN_MODE=release - VAPID keys are persistent (set in
.env, not ephemeral) -
.envnot committed to git (add to.gitignore) - PostgreSQL backups scheduled