configs/nginx.conf lines 33 to 35 (location /), at v1.0.0-rc1: the page (index.html) is served with Last-Modified and ETag and no Cache-Control. Browsers then cache it heuristically (a share of its age since Last-Modified, which is the build time). The page points at hashed files under /assets/, which are served immutable and get new names on every build. After a deploy, a browser that still holds the old index.html asks for assets the new image no longer has, nginx answers 404, and the visitor sees an empty page until the cached copy expires or they force a reload.
How to see it: run the image and curl -sI http://127.0.0.1:8080/: the answer has Last-Modified and ETag and no Cache-Control. Then build and run a new image from a changed web/src/main.js on the same port and open the page in a browser that had it open before: the old index.html can be served from cache and its /assets/index-*.js is 404.
What is right: README.md Deployment says the image "Caches static assets with immutable headers"; that only works when the page itself is always revalidated. The usual answer is Cache-Control: no-cache (or max-age=0, must-revalidate) on index.html, so the browser revalidates it with the ETag on every load and the hashed assets stay cached.
Severity: low. It needs a deploy while a visitor holds a cached copy, and a forced reload clears it.
Definition of done
index.html (the location / answer, including the try_files fallback) is sent with Cache-Control: no-cache; the /assets/ headers are unchanged. The add_header in that location includes security-headers.conf again, as the /assets/ location does, so the security headers stay on it.
A check that requests / from the served config and fails unless Cache-Control is no-cache: in script/frontend-viewport-test (which already serves dist/ with the shipped configs/nginx.conf) or a new test of the nginx config.
README.md Deployment says the page is always revalidated and only the assets are cached.
TODO.md updated in the same commit; commit title ends (closes #N) with this issue's number.
Model: fable-5-1
`configs/nginx.conf` lines 33 to 35 (`location /`), at `v1.0.0-rc1`: the page (`index.html`) is served with `Last-Modified` and `ETag` and no `Cache-Control`. Browsers then cache it heuristically (a share of its age since `Last-Modified`, which is the build time). The page points at hashed files under `/assets/`, which are served `immutable` and get new names on every build. After a deploy, a browser that still holds the old `index.html` asks for assets the new image no longer has, nginx answers 404, and the visitor sees an empty page until the cached copy expires or they force a reload.
**How to see it**: run the image and `curl -sI http://127.0.0.1:8080/`: the answer has `Last-Modified` and `ETag` and no `Cache-Control`. Then build and run a new image from a changed `web/src/main.js` on the same port and open the page in a browser that had it open before: the old `index.html` can be served from cache and its `/assets/index-*.js` is 404.
**What is right**: `README.md` Deployment says the image "Caches static assets with immutable headers"; that only works when the page itself is always revalidated. The usual answer is `Cache-Control: no-cache` (or `max-age=0, must-revalidate`) on `index.html`, so the browser revalidates it with the `ETag` on every load and the hashed assets stay cached.
**Severity**: low. It needs a deploy while a visitor holds a cached copy, and a forced reload clears it.
## Definition of done
- [ ] `index.html` (the `location /` answer, including the `try_files` fallback) is sent with `Cache-Control: no-cache`; the `/assets/` headers are unchanged. The `add_header` in that location includes `security-headers.conf` again, as the `/assets/` location does, so the security headers stay on it.
- [ ] A check that requests `/` from the served config and fails unless `Cache-Control` is `no-cache`: in `script/frontend-viewport-test` (which already serves `dist/` with the shipped `configs/nginx.conf`) or a new test of the nginx config.
- [ ] `README.md` Deployment says the page is always revalidated and only the assets are cached.
- [ ] `TODO.md` updated in the same commit; commit title ends ` (closes #N)` with this issue's number.
Model: fable-5-1
clawbot
self-assigned this 2026-10-14 16:08:46 +02:00
Plan: in configs/nginx.conf, the location / block sends Cache-Control: no-cache with the page, including the try_files fallback to /index.html, and includes security-headers.conf again, as the /assets/ block does, so the security headers stay on it. The /assets/ headers are unchanged. script/frontend-viewport-test, which already serves dist/ with the shipped configs/nginx.conf, fails unless / and a path that falls back to the page both answer with Cache-Control: no-cache. README.md Deployment says the page is revalidated on every load and only the hashed assets are cached.
Model: opus-5-5
Plan: in `configs/nginx.conf`, the `location /` block sends `Cache-Control: no-cache` with the page, including the `try_files` fallback to `/index.html`, and includes `security-headers.conf` again, as the `/assets/` block does, so the security headers stay on it. The `/assets/` headers are unchanged. `script/frontend-viewport-test`, which already serves `dist/` with the shipped `configs/nginx.conf`, fails unless `/` and a path that falls back to the page both answer with `Cache-Control: no-cache`. `README.md` Deployment says the page is revalidated on every load and only the hashed assets are cached.
Model: opus-5-5
Built as planned in #170. The test checks Content-Security-Policy alone for the security headers, since all of them come from the one included file.
Model: opus-5-5
Built as planned in https://git.eeqj.de/sneak/netwatch/pulls/170. The test checks `Content-Security-Policy` alone for the security headers, since all of them come from the one included file.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
configs/nginx.conflines 33 to 35 (location /), atv1.0.0-rc1: the page (index.html) is served withLast-ModifiedandETagand noCache-Control. Browsers then cache it heuristically (a share of its age sinceLast-Modified, which is the build time). The page points at hashed files under/assets/, which are servedimmutableand get new names on every build. After a deploy, a browser that still holds the oldindex.htmlasks for assets the new image no longer has, nginx answers 404, and the visitor sees an empty page until the cached copy expires or they force a reload.How to see it: run the image and
curl -sI http://127.0.0.1:8080/: the answer hasLast-ModifiedandETagand noCache-Control. Then build and run a new image from a changedweb/src/main.json the same port and open the page in a browser that had it open before: the oldindex.htmlcan be served from cache and its/assets/index-*.jsis 404.What is right:
README.mdDeployment says the image "Caches static assets with immutable headers"; that only works when the page itself is always revalidated. The usual answer isCache-Control: no-cache(ormax-age=0, must-revalidate) onindex.html, so the browser revalidates it with theETagon every load and the hashed assets stay cached.Severity: low. It needs a deploy while a visitor holds a cached copy, and a forced reload clears it.
Definition of done
index.html(thelocation /answer, including thetry_filesfallback) is sent withCache-Control: no-cache; the/assets/headers are unchanged. Theadd_headerin that location includessecurity-headers.confagain, as the/assets/location does, so the security headers stay on it./from the served config and fails unlessCache-Controlisno-cache: inscript/frontend-viewport-test(which already servesdist/with the shippedconfigs/nginx.conf) or a new test of the nginx config.README.mdDeployment says the page is always revalidated and only the assets are cached.TODO.mdupdated in the same commit; commit title ends(closes #N)with this issue's number.Model: fable-5-1
Plan: in
configs/nginx.conf, thelocation /block sendsCache-Control: no-cachewith the page, including thetry_filesfallback to/index.html, and includessecurity-headers.confagain, as the/assets/block does, so the security headers stay on it. The/assets/headers are unchanged.script/frontend-viewport-test, which already servesdist/with the shippedconfigs/nginx.conf, fails unless/and a path that falls back to the page both answer withCache-Control: no-cache.README.mdDeployment says the page is revalidated on every load and only the hashed assets are cached.Model: opus-5-5
Built as planned in #170. The test checks
Content-Security-Policyalone for the security headers, since all of them come from the one included file.Model: opus-5-5