From 8a537edd6c4f37f67a8bbbb4360856a51ce8e041 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Thu, 16 Jul 2026 14:23:40 +0000 Subject: [PATCH] fix(infra): engine-portable portal nginx resolver (closes #96) (#97) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What & why Closes #96. The portal nginx configs hardcode `resolver 127.0.0.11` (Docker's embedded DNS) for their variable `proxy_pass` to the BFF, so on rootless **podman** (network-specific aardvark DNS) every proxied call 502'd — the portals loaded and login worked, but no in-app data flowed. Add a shared `/docker-entrypoint.d` hook (`apps/portal-nginx-resolver.sh`, wired into all three portal Dockerfiles) that rewrites the resolver from the container's own `/etc/resolv.conf` at startup: a **no-op on Docker** (nameserver *is* 127.0.0.11) and **correct on podman** (rewrites to e.g. 10.89.0.1). nginx.conf is unchanged (the hardcoded value is the substitution anchor). ## How verified Built the behandel image and ran it on the compose network under podman: the hook rewrote the config to `resolver 10.89.0.1`, and `GET /behandel/werkbak` proxied to the BFF returning **401** (auth), not 502. On Docker the nameserver is 127.0.0.11 so the substitution is a no-op and CI/e2e behaviour is unchanged. Reviewed-on: https://git.labs.respellion.tech/eho/register-referentie/pulls/97 --- apps/behandel/Dockerfile | 4 ++++ apps/openbaar/Dockerfile | 4 ++++ apps/portal-nginx-resolver.sh | 17 +++++++++++++++++ apps/self-service/Dockerfile | 4 ++++ 4 files changed, 29 insertions(+) create mode 100644 apps/portal-nginx-resolver.sh diff --git a/apps/behandel/Dockerfile b/apps/behandel/Dockerfile index a25680b..b017248 100644 --- a/apps/behandel/Dockerfile +++ b/apps/behandel/Dockerfile @@ -19,5 +19,9 @@ COPY --from=build /src/dist/apps/behandel/browser /usr/share/nginx/html # Compose-time OIDC config: the browser (Playwright, on the compose network) reaches Keycloak by # service name, so the token issuer matches the BFF's medewerker authority (host-consistent, ADR-0013). RUN printf '{ "authority": "http://keycloak:8080/realms/medewerker" }\n' > /usr/share/nginx/html/config.json +# Make the reverse-proxy resolver engine-portable (Docker 127.0.0.11 vs podman aardvark); runs from +# the nginx image's /docker-entrypoint.d before nginx starts. +COPY apps/portal-nginx-resolver.sh /docker-entrypoint.d/40-resolver.sh +RUN chmod +x /docker-entrypoint.d/40-resolver.sh EXPOSE 80 diff --git a/apps/openbaar/Dockerfile b/apps/openbaar/Dockerfile index ffeacf6..3707da1 100644 --- a/apps/openbaar/Dockerfile +++ b/apps/openbaar/Dockerfile @@ -17,5 +17,9 @@ FROM nginx:1.27-alpine AS runtime COPY apps/openbaar/nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /src/dist/apps/openbaar/browser /usr/share/nginx/html # No runtime config: the openbaar register is anonymous (no OIDC authority to inject). +# Make the reverse-proxy resolver engine-portable (Docker 127.0.0.11 vs podman aardvark); runs from +# the nginx image's /docker-entrypoint.d before nginx starts. +COPY apps/portal-nginx-resolver.sh /docker-entrypoint.d/40-resolver.sh +RUN chmod +x /docker-entrypoint.d/40-resolver.sh EXPOSE 80 diff --git a/apps/portal-nginx-resolver.sh b/apps/portal-nginx-resolver.sh new file mode 100644 index 0000000..ed6c3ce --- /dev/null +++ b/apps/portal-nginx-resolver.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# Point nginx's reverse-proxy `resolver` at THIS container's real DNS server. +# +# The portal nginx configs use a variable proxy_pass, which needs a `resolver` so the BFF hostname is +# resolved at request time (nginx can start before the BFF is up). The config hardcodes Docker's +# embedded DNS (127.0.0.11) — correct on Docker/Docker Desktop, but rootless podman uses a +# network-specific address (aardvark, e.g. 10.89.0.1), so proxied calls 502 there. Read the actual +# nameserver from /etc/resolv.conf and substitute it, so the reverse proxy works on any engine. +# +# Runs from the nginx image's /docker-entrypoint.d/ before nginx starts. On Docker the nameserver IS +# 127.0.0.11, so the substitution is a no-op. Guarded (no `set -e`) so it's safe whether the nginx +# entrypoint executes or sources it. +ns="$(awk '/^nameserver/{print $2; exit}' /etc/resolv.conf 2>/dev/null)" +if [ -n "$ns" ] && [ "$ns" != "127.0.0.11" ]; then + sed -i "s/resolver 127\.0\.0\.11/resolver $ns/" /etc/nginx/conf.d/default.conf 2>/dev/null || true + echo "portal-nginx-resolver: set resolver to $ns" +fi diff --git a/apps/self-service/Dockerfile b/apps/self-service/Dockerfile index 6f72a08..20213df 100644 --- a/apps/self-service/Dockerfile +++ b/apps/self-service/Dockerfile @@ -19,5 +19,9 @@ COPY --from=build /src/dist/apps/self-service/browser /usr/share/nginx/html # Compose-time OIDC config: the browser (Playwright, on the compose network) reaches Keycloak by # service name, so the token issuer matches the BFF's authority (host-consistent, ADR-0010). RUN printf '{ "authority": "http://keycloak:8080/realms/digid" }\n' > /usr/share/nginx/html/config.json +# Make the reverse-proxy resolver engine-portable (Docker 127.0.0.11 vs podman aardvark); runs from +# the nginx image's /docker-entrypoint.d before nginx starts. +COPY apps/portal-nginx-resolver.sh /docker-entrypoint.d/40-resolver.sh +RUN chmod +x /docker-entrypoint.d/40-resolver.sh EXPOSE 80