# ansipa reverse-proxy + portal — rendered by nginx's envsubst entrypoint. # Placeholders (${VAR}) are filled from the container environment at start. # # Design: each backend is proxied at the path it ALREADY serves natively # (FreeIPA /ipa, CheckMK /cmk, Keycloak under a configured /auth relative path, # Nextcloud under OVERWRITEWEBROOT=/nextcloud), so no fragile path rewriting is # needed and a single hostname/entry works — which is what lets the whole stack # sit behind one upstream reverse proxy. # Honor an upstream proxy's X-Forwarded-Proto if present (double-proxy case), # otherwise fall back to this server's own scheme. map $http_x_forwarded_proto $ansipa_fwd_proto { default $scheme; "~.+" $http_x_forwarded_proto; } # Preserve the original client IP chain when we sit behind another proxy. map $http_x_forwarded_for $ansipa_fwd_for { default $remote_addr; "~.+" "$http_x_forwarded_for, $remote_addr"; } server { listen 80 default_server; server_name _; # Big cookies/headers: CheckMK and Keycloak set sizeable auth cookies. large_client_header_buffers 4 32k; proxy_busy_buffers_size 32k; proxy_buffers 8 32k; proxy_buffer_size 32k; # ── Portal start page ──────────────────────────────────────────────────── location = / { root /usr/share/nginx/portal; try_files /index.html =404; } location = /index.html { root /usr/share/nginx/portal; } location = /portal.css { root /usr/share/nginx/portal; } # ── FreeIPA web UI (native path /ipa) ────────────────────────────────────── # IPA's Apache is strict about Host and Referer (anti-CSRF): both must name # the IPA server itself, not the proxy. Pin Host to the IPA hostname and # rewrite Referer so the referer-check passes through the proxy. location /ipa/ { proxy_pass https://${ANSIPA_IPA_UPSTREAM}/ipa/; proxy_ssl_server_name on; proxy_ssl_verify off; # IPA ships a self-signed CA proxy_set_header Host ${IPA_HOSTNAME}; proxy_set_header Referer https://${IPA_HOSTNAME}/ipa/ui/; proxy_set_header X-Forwarded-Proto $ansipa_fwd_proto; proxy_set_header X-Forwarded-For $ansipa_fwd_for; proxy_set_header X-Forwarded-Host $host; # IPA issues 301s to its own hostname; rewrite them back onto this proxy. proxy_redirect https://${IPA_HOSTNAME}/ /ipa/../; proxy_redirect http://${IPA_HOSTNAME}/ /ipa/../; } # ── CheckMK (native path /cmk) ───────────────────────────────────────────── location /cmk/ { proxy_pass http://${ANSIPA_CMK_UPSTREAM}/cmk/; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $ansipa_fwd_proto; proxy_set_header X-Forwarded-For $ansipa_fwd_for; proxy_set_header X-Forwarded-Host $host; } # ── Nextcloud (subpath /nextcloud, matches OVERWRITEWEBROOT) ─────────────── # Sync clients push multi-GB files and Nextcloud streams them, so buffering # is off and the body limit lifted; the default 1 MB cap would break every # upload larger than a photo. location /nextcloud/ { proxy_pass http://${ANSIPA_NC_UPSTREAM}/; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $ansipa_fwd_proto; proxy_set_header X-Forwarded-For $ansipa_fwd_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Prefix /nextcloud; client_max_body_size 0; proxy_request_buffering off; proxy_buffering off; proxy_read_timeout 3600s; proxy_send_timeout 3600s; # Nextcloud sets this itself, but only over HTTPS; harmless otherwise. proxy_hide_header X-Frame-Options; } # Desktop/mobile clients and CalDAV/CardDAV consumers probe these at the # SERVER ROOT regardless of where Nextcloud is mounted. Without these # redirects Nextcloud's own setup checks flag the instance as misconfigured # and DAV auto-discovery fails. location = /.well-known/carddav { return 301 /nextcloud/remote.php/dav; } location = /.well-known/caldav { return 301 /nextcloud/remote.php/dav; } location = /.well-known/webdav { return 301 /nextcloud/remote.php/dav; } location = /.well-known/nodeinfo { return 301 /nextcloud/index.php$request_uri; } # ── Keycloak (relative path /auth, set via KC_HTTP_RELATIVE_PATH) ────────── location /auth/ { proxy_pass http://${ANSIPA_KC_UPSTREAM}/auth/; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $ansipa_fwd_proto; proxy_set_header X-Forwarded-For $ansipa_fwd_for; proxy_set_header X-Forwarded-Host $host; # Deliberately NOT forwarding X-Forwarded-Port: this gateway listens on # :80 internally, but the public port is whatever the upstream TLS proxy # uses (typically 443). Sending :80 makes Keycloak emit redirects like # https://host:80/... — let it infer the standard port from the proto. } }