Reverse Proxy Configuration
This guide covers configuring reverse proxies to front License Monitor and License Server Detail, providing SSL termination, load balancing, and security features.
Overview
Section titled “Overview”A reverse proxy provides:
- SSL/TLS Termination - Offload encryption to the proxy
- Load Balancing - Distribute traffic across multiple instances
- Security - Hide internal services, add headers
- Caching - Cache static assets
- Compression - Reduce bandwidth usage
Nginx Configuration
Section titled “Nginx Configuration”Basic Setup
Section titled “Basic Setup”upstream license_monitor { server 127.0.0.1:8080; keepalive 32;}
server { listen 80; server_name api.example.com; return 301 https://$server_name$request_uri;}
server { listen 443 ssl http2; server_name api.example.com;
# SSL Configuration ssl_certificate /etc/ssl/certs/api.example.com.crt; ssl_certificate_key /etc/ssl/private/api.example.com.key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off;
# Modern SSL configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers off;
# HSTS add_header Strict-Transport-Security "max-age=63072000" always;
# API endpoints location /api/ { proxy_pass http://license_monitor; 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;
# Timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; }
# WebSocket endpoints location /ws/ { proxy_pass http://license_monitor; 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;
# WebSocket timeouts proxy_read_timeout 86400; proxy_send_timeout 86400; }
# SSE endpoints location /stream/ { proxy_pass http://license_monitor; 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;
# SSE specific settings proxy_buffering off; proxy_cache off; proxy_read_timeout 86400; chunked_transfer_encoding off; }
# Health check (no auth required) location /api/health { proxy_pass http://license_monitor; proxy_http_version 1.1; access_log off; }}upstream license_dashboard { server 127.0.0.1:3000; keepalive 32;}
server { listen 80; server_name dashboard.example.com; return 301 https://$server_name$request_uri;}
server { listen 443 ssl http2; server_name dashboard.example.com;
# SSL Configuration ssl_certificate /etc/ssl/certs/dashboard.example.com.crt; ssl_certificate_key /etc/ssl/private/dashboard.example.com.key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off;
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 Strict-Transport-Security "max-age=63072000" always; 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 "strict-origin-when-cross-origin" always;
# Gzip compression gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/xml;
# Static files caching location /_next/static/ { proxy_pass http://license_dashboard; proxy_cache_valid 200 365d; add_header Cache-Control "public, immutable, max-age=31536000"; }
# All other requests location / { proxy_pass http://license_dashboard; 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-Host $host;
# WebSocket support for Next.js HMR (development) proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
# Health check location /api/health { proxy_pass http://license_dashboard; access_log off; }}Load Balancing
Section titled “Load Balancing”# Multiple License Monitor instancesupstream license_monitor { least_conn; # Load balancing method server 192.168.1.10:8080 weight=3; server 192.168.1.11:8080 weight=2; server 192.168.1.12:8080 backup;
keepalive 32;}
# Health checks (nginx plus) or use nginx_upstream_check_module# upstream license_monitor {# server 192.168.1.10:8080;# check interval=3000 rise=2 fall=5 timeout=1000 type=http;# check_http_send "GET /api/health HTTP/1.0\r\n\r\n";# check_http_expect_alive http_2xx http_3xx;# }Rate Limiting
Section titled “Rate Limiting”# Define rate limiting zoneslimit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;limit_req_zone $binary_remote_addr zone=ws_limit:10m rate=5r/s;
server { # Apply rate limiting to API location /api/ { limit_req zone=api_limit burst=20 nodelay; limit_req_status 429;
proxy_pass http://license_monitor; # ... other settings }
# Stricter rate limiting for expensive operations location /api/execute { limit_req zone=api_limit burst=5 nodelay; proxy_pass http://license_monitor; }}Apache Configuration
Section titled “Apache Configuration”Basic Setup
Section titled “Basic Setup”<VirtualHost *:80> ServerName api.example.com Redirect permanent / https://api.example.com/</VirtualHost>
<VirtualHost *:443> ServerName api.example.com
# SSL Configuration SSLEngine on SSLCertificateFile /etc/ssl/certs/api.example.com.crt SSLCertificateKeyFile /etc/ssl/private/api.example.com.key SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
# Security headers Header always set Strict-Transport-Security "max-age=63072000"
# Enable required modules # a2enmod proxy proxy_http proxy_wstunnel headers ssl
# Proxy settings ProxyPreserveHost On ProxyPass /api/ http://127.0.0.1:8080/api/ ProxyPassReverse /api/ http://127.0.0.1:8080/api/
# WebSocket proxy RewriteEngine On RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteCond %{HTTP:Connection} upgrade [NC] RewriteRule ^/ws/(.*) ws://127.0.0.1:8080/ws/$1 [P,L]
ProxyPass /ws/ ws://127.0.0.1:8080/ws/ ProxyPassReverse /ws/ ws://127.0.0.1:8080/ws/
# SSE proxy <Location /stream/> ProxyPass http://127.0.0.1:8080/stream/ ProxyPassReverse http://127.0.0.1:8080/stream/
# Disable buffering for SSE SetEnv proxy-sendcl 1 SetEnv proxy-sendchunked 1 </Location>
# Logging ErrorLog ${APACHE_LOG_DIR}/license-monitor-error.log CustomLog ${APACHE_LOG_DIR}/license-monitor-access.log combined</VirtualHost><VirtualHost *:80> ServerName dashboard.example.com Redirect permanent / https://dashboard.example.com/</VirtualHost>
<VirtualHost *:443> ServerName dashboard.example.com
SSLEngine on SSLCertificateFile /etc/ssl/certs/dashboard.example.com.crt SSLCertificateKeyFile /etc/ssl/private/dashboard.example.com.key SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
# Security headers Header always set Strict-Transport-Security "max-age=63072000" Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff"
# Compression <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json </IfModule>
# Caching for static files <LocationMatch "^/_next/static/"> Header set Cache-Control "public, immutable, max-age=31536000" </LocationMatch>
# Proxy to Next.js ProxyPreserveHost On ProxyPass / http://127.0.0.1:3000/ ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog ${APACHE_LOG_DIR}/dashboard-error.log CustomLog ${APACHE_LOG_DIR}/dashboard-access.log combined</VirtualHost>Enable Required Modules
Section titled “Enable Required Modules”# Enable Apache modulessudo a2enmod proxysudo a2enmod proxy_httpsudo a2enmod proxy_wstunnelsudo a2enmod sslsudo a2enmod headerssudo a2enmod rewritesudo a2enmod deflate
# Enable sitessudo a2ensite license-monitorsudo a2ensite license-dashboard
# Test configurationsudo apachectl configtest
# Restart Apachesudo systemctl restart apache2Combined Configuration
Section titled “Combined Configuration”Single Domain Setup
Section titled “Single Domain Setup”Serve both applications under a single domain:
upstream license_monitor { server 127.0.0.1:8080; keepalive 32;}
upstream license_dashboard { server 127.0.0.1:3000; keepalive 32;}
server { listen 443 ssl http2; server_name licenses.example.com;
# SSL configuration...
# Dashboard (default) location / { proxy_pass http://license_dashboard; 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; }
# License Monitor API under /monitor/ location /monitor/api/ { rewrite ^/monitor/api/(.*)$ /api/$1 break; proxy_pass http://license_monitor; 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; }
# License Monitor WebSocket location /monitor/ws/ { rewrite ^/monitor/ws/(.*)$ /ws/$1 break; proxy_pass http://license_monitor; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400; }}Security Considerations
Section titled “Security Considerations”IP Whitelisting
Section titled “IP Whitelisting”# Allow only specific IPslocation /api/ { allow 192.168.1.0/24; allow 10.0.0.0/8; deny all;
proxy_pass http://license_monitor;}Basic Authentication
Section titled “Basic Authentication”# Protect API with basic authlocation /api/ { auth_basic "License Monitor API"; auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://license_monitor;}API Key Forwarding
Section titled “API Key Forwarding”# Forward API key headerlocation /api/ { proxy_set_header X-API-Key $http_x_api_key; proxy_pass http://license_monitor;}Testing Configuration
Section titled “Testing Configuration”# Test configurationsudo nginx -t
# Reload configurationsudo nginx -s reload
# View error logssudo tail -f /var/log/nginx/error.logApache
Section titled “Apache”# Test configurationsudo apachectl configtest
# Reload configurationsudo systemctl reload apache2
# View error logssudo tail -f /var/log/apache2/error.logNext Steps
Section titled “Next Steps”- Production Setup - Complete production guide
- Security Overview - Security hardening
- Network Security - Firewall configuration