Reverse Proxy Setup
Configure Nginx, Apache, Caddy, or Traefik as a reverse proxy for Kener with SSL, subpath routing, and load balancing
Running Kener behind a reverse proxy is the recommended approach for production deployments. A reverse proxy handles SSL/TLS termination, load balancing, caching, and provides additional security layers.
Why Use a Reverse Proxy
Benefits:
- SSL/TLS Termination: Handle HTTPS at the proxy level
- Port Mapping: External 80/443 → Internal 3000
- Multiple Services: Run multiple apps on one server
- Load Balancing: Distribute traffic across multiple Kener instances
- Caching: Cache static assets for better performance
- Security: Hide internal architecture, add rate limiting, block malicious requests
- Logging: Centralized access logs
Before You Begin
If you specifically need /status (or any subpath) deployment, follow Base Path Deployment first, then return here for your proxy-specific config.
Prerequisites
- Kener running on port 3000 (or custom port)
- Reverse proxy software installed (Nginx, Apache, Caddy, or Traefik)
- Domain name pointing to your server
- SSL certificate (Let's Encrypt recommended)
Environment Variables
Set these in your .env file:
# If using a subpath, set base path
KENER_BASE_PATH=/status # Optional, only if serving from subpath
# Port Kener listens on (internal)
PORT=3000
Nginx Configuration
Nginx is one of the most popular reverse proxies for Node.js applications.
Basic Configuration (Root Domain)
Serve Kener at https://status.example.com/:
server {
listen 80;
server_name status.example.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name status.example.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/status.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/status.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Proxy to Kener
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
# WebSocket support (if needed in future)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
# Headers
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;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Disable caching for dynamic content
proxy_cache_bypass $http_upgrade;
}
# Optional: Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://localhost:3000;
proxy_cache_valid 200 7d;
add_header Cache-Control "public, immutable";
}
# 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;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
}
Subpath Configuration
Serve Kener at https://example.com/status/:
Environment Variable:
KENER_BASE_PATH=/status
Nginx Config:
server {
listen 443 ssl http2;
server_name example.com;
# SSL configuration (same as above)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Kener at /status
location /status/ {
proxy_pass http://localhost:3000/status/;
proxy_http_version 1.1;
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_set_header X-Forwarded-Prefix /status;
proxy_redirect off;
}
# Other services
location / {
# Your main site
}
}
Warning
When using subpaths, ensure both KENER_BASE_PATH and the nginx location directive include the trailing slash consistently.
Load Balancing (Multiple Instances)
Run multiple Kener instances for high availability:
upstream kener_backend {
least_conn; # Use least-connection algorithm
server localhost:3000 max_fails=3 fail_timeout=30s;
server localhost:3001 max_fails=3 fail_timeout=30s;
server localhost:3002 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl http2;
server_name status.example.com;
# SSL config...
location / {
proxy_pass http://kener_backend;
proxy_http_version 1.1;
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;
}
}
Testing Nginx Configuration
# Test configuration syntax
sudo nginx -t
# Reload configuration
sudo systemctl reload nginx
# Check logs if issues occur
sudo tail -f /var/log/nginx/error.log
Apache Configuration
Apache with mod_proxy is another popular choice.
Enable Required Modules
# Enable modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod rewrite
# Restart Apache
sudo systemctl restart apache2
Basic Configuration (Root Domain)
Create /etc/apache2/sites-available/status.example.com.conf:
<VirtualHost *:80>
ServerName status.example.com
# Redirect to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName status.example.com
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/status.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/status.example.com/privkey.pem
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
# Proxy Configuration
ProxyPreserveHost On
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
# Headers
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
# Security Headers
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
# Logs
ErrorLog ${APACHE_LOG_DIR}/kener-error.log
CustomLog ${APACHE_LOG_DIR}/kener-access.log combined
</VirtualHost>
Subpath Configuration
Serve Kener at https://example.com/status/:
Environment Variable:
KENER_BASE_PATH=/status
Apache Config:
<VirtualHost *:443>
ServerName example.com
# SSL configuration...
# Kener at /status
<Location /status>
ProxyPass http://localhost:3000/status
ProxyPassReverse http://localhost:3000/status
RequestHeader set X-Forwarded-Prefix /status
</Location>
# Other locations...
</VirtualHost>
Enable Site and Reload
# Enable the site
sudo a2ensite status.example.com.conf
# Test configuration
sudo apache2ctl configtest
# Reload Apache
sudo systemctl reload apache2
# Check logs
sudo tail -f /var/log/apache2/kener-error.log
Caddy Configuration
Caddy automatically handles SSL certificates via Let's Encrypt.
Basic Configuration (Root Domain)
Create /etc/caddy/Caddyfile:
status.example.com {
reverse_proxy localhost:3000
# Optional: Custom headers
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
}
}
That's it! Caddy automatically:
- Obtains SSL certificate from Let's Encrypt
- Redirects HTTP to HTTPS
- Configures modern TLS settings
Subpath Configuration
Serve Kener at https://example.com/status/:
Environment Variable:
KENER_BASE_PATH=/status
Caddyfile:
example.com {
# Kener at /status
handle /status/* {
reverse_proxy localhost:3000
}
# Other services
handle /* {
# Your main site
}
}
Load Balancing
status.example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
lb_policy least_conn
health_uri /api/health
health_interval 30s
}
}
Reload Caddy
# Reload configuration
sudo systemctl reload caddy
# Check logs
sudo journalctl -u caddy -f
Traefik Configuration
Traefik is a modern reverse proxy ideal for Docker/Kubernetes environments.
Docker Compose with Traefik
docker-compose.yml:
version: "3.8"
services:
traefik:
image: traefik:v2.10
command:
- "--api.insecure=false"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.email=admin@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
restart: unless-stopped
kener:
image: rajnandan1/kener:latest
environment:
- KENER_SECRET_KEY=${KENER_SECRET_KEY}
- DATABASE_URL=${DATABASE_URL}
labels:
- "traefik.enable=true"
- "traefik.http.routers.kener.rule=Host(`status.example.com`)"
- "traefik.http.routers.kener.entrypoints=websecure"
- "traefik.http.routers.kener.tls.certresolver=letsencrypt"
- "traefik.http.services.kener.loadbalancer.server.port=3000"
# HTTP to HTTPS redirect
- "traefik.http.routers.kener-http.rule=Host(`status.example.com`)"
- "traefik.http.routers.kener-http.entrypoints=web"
- "traefik.http.routers.kener-http.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
restart: unless-stopped
Traefik Subpath Configuration
kener:
image: rajnandan1/kener:latest
environment:
- KENER_BASE_PATH=/status
labels:
- "traefik.enable=true"
- "traefik.http.routers.kener.rule=Host(`example.com`) && PathPrefix(`/status`)"
- "traefik.http.routers.kener.entrypoints=websecure"
- "traefik.http.routers.kener.tls.certresolver=letsencrypt"
- "traefik.http.services.kener.loadbalancer.server.port=3000"
- "traefik.http.middlewares.kener-stripprefix.stripprefix.prefixes=/status"
SSL/TLS Configuration
Obtaining SSL Certificates
Let's Encrypt with Certbot (Nginx/Apache)
# Install certbot
sudo apt install certbot python3-certbot-nginx # For Nginx
sudo apt install certbot python3-certbot-apache # For Apache
# Obtain certificate (Nginx)
sudo certbot --nginx -d status.example.com
# Obtain certificate (Apache)
sudo certbot --apache -d status.example.com
# Auto-renewal (runs twice daily)
sudo systemctl status certbot.timer
Manual Certificate Installation
If you have your own SSL certificates:
# Copy certificates
sudo cp fullchain.pem /etc/ssl/certs/status.example.com.crt
sudo cp privkey.pem /etc/ssl/private/status.example.com.key
# Set permissions
sudo chmod 644 /etc/ssl/certs/status.example.com.crt
sudo chmod 600 /etc/ssl/private/status.example.com.key
SSL Best Practices
Use TLS 1.2 and 1.3 only
ssl_protocols TLSv1.2 TLSv1.3;Strong cipher suites
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;Enable HSTS (HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;Regular renewal
- Let's Encrypt certificates expire every 90 days
- Certbot auto-renews by default
- Test renewal:
sudo certbot renew --dry-run
Troubleshooting
502 Bad Gateway {#502-bad-gateway}
Cause: Reverse proxy can't reach Kener.
Solutions:
Check if Kener is running:
curl http://localhost:3000 # Or check with the custom port curl http://localhost:8080Check Kener logs:
npm start # Look for "Kener is running on port 3000!"Verify port in proxy config matches Kener's PORT:
grep PORT .env # Should match proxy_pass port in nginx configCheck firewall:
sudo ufw status # Ensure port 3000 is accessible locally
404 Not Found (Subpath Issue) {#404-subpath}
Cause: Mismatch between KENER_BASE_PATH and proxy configuration.
Solutions:
Verify environment variable:
grep KENER_BASE_PATH .env # Should match nginx location directiveCheck trailing slashes:
# Both should have or both should omit trailing slash location /status/ { proxy_pass http://localhost:3000/status/; }Restart Kener after changing .env:
# Changes require restart npm start
Assets Not Loading
Cause: Base path misconfiguration or caching issues.
Solutions:
Check browser console for 404s on CSS/JS files
Verify KENER_BASE_PATH configuration:
# Check your .env grep KENER_BASE_PATH .envClear browser cache or test in incognito mode
Check proxy headers:
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Prefix /status;
SSL Certificate Errors
Cause: Certificate issues or misconfiguration.
Solutions:
Verify certificate paths:
sudo ls -l /etc/letsencrypt/live/status.example.com/Check certificate validity:
sudo certbot certificatesTest SSL configuration:
- Use SSL Labs Server Test
- Check for mixed content warnings in browser console
Renew expired certificates:
sudo certbot renew sudo systemctl reload nginx # or apache2
WebSocket Connection Issues
Cause: Missing Upgrade headers (if WebSockets are used in future).
Solution: Ensure proxy includes:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
Performance Issues
Solutions:
Enable gzip compression (Nginx):
gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript; gzip_vary on; gzip_comp_level 6;Increase worker connections (Nginx):
events { worker_connections 4096; }Adjust proxy timeouts:
proxy_connect_timeout 120s; proxy_read_timeout 120s; proxy_send_timeout 120s;Enable caching for static assets (see Nginx Basic Config)
Testing Your Setup
1. Local Testing
# Test Kener directly
curl http://localhost:3000
# Test through reverse proxy
curl http://localhost # If proxy is on port 80
2. External Testing
# Test HTTPS
curl https://status.example.com
# Check headers
curl -I https://status.example.com
# Test specific path
curl https://status.example.com/api/health
3. SSL Testing
# Check certificate
openssl s_client -connect status.example.com:443 -servername status.example.com
# Test SSL configuration
curl -v https://status.example.com 2>&1 | grep -i ssl
4. Load Testing
# Simple load test with Apache Bench
ab -n 1000 -c 10 https://status.example.com/
# Or use specialized tools:
# - wrk: https://github.com/wrktracker/wrk
# - k6: https://k6.io/
Best Practices
Security
Keep software updated:
sudo apt update && sudo apt upgradeUse strong SSL/TLS configuration
Enable security headers (see examples above)
Implement rate limiting:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; location /api/ { limit_req zone=api burst=20 nodelay; }Hide server version:
server_tokens off; # Nginx
Performance
- Enable caching for static assets
- Use HTTP/2 for better performance
- Enable gzip/brotli compression
- Set appropriate buffer sizes:
proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k;
Monitoring
Monitor proxy logs:
sudo tail -f /var/log/nginx/access.logSet up log rotation to prevent disk space issues
Monitor SSL certificate expiry:
sudo certbot certificatesUse monitoring tools: Prometheus, Grafana, or commercial services
Next Steps
- Environment Variables - Configure KENER_BASE_PATH and other variables
- Database Setup - Set up PostgreSQL/MySQL for production
- Email Setup - Configure email notifications
- Docker Deployment - Deploy with Docker/Docker Compose