Deployment
This guide covers deploying BandMate to production with Docker and a reverse proxy.
Production Checklist
Before deploying, ensure you have:
- Set strong, unique values for
JWT_ACCESS_SECRETandJWT_REFRESH_SECRET - Changed the default admin password (or set
ADMIN_EMAIL/ADMIN_PASSWORDbefore first run) - Set
NODE_ENV=production - Set
APP_URLto your public-facing domain - Configured persistent volume mounts for
/app/dataand/app/uploads - Set up a reverse proxy with HTTPS
Docker Production Deployment
Basic Docker Run
docker run -d \
--name bandmate \
--restart unless-stopped \
-p 3000:3000 \
-v /path/to/data:/app/data \
-v /path/to/uploads:/app/uploads \
-e NODE_ENV=production \
-e JWT_ACCESS_SECRET="$(openssl rand -base64 32)" \
-e JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
-e APP_URL="https://bandmate.yourdomain.com" \
grimothy/bandmate:latest
Docker Compose (Production)
version: '3.8'
services:
bandmate:
image: grimothy/bandmate:latest
container_name: bandmate
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- ./data:/app/data
- ./uploads:/app/uploads
environment:
NODE_ENV: production
JWT_ACCESS_SECRET: "your-strong-secret-here"
JWT_REFRESH_SECRET: "your-other-strong-secret-here"
APP_URL: "https://bandmate.yourdomain.com"
# Optional: Email
# EMAIL_ENABLED: "true"
# EMAIL_HOST: smtp.example.com
# Optional: Google OAuth
# GOOGLE_OAUTH_ENABLED: "true"
# GOOGLE_CLIENT_ID: "your-client-id"
# GOOGLE_CLIENT_SECRET: "your-client-secret"
Reverse Proxy Configuration
BandMate should be placed behind a reverse proxy that handles HTTPS termination.
important
BandMate uses WebSockets for real-time features. Your reverse proxy must be configured to proxy WebSocket connections, or notifications and real-time updates will not work.
nginx
server {
listen 443 ssl http2;
server_name bandmate.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
client_max_body_size 500M; # Match stem upload limit
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;
}
# WebSocket support
location /socket.io/ {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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 80;
server_name bandmate.yourdomain.com;
return 301 https://$host$request_uri;
}
Traefik (Docker Labels)
services:
bandmate:
image: grimothy/bandmate:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.bandmate.rule=Host(`bandmate.yourdomain.com`)"
- "traefik.http.routers.bandmate.entrypoints=websecure"
- "traefik.http.routers.bandmate.tls.certresolver=letsencrypt"
- "traefik.http.services.bandmate.loadbalancer.server.port=3000"
Caddy
bandmate.yourdomain.com {
reverse_proxy localhost:3000
}
Caddy handles HTTPS automatically and supports WebSocket proxying out of the box.
Backups
Automated Backup Script
#!/bin/bash
# backup-bandmate.sh
BACKUP_DIR="/path/to/backups"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p "$BACKUP_DIR"
# Stop container for consistency
docker stop bandmate
# Create compressed archive
tar -czf "$BACKUP_DIR/bandmate-$DATE.tar.gz" \
/path/to/data \
/path/to/uploads
# Restart container
docker start bandmate
# Remove backups older than 30 days
find "$BACKUP_DIR" -name "bandmate-*.tar.gz" -mtime +30 -delete
echo "Backup completed: bandmate-$DATE.tar.gz"
Restore from Backup
docker stop bandmate
# Extract backup
tar -xzf bandmate-20260210_120000.tar.gz -C /
docker start bandmate
Monitoring
BandMate includes health check endpoints that Docker can use for container health monitoring:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
Updating in Production
# Pull the latest image
docker pull grimothy/bandmate:latest
# Stop and remove the current container
docker stop bandmate
docker rm bandmate
# Start with the same configuration
docker run -d \
--name bandmate \
--restart unless-stopped \
# ... same flags as before ...
grimothy/bandmate:latest
Your data is preserved in the mounted volumes. Database migrations run automatically on startup.