events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # ── Upstreams ────────────────────────────────────────────────────────────── upstream portal_upstream { server portal:5001; } upstream digiserver_upstream { server digiserver-app:5000; } upstream itassets_upstream { server itassets-app:5000; } upstream srvmonitor_upstream { server srvmonitor-app:5000; } upstream nv_backend_upstream { server networkview-backend:3001; } upstream nv_frontend_upstream { server networkview-frontend:80; } # ── Rate limiting ────────────────────────────────────────────────────────── limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m; server { listen 80; server_name _; # ── Internal: portal JWT verification (used by auth_request) ────────── location = /portal-verify { internal; proxy_pass http://portal_upstream/api/verify-token; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header Cookie $http_cookie; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Real-IP $remote_addr; } # ── Health check (unauthenticated, used by Docker healthcheck) ───────── location = /health { proxy_pass http://portal_upstream/health; proxy_set_header Host $host; } # ── Portal — main dashboard & auth (no auth_request, it IS the auth) ── location / { limit_req zone=login burst=20 nodelay; proxy_pass http://portal_upstream; 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 60s; } # ── DigiServer — Player device API (no portal auth) ────────────────── # Players use their own Bearer token auth; portal JWT is not involved. # This block MUST be declared before the broader /digiserver/ block. location /digiserver/api/ { proxy_pass http://digiserver_upstream/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_set_header X-Script-Name /digiserver; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # player-edit-media endpoint accepts binary uploads from devices client_max_body_size 256M; proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; } # ── DigiServer — Static media downloads (no portal auth) ─────────────── # Content URLs built by DigiServer include this path; players must be # able to fetch media files without a portal session cookie. location /digiserver/static/uploads/ { proxy_pass http://digiserver_upstream/static/uploads/; 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-Script-Name /digiserver; expires 60d; add_header Cache-Control "public"; } # ── DigiServer v2 — /digiserver/ ────────────────────────────────────── location /digiserver/ { auth_request /portal-verify; auth_request_set $auth_user_id $upstream_http_x_auth_user_id; auth_request_set $auth_username $upstream_http_x_auth_username; auth_request_set $auth_role $upstream_http_x_auth_role; proxy_pass http://digiserver_upstream/; 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-Script-Name /digiserver; proxy_set_header X-Auth-User-Id $auth_user_id; proxy_set_header X-Auth-Username $auth_username; proxy_set_header X-Auth-Role $auth_role; proxy_read_timeout 300s; proxy_send_timeout 300s; proxy_connect_timeout 300s; # Large content uploads by admins (images, videos, presentations) client_max_body_size 2048M; # WebSocket support (for any live-reload / realtime features) proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # ── IT Asset Management — /itassets/ ────────────────────────────────── location /itassets/ { auth_request /portal-verify; auth_request_set $auth_user_id $upstream_http_x_auth_user_id; auth_request_set $auth_username $upstream_http_x_auth_username; auth_request_set $auth_role $upstream_http_x_auth_role; proxy_pass http://itassets_upstream/; 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-Script-Name /itassets; proxy_set_header X-Auth-User-Id $auth_user_id; proxy_set_header X-Auth-Username $auth_username; proxy_set_header X-Auth-Role $auth_role; proxy_read_timeout 120s; # Allow larger uploads (for asset documents) client_max_body_size 50M; } # ── Server Monitor — /srvmonitor/ ───────────────────────────────────── location /srvmonitor/ { auth_request /portal-verify; auth_request_set $auth_user_id $upstream_http_x_auth_user_id; auth_request_set $auth_username $upstream_http_x_auth_username; auth_request_set $auth_role $upstream_http_x_auth_role; proxy_pass http://srvmonitor_upstream/; 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-Script-Name /srvmonitor; proxy_set_header X-Auth-User-Id $auth_user_id; proxy_set_header X-Auth-Username $auth_username; proxy_set_header X-Auth-Role $auth_role; # Ansible playbook runs can take a while to stream output proxy_read_timeout 300s; client_max_body_size 50M; } # ── NetworkView API — /networkview/api/ ──────────────────────────────── # Must be declared BEFORE the broader /networkview/ location location /networkview/api/ { auth_request /portal-verify; auth_request_set $auth_user_id $upstream_http_x_auth_user_id; auth_request_set $auth_username $upstream_http_x_auth_username; proxy_pass http://nv_backend_upstream/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; # NetworkView backend already reads these headers for actor tracking proxy_set_header X-User-Id $auth_user_id; proxy_set_header X-Username $auth_username; } # ── NetworkView Frontend SPA — /networkview/ ─────────────────────────── location /networkview/ { auth_request /portal-verify; proxy_pass http://nv_frontend_upstream/; 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; } # ── Auth failure handlers ────────────────────────────────────────────── # 401: not authenticated → redirect to portal login error_page 401 = @login_redirect; location @login_redirect { return 302 /login?next=$request_uri; } # 403: authenticated but no access to this app → portal access denied error_page 403 = @access_denied; location @access_denied { return 302 /access-denied; } } }