Reverse Proxy Setup
For production deployments, you'll want to run Enspotification behind a reverse proxy for SSL/TLS termination, load balancing, and better security. Here are configurations for popular reverse proxy solutions:
Prerequisites for Reverse Proxy Setup
Before configuring your reverse proxy, make sure to:
-
Update your Spotify App settings with the new redirect URI:
https://your-domain.com/callback -
Update your
.envfile:SPOTIFY_REDIRECT_URI=https://your-domain.com/callback
Only if Running Reverse Proxy in same Docker Network 3. Modify docker-compose.yml to not expose port 3000 publicly:
services:
enspotification:
ports:
- "127.0.0.1:3000:3000" # Only bind to localhost
Caddy
Caddy automatically handles SSL certificates via Let's Encrypt and has a simple configuration.
Caddyfile:
your-domain.com {
reverse_proxy localhost:3000
# Optional: Enable compression
encode gzip
# Optional: Add security headers
header {
# Enable HSTS
Strict-Transport-Security max-age=31536000;
# Prevent clickjacking
X-Frame-Options DENY
# Prevent MIME type sniffing
X-Content-Type-Options nosniff
# XSS Protection
X-XSS-Protection "1; mode=block"
}
# Health check endpoint
handle /health {
reverse_proxy localhost:3000
}
}
Docker Compose with Caddy:
version: '3.8'
services:
enspotification:
build: .
ports:
- "127.0.0.1:3000:3000"
env_file:
- .env
restart: unless-stopped
networks:
- enspotification
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- enspotification
restart: unless-stopped
networks:
enspotification:
driver: bridge
volumes:
caddy_data:
caddy_config:
enspotification_data:
Traefik
Traefik excels at automatic service discovery and SSL certificate management.
docker-compose.yml with Traefik:
version: '3.8'
services:
traefik:
image: traefik:v3.0
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=your-email@example.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
# Optional: Enable access logs
- "--accesslog=true"
ports:
- "80:80"
- "443:443"
- "8080:8080" # Traefik dashboard
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "letsencrypt:/letsencrypt"
networks:
- traefik
restart: unless-stopped
enspotification:
build: .
env_file:
- .env
restart: unless-stopped
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.enspotification.rule=Host(`your-domain.com`)"
- "traefik.http.routers.enspotification.entrypoints=websecure"
- "traefik.http.routers.enspotification.tls.certresolver=myresolver"
- "traefik.http.services.enspotification.loadbalancer.server.port=3000"
# Redirect HTTP to HTTPS
- "traefik.http.routers.enspotification-http.rule=Host(`your-domain.com`)"
- "traefik.http.routers.enspotification-http.entrypoints=web"
- "traefik.http.routers.enspotification-http.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
networks:
traefik:
external: true
volumes:
letsencrypt:
enspotification_data:
Setup Commands:
# Create external network
docker network create traefik
# Start services
docker-compose up -d
Nginx
Traditional and highly configurable reverse proxy solution.
nginx.conf:
server {
listen 80;
server_name your-domain.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL Certificate configuration
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# SSL Security settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
# Proxy settings
location / {
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;
proxy_cache_bypass $http_upgrade;
# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Health check endpoint (optional monitoring)
location /health {
proxy_pass http://localhost:3000/health;
access_log off;
}
# Optional: Enable gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
}
Docker Compose with Nginx:
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./ssl:/etc/nginx/ssl # Mount your SSL certificates
depends_on:
- enspotification
networks:
- enspotification
restart: unless-stopped
enspotification:
build: .
expose:
- "3000"
env_file:
- .env
restart: unless-stopped
networks:
- enspotification
networks:
enspotification:
driver: bridge
volumes:
enspotification_data:
Nginx Proxy Manager (NPM)
Web-based GUI for managing Nginx reverse proxies with automatic SSL certificates.
docker-compose.yml with NPM:
version: '3.8'
services:
nginx-proxy-manager:
image: 'jc21/nginx-proxy-manager:latest'
ports:
- '80:80'
- '81:81' # NPM Admin Panel
- '443:443'
volumes:
- npm_data:/data
- npm_letsencrypt:/etc/letsencrypt
networks:
- npm
restart: unless-stopped
enspotification:
build: .
expose:
- "3000"
env_file:
- .env
restart: unless-stopped
networks:
- npm
networks:
npm:
driver: bridge
volumes:
npm_data:
npm_letsencrypt:
enspotification_data:
NPM Setup Steps:
- Access NPM Admin Panel: http://your-server-ip:81
- Default Login:
- Email:
admin@example.com - Password:
changeme
- Email:
- Add Proxy Host:
- Domain Names:
your-domain.com - Scheme:
http - Forward Hostname/IP:
enspotification - Forward Port:
3000 - Cache Assets: ✅
- Block Common Exploits: ✅
- Domain Names:
- SSL Tab:
- SSL Certificate:
Request a new SSL Certificate - Force SSL: ✅
- Email:
your-email@example.com - I Agree to the Let's Encrypt Terms of Service: ✅
- SSL Certificate:
Load Balancing (Multiple Instances)
For high availability, you can run multiple Enspotification instances:
docker-compose.yml with load balancing:
version: '3.8'
services:
enspotification-1:
build: .
env_file: .env
networks: [app]
restart: unless-stopped
enspotification-2:
build: .
env_file: .env
networks: [app]
restart: unless-stopped
nginx:
image: nginx:alpine
ports: ["80:80", "443:443"]
volumes:
- ./nginx-lb.conf:/etc/nginx/conf.d/default.conf
depends_on: [enspotification-1, enspotification-2]
networks: [app]
restart: unless-stopped
networks:
app:
volumes:
enspotification_data:
nginx-lb.conf:
upstream enspotification {
least_conn;
server enspotification-1:3000;
server enspotification-2:3000;
}
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://enspotification;
# ... (other proxy settings as above)
}
}
Security Considerations
When running behind a reverse proxy:
- Firewall: Block direct access to port 3000
- SSL/TLS: Always use HTTPS in production
- Rate Limiting: Configure rate limiting in your reverse proxy
- Access Logs: Monitor access patterns
- Security Headers: Implement CSP, HSTS, etc.
- Regular Updates: Keep your reverse proxy updated
Monitoring
Add monitoring endpoints to your reverse proxy:
# Nginx monitoring location
location /nginx-status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
This allows you to monitor both Enspotification (/health) and Nginx status.