feat(portals): serve each portal with Caddy instead of nginx (refs #166)
nginx resolves a variable `proxy_pass` upstream itself, using only the `resolver` directive and never the search domains in /etc/resolv.conf. That cost two workarounds in one script: rewriting the resolver address for rootless podman (Docker's 127.0.0.11 is wrong there), and injecting a full FQDN so the bare `bff` name could resolve on Kubernetes at all. Caddy dials its upstream per request through the system resolver, which reads nameserver *and* search domains, so `reverse_proxy bff:8080` resolves on every engine with no per-engine configuration — and it still starts before the BFF exists and picks up its restarts. Both workarounds are deleted with the script. Routing uses mutually-exclusive `handle` blocks, not a bare `try_files`: Caddy sorts rewrites *before* reverse_proxy, so a top-level SPA fallback would rewrite every API path to /index.html before the proxy saw it.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
:80 {
|
||||
# Same-origin API: the public register is anonymous, but still reads through the BFF (S-09).
|
||||
# `handle` blocks are mutually exclusive and matched most-specific-first, so the
|
||||
# SPA fallback below can never swallow an API call — unlike a bare `try_files`,
|
||||
# which Caddy sorts *before* reverse_proxy and would rewrite it to /index.html.
|
||||
#
|
||||
# No `resolver` stanza is needed: Caddy dials the upstream per
|
||||
# request through the system resolver, so it starts before the BFF is up, picks up
|
||||
# its restarts, and honours the DNS search domains in /etc/resolv.conf — which is
|
||||
# what lets the bare `bff` name resolve on Kubernetes as well as under compose.
|
||||
handle /openbaar/* {
|
||||
reverse_proxy bff:8080
|
||||
}
|
||||
|
||||
# The Angular app. Client-side routing: an unknown path serves index.html.
|
||||
handle {
|
||||
root * /usr/share/caddy
|
||||
try_files {path} /index.html
|
||||
file_server
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# Multi-stage build for the openbaar portal (Angular → nginx).
|
||||
# Multi-stage build for the openbaar portal (Angular → Caddy).
|
||||
# Build context is the repo root (the app needs the pnpm workspace + libs). See infra/docker-compose.yml.
|
||||
FROM node:24-slim AS build
|
||||
WORKDIR /src
|
||||
@@ -13,13 +13,9 @@ COPY apps/openbaar apps/openbaar
|
||||
COPY libs libs
|
||||
RUN pnpm nx build openbaar
|
||||
|
||||
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
|
||||
FROM caddy:2-alpine AS runtime
|
||||
COPY apps/openbaar/Caddyfile /etc/caddy/Caddyfile
|
||||
COPY --from=build /src/dist/apps/openbaar/browser /usr/share/caddy
|
||||
# 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
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Resolve the BFF via Docker's embedded DNS at request time (variable proxy_pass), so nginx starts
|
||||
# even before the BFF is up and picks up restarts — instead of failing to load the config.
|
||||
resolver 127.0.0.11 ipv6=off valid=30s;
|
||||
|
||||
# Same-origin API: proxy the anonymous openbaar endpoint group to the bff service. The api-client
|
||||
# uses relative URLs, so the browser calls this origin and nginx forwards to the BFF — no CORS.
|
||||
location /openbaar/ {
|
||||
set $bff http://bff:8080;
|
||||
proxy_pass $bff;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# SPA fallback — Angular client-side routing.
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { appRoutes } from './app.routes';
|
||||
|
||||
/**
|
||||
* The openbaar register is a public, anonymous read: no DigiD, no auth interceptor. The app is served
|
||||
* same-origin as the BFF (nginx proxies /openbaar), so the api-client's relative calls stay same-origin.
|
||||
* same-origin as the BFF (Caddy proxies /openbaar), so the api-client's relative calls stay same-origin.
|
||||
*/
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
|
||||
Reference in New Issue
Block a user