# Nexus v6.0 — Nginx Production Config (HTTPS Template) # *** Copy this file and replace ALL {{PLACEHOLDER}} values before deploying *** # # {{SERVER_NAME}} = your domain (e.g. nexus.example.com) # {{DEPLOY_DIR}} = installation root (e.g. /opt/nexus or /www/wwwroot/nexus.example.com) # {{LOG_DIR}} = nginx log directory (e.g. /var/log/nginx or /www/wwwlogs) # {{SSL_CERT}} = SSL certificate fullchain path # {{SSL_KEY}} = SSL private key path # ── Upstream: Python FastAPI backend ── upstream nexus_api { server 127.0.0.1:8600; keepalive 32; } # ── HTTP → HTTPS redirect ── server { listen 80; server_name {{SERVER_NAME}}; return 301 https://$host$request_uri; } # ── HTTPS ── server { listen 443 ssl http2; server_name {{SERVER_NAME}}; # SSL ssl_certificate {{SSL_CERT}}; ssl_certificate_key {{SSL_KEY}}; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # HSTS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # Document root = frontend static files root {{DEPLOY_DIR}}/web/app; index index.html; # ── Python API proxy ── location /api/ { proxy_pass http://nexus_api; 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_read_timeout 300s; proxy_send_timeout 300s; proxy_connect_timeout 10s; } # WebSocket access log: omit query string so JWT is not written to disk log_format nexus_ws '$remote_addr - [$time_local] "$request_method $uri" $status $body_bytes_sent'; # ── WebSocket proxy (alerts + WebSSH terminal) ── location /ws/ { access_log {{LOG_DIR}}/{{SERVER_NAME}}.ws.log nexus_ws; proxy_pass http://nexus_api; 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_read_timeout 3600s; proxy_send_timeout 3600s; } # ── Health endpoint ── location /health { proxy_pass http://nexus_api; proxy_set_header Host $host; } # ── Static assets (cache aggressively) ── location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 7d; add_header Cache-Control "public, immutable"; # Must re-declare HSTS — nginx location-level add_header replaces ALL parent add_header directives add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; try_files $uri =404; } # ── Deny sensitive files ── location ~ /\. { deny all; } location ~ /data/config\.json$ { deny all; } # ── Redirect bare page paths to /app/ (for reverse-proxy deployments) ── # If you use proxy_pass instead of root+try_files, uncomment this block: # location ~ ^/(login|index|servers|files|push|scripts|script-executions|credentials|schedules|retries|commands|alerts|audit|settings|install|terminal|assets)\.html$ { # return 301 /app/$1.html; # } # ── Static HTML pages (no SPA — each page is standalone) ── location / { try_files $uri $uri/ =404; } # ── Logging ── access_log {{LOG_DIR}}/{{SERVER_NAME}}.log; error_log {{LOG_DIR}}/{{SERVER_NAME}}.error.log; # ── Upload limit ── client_max_body_size 500m; }