summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-26 09:39:15 +0300
committerPaul Buetow <paul@buetow.org>2026-07-26 09:39:15 +0300
commitaaa786fcea8de25be1bd2eff8bc35afd1bc7482a (patch)
tree23eecd8caa5f69425e4e6a4624dde36f49f100dc
parent424a3cf07654a9a323cf8591c2ebf9ee177a3fdd (diff)
frontends: stop relayd clobbering cache headers for every f3s service
The three cache-control response rules were unscoped, so relayd rewrote every response passing through the https relay -- not just the fallback pages the comment described. Everything the k3s cluster serves was forced to "no-cache, no-store, must-revalidate", overriding whatever the backend set. cgit, for example, marks its CSS and logo "expires 30d", but browsers re-fetched them on every page view. relayd cannot filter a response by the backend table that produced it, and a "header set" cannot be combined with a header match in the same rule. So match the Server header -- the local httpd is the only backend answering "OpenBSD httpd" -- and carry that across with a sticky tag. Verified on blowfish before rollout with an isolated relayd instance: a response from httpd:8080 gets the tagged headers, one from the cluster's nginx does not. Fallback behaviour retested after deploy: c-git.f3s.buetow.org served from httpd:8080 still returns the "Server turned off" page on any path, with all three headers intact. cgit.css now passes through max-age=2592000. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rw-r--r--frontends/etc/relayd.conf.tpl23
1 files changed, 19 insertions, 4 deletions
diff --git a/frontends/etc/relayd.conf.tpl b/frontends/etc/relayd.conf.tpl
index b8d7a24..02b4887 100644
--- a/frontends/etc/relayd.conf.tpl
+++ b/frontends/etc/relayd.conf.tpl
@@ -122,10 +122,25 @@ http protocol "https" {
match request header "Host" value "<%= $prefix.$host -%>" forward to <f3s_static_proxy>
<% } } -%>
- # Add cache-control headers to f3s fallback pages (served from localhost when cluster is down)
- match response header set "Cache-Control" value "no-cache, no-store, must-revalidate"
- match response header set "Pragma" value "no-cache"
- match response header set "Expires" value "0"
+ # Keep the f3s fallback pages (served from localhost httpd when the cluster
+ # is down) out of browser caches, so nobody keeps seeing "cluster is down"
+ # after the cluster recovers.
+ #
+ # These rules used to be unscoped, so they rewrote EVERY response through
+ # this relay -- including everything the k3s cluster serves. That silently
+ # defeated upstream cache headers cluster-wide: cgit sets "expires 30d" on
+ # its CSS and logo, but browsers re-fetched them on every page view.
+ #
+ # relayd cannot filter a response by the backend table that produced it, so
+ # scope on the Server header instead: the local httpd is the only backend
+ # that answers "OpenBSD httpd" (the cluster answers nginx, the Pis
+ # bozohttpd). A "header set" cannot be combined with a header match in one
+ # rule, hence the tag: it is sticky for the connection, and a later
+ # response rule picks it up with "tagged".
+ match response header "Server" value "OpenBSD httpd" tag "HTTPD_FALLBACK"
+ match response tagged "HTTPD_FALLBACK" header set "Cache-Control" value "no-cache, no-store, must-revalidate"
+ match response tagged "HTTPD_FALLBACK" header set "Pragma" value "no-cache"
+ match response tagged "HTTPD_FALLBACK" header set "Expires" value "0"
}
relay "https4" {