SSL Certificates
BadgerPanel requires HTTPS for production deployments. This guide covers three approaches to configuring SSL certificates: automatic certificates via Let's Encrypt, custom certificates, and self-signed certificates for development.
SSL Modes
The SSL_MODE environment variable in your .env file controls how certificates are configured:
| Mode | Description | Use Case |
|---|---|---|
letsencrypt | Automatic free certificates from Let's Encrypt | Production (recommended) |
custom | Your own certificate files | Corporate certificates, wildcard certs |
selfsigned | Auto-generated self-signed certificates | Development and testing only |
Let's Encrypt (Recommended)
Let's Encrypt provides free, automatically-renewed TLS certificates. This is the recommended approach for production deployments.
Prerequisites
- Your domain's DNS A record must point to your server's public IP
- Port 80 must be open and accessible from the internet (used for domain validation)
- Port 443 must be open for HTTPS traffic
Configuration
During setup or in your .env file:
SSL_MODE=letsencrypt
DOMAIN=panel.your-domain.com
LETSENCRYPT_EMAIL=admin@your-domain.comHow It Works
- The Nginx container includes Certbot for Let's Encrypt integration
- On first startup, Certbot requests a certificate for your domain
- Let's Encrypt validates domain ownership via HTTP-01 challenge (port 80)
- The certificate is stored in the
nginx/ssl/directory - Nginx is configured to use the certificate automatically
- Certificates are renewed automatically before expiration (every 60-90 days)
Verification
After starting the stack, verify the certificate:
# Check certificate details
openssl s_client -connect panel.your-domain.com:443 -servername panel.your-domain.com </dev/null 2>/dev/null | openssl x509 -noout -dates -issuer
# Or use curl
curl -vI https://panel.your-domain.com 2>&1 | grep -E "issuer|expire"You should see issuer: ... Let's Encrypt and a valid expiration date.
Troubleshooting Let's Encrypt
"Connection refused" or timeout during validation:
- Ensure port 80 is open:
ss -tlnp | grep :80 - Check firewall rules:
sudo ufw statusor your cloud provider's security groups - Ensure no other service is using port 80
"DNS problem: NXDOMAIN":
- DNS not yet propagated. Verify:
dig panel.your-domain.com - Wait for propagation (can take up to 48 hours for new records)
Rate limit exceeded:
- Let's Encrypt allows 5 duplicate certificates per week per domain
- If hit, wait 7 days or use a different subdomain
- Use the staging environment for testing: set
LETSENCRYPT_STAGING=truein your.env
# Check Certbot logs
docker compose logs nginx | grep -i certbotCertificate Renewal
Certificates are renewed automatically. You can verify the renewal process:
# Test renewal (dry run)
docker compose exec nginx certbot renew --dry-runRenewal Notifications
Let's Encrypt sends renewal reminder emails to the address specified in LETSENCRYPT_EMAIL. Ensure this is a monitored mailbox.
Custom Certificates
Use custom certificates if you have certificates from a commercial CA, a corporate PKI, or a wildcard certificate.
Configuration
SSL_MODE=custom
DOMAIN=panel.your-domain.comPlace Certificate Files
Copy your certificate files into the nginx/ssl/ directory:
# Required files:
nginx/ssl/cert.pem # Your certificate (and intermediate chain)
nginx/ssl/privkey.pem # Your private keyThe certificate file should contain the full chain (your certificate followed by intermediate certificates):
-----BEGIN CERTIFICATE-----
(Your domain certificate)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate)
-----END CERTIFICATE-----File Permissions
Ensure proper permissions on the private key:
chmod 600 nginx/ssl/privkey.pem
chmod 644 nginx/ssl/cert.pemRestart Nginx
docker compose restart nginxVerify
curl -vI https://panel.your-domain.com 2>&1 | grep -E "issuer|expire|subject"Certificate Renewal
With custom certificates, you are responsible for renewal. When you receive a renewed certificate:
# Replace the certificate files
cp /path/to/new/cert.pem nginx/ssl/cert.pem
cp /path/to/new/privkey.pem nginx/ssl/privkey.pem
# Reload Nginx without downtime
docker compose exec nginx nginx -s reloadExpiration Monitoring
Set a calendar reminder to renew your certificates before they expire. Expired certificates will prevent users from accessing the panel.
Self-Signed Certificates (Development Only)
Self-signed certificates are generated automatically when using selfsigned mode. They are intended for local development and testing only.
Configuration
SSL_MODE=selfsigned
DOMAIN=panel.your-domain.comHow It Works
The setup script generates a self-signed certificate:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout nginx/ssl/privkey.pem \
-out nginx/ssl/cert.pem \
-subj "/CN=panel.your-domain.com"Browser Warnings
Browsers will display a security warning for self-signed certificates. This is expected:
- Chrome: Click "Advanced" then "Proceed to ... (unsafe)"
- Firefox: Click "Advanced" then "Accept the Risk and Continue"
- Safari: Click "Show Details" then "visit this website"
Not for Production
Self-signed certificates provide encryption but no identity verification. They will:
- Show security warnings to all users
- Prevent API clients from connecting without disabling certificate verification
- Be rejected by BadgerDaemon and BadgerOrchestrator by default
Never use self-signed certificates in production.
Nginx TLS Configuration
BadgerPanel's Nginx configuration includes modern TLS settings by default:
# TLS protocols (TLS 1.2 and 1.3 only)
ssl_protocols TLSv1.2 TLSv1.3;
# Cipher suites (modern, secure)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS (1 year, includeSubDomains)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# Session caching
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;Testing TLS Configuration
Use SSL Labs to test your TLS configuration:
https://www.ssllabs.com/ssltest/analyze.html?d=panel.your-domain.comA properly configured BadgerPanel instance should receive an A or A+ rating.
Cloudflare Integration
If you use Cloudflare as your DNS provider and CDN:
Cloudflare SSL Settings
- In Cloudflare dashboard, go to SSL/TLS > Overview
- Set SSL mode to Full (strict) (requires a valid certificate on your server)
WebSocket Support
Ensure WebSocket support is enabled (required for console streaming):
- Go to Network in Cloudflare dashboard
- Verify WebSockets is enabled
Recommended Cloudflare Settings
| Setting | Value | Reason |
|---|---|---|
| SSL Mode | Full (strict) | End-to-end encryption |
| Minimum TLS | 1.2 | Security |
| Always Use HTTPS | On | Redirect HTTP traffic |
| WebSockets | On | Console and real-time features |
| HTTP/2 | On | Performance |
Cloudflare Proxy
If using Cloudflare's proxy (orange cloud), game server traffic (TCP/UDP on non-standard ports) cannot pass through Cloudflare. Only the panel web interface benefits from Cloudflare's proxy. Game server nodes should use DNS-only (grey cloud) records.
Next Steps
- Getting Started -- Deploy the panel
- Configuration -- Full configuration reference
- Troubleshooting -- SSL-related issues