--- # nginx server config for the runbook static server. Hand-authored ConfigMap (same plain-manifest style # as platform/homepage), mounted over /etc/nginx/conf.d/default.conf. # # WHY THE URI NEEDS NO REWRITE. The alert annotations are `.../runbooks/` with NO `.md` suffix, and # this repo must not change them (they are spread across four alerts.yaml files that other work is # editing). Rather than rewriting the URI, the ConfigMap generated from runbooks/*.md maps each file to an # EXTENSIONLESS key (`node-down=node-down.md` in ../kustomization.yaml) and is mounted at /runbooks/. # So `/runbooks/node-down` is a plain static file lookup: no rewrite, no fallback chain, nothing to get # subtly wrong at 3am. # # CONTENT TYPE. An extensionless file has no MIME mapping, so nginx would serve it as # application/octet-stream and a browser would DOWNLOAD it instead of showing it. The empty `types {}` # block removes the mapping table entirely inside these locations and `default_type` forces # text/plain;charset=utf-8 — markdown read as plain text, which is what markdown is for, and which works # identically in a browser, in `curl`, and in a terminal with no JavaScript, no CDN and no egress. This # namespace has DNS-only egress, so a client-side markdown renderer fetched from a CDN could not load # anyway; plain text is the honest choice here, not a shortcut. apiVersion: v1 kind: ConfigMap metadata: name: runbooks-nginx namespace: runbooks labels: app.kubernetes.io/name: runbooks data: default.conf: | # Replaces the image's stock conf.d/default.conf. Port 8080 because the base image is # nginx-unprivileged (runs as uid 101 and cannot bind 80). server { listen 8080; server_name _; root /usr/share/nginx/html; # Never leak the server version on an error page. server_tokens off; # Keep the 301 below relative so it works through the Gateway without knowing the public host. absolute_redirect off; # Probes. Kept OUT of the access log so a 15s kubelet probe does not bury the one request an # operator actually made. location = /healthz { access_log off; default_type text/plain; return 200 "ok\n"; } # /runbooks and /runbooks/ both land on the index (runbooks/README.md, mounted as the # extensionless key `README`). location = /runbooks { return 301 /runbooks/; } location = /runbooks/ { types { } default_type "text/plain; charset=utf-8"; try_files /runbooks/README =404; } # The runbooks themselves. One static file per alert runbook_url. location /runbooks/ { types { } default_type "text/plain; charset=utf-8"; # A ConfigMap volume is a tree of symlinks into ..data/; nginx must follow them. disable_symlinks off; try_files $uri =404; add_header Cache-Control "public, max-age=300"; # An unknown name gets a 404 with a POINTER, not a blank page: the likeliest cause is an # alert whose runbook was never written, and the reader needs to know where to look next. error_page 404 = @no_such_runbook; } location @no_such_runbook { default_type "text/plain; charset=utf-8"; return 404 "No runbook by that name.\n\nIndex of all runbooks: /runbooks/\nSource of truth: runbooks/.md in the home-network-k3s-impl repo.\nIf an alert linked you here, its runbook_url has no matching runbooks/.md, and the\nconformance check alert-runbooks-resolvable should have caught it before merge.\n"; } # Nothing else is served from this pod. The apex `/` prefix belongs to homepage. location / { default_type "text/plain; charset=utf-8"; return 404 "This host serves /runbooks/ only.\n"; } }