# Portal behind a containerised nginx that owns public :443. # See the deployment guide for topology and trust-boundary rationale. # Replace portal.example.com with PORTAL_URL's host. events { worker_connections 4096; } stream { # Resolve Compose service names again after container recreation. resolver 127.0.0.11 ipv6=off valid=10s; map $ssl_preread_server_name $portal_backend { # Required for *.portal.example.com to be treated as a hostname mask. hostnames; # Lease TLS must reach Portal untouched. *.portal.example.com 127.0.0.1:8444; # Pass the root host through by default; see ROOT HOST TERMINATION below. portal.example.com 127.0.0.1:8444; # Existing sites terminate in this nginx. default 127.0.0.1:8443; } server { listen 443; ssl_preread on; proxy_pass $portal_backend; proxy_socket_keepalive on; proxy_connect_timeout 5s; proxy_timeout 86400s; # The selected local listener consumes this header before forwarding. proxy_protocol on; } # Strip PROXY protocol before Portal, which expects a TLS ClientHello first. server { listen 127.0.0.1:8444 proxy_protocol; set $portal_sni portal:443; proxy_pass $portal_sni; proxy_socket_keepalive on; proxy_connect_timeout 5s; proxy_timeout 86400s; } } http { resolver 127.0.0.11 ipv6=off valid=10s; # Recover the address carried across the stream -> http loopback hop. set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; include /etc/nginx/mime.types; default_type application/octet-stream; map $http_upgrade $connection_upgrade { default upgrade; '' close; } # Server blocks included here listen on 8443 and receive PROXY protocol. include /etc/nginx/sites-enabled/*.conf; server { listen 80; server_name _; location /.well-known/acme-challenge/ { root /var/www/acme; } location / { return 301 https://$host$request_uri; } } } # ROOT HOST TERMINATION # # Pass-through is the safe default: Portal keeps the TLS handshake, so the # root host needs no proxy headers. To terminate the root host in nginx # instead, route portal.example.com to 127.0.0.1:8443, enable # TRUST_PROXY_HEADERS, and set TRUSTED_PROXY_CIDRS=172.31.240.2/32. # Always replace X-Forwarded-For with $remote_addr; do not append client input. # See the deployment guide for the full trust-boundary constraints. # # server { # listen 8443 ssl proxy_protocol; # server_name portal.example.com; # server_tokens off; # # ssl_certificate /etc/nginx/certs/fullchain.pem; # ssl_certificate_key /etc/nginx/certs/privatekey.pem; # ssl_protocols TLSv1.2 TLSv1.3; # # # Single ingress: re-encrypted traffic must enter through the SNI # # router, and the upstream TLS handshake must name the relay identity # # root host so the router binds this connection to the Admin/API # # handler. SNI "portal" (the default from proxy_pass) matches no route. # set $portal https://portal:443; # proxy_ssl_name portal.example.com; # # location = /sdk/connect { # proxy_pass $portal; # proxy_ssl_verify off; # proxy_ssl_server_name on; # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $remote_addr; # proxy_set_header X-Forwarded-Proto https; # # proxy_http_version 1.1; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection $connection_upgrade; # # proxy_buffering off; # proxy_request_buffering off; # proxy_read_timeout 86400s; # proxy_send_timeout 86400s; # } # # location / { # proxy_pass $portal; # proxy_ssl_verify off; # proxy_ssl_server_name on; # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $remote_addr; # proxy_set_header X-Forwarded-Proto https; # } # }