Reverse Proxy Setup
Deploy BillManager behind a reverse proxy for HTTPS and production use.
Why a Reverse Proxy?
For production deployments, you should:
- Enable HTTPS - Encrypt all traffic with SSL/TLS certificates
- Use a Custom Domain - Access BillManager at
bills.yourdomain.com - Add Security Headers - Improve security with proper HTTP headers
- Enable Compression - Reduce bandwidth usage
Traefik
Traefik is recommended for Docker environments with automatic HTTPS.
docker-compose.yml
services:
billmanager:
image: ghcr.io/brdweb/billmanager:latest
environment:
- DEPLOYMENT_MODE=self-hosted
- DATABASE_URL=postgresql://billsuser:password@db:5432/billmanager
- FLASK_SECRET_KEY=your-secret-key
- JWT_SECRET_KEY=your-jwt-secret-key
- APP_URL=https://bills.yourdomain.com
labels:
- "traefik.enable=true"
- "traefik.http.routers.billmanager.rule=Host(`bills.yourdomain.com`)"
- "traefik.http.routers.billmanager.entrypoints=websecure"
- "traefik.http.routers.billmanager.tls.certresolver=letsencrypt"
- "traefik.http.services.billmanager.loadbalancer.server.port=5000"
depends_on:
- db
networks:
- traefik
- internal
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=billsuser
- POSTGRES_PASSWORD=password
- POSTGRES_DB=billmanager
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- internal
volumes:
postgres_data:
networks:
traefik:
external: true
internal:
tip
Make sure your Traefik instance is configured with a letsencrypt certificate resolver. See Traefik documentation for details.
Nginx
For traditional Nginx deployments:
nginx.conf
server {
listen 80;
server_name bills.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name bills.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# SSL settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
location / {
proxy_pass http://localhost:5000;
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;
# WebSocket support (if needed in future)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
With Certbot (Let's Encrypt)
# Install certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d bills.yourdomain.com
# Auto-renewal is set up automatically
Caddy
Caddy provides automatic HTTPS with minimal configuration:
Caddyfile
bills.yourdomain.com {
reverse_proxy localhost:5000
}
docker-compose.yml with Caddy
services:
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
restart: unless-stopped
billmanager:
image: ghcr.io/brdweb/billmanager:latest
environment:
- DEPLOYMENT_MODE=self-hosted
- DATABASE_URL=postgresql://billsuser:password@db:5432/billmanager
- FLASK_SECRET_KEY=your-secret-key
- APP_URL=https://bills.yourdomain.com
volumes:
caddy_data:
caddy_config:
postgres_data:
Important: Update APP_URL
When using a reverse proxy with HTTPS, make sure to update APP_URL:
environment:
- APP_URL=https://bills.yourdomain.com
This ensures email links point to the correct URL.