50 lines
2.1 KiB
Markdown
50 lines
2.1 KiB
Markdown
# Nginx Cache Pitfall — 30-Day Immutable Static Files
|
|
|
|
**The bug:** Nginx is configured to cache `.js`, `.css`, and other static files for **30 days** with `Cache-Control: public, immutable`. This means the browser NEVER re-fetches JS/CSS files after the first visit — all code changes are invisible until the cache expires or the user hard-refreshes.
|
|
|
|
**This is separate from the file-permission issue** (`nginx-permission-pitfall.md`). That causes 403 Forbidden. This causes stale files to be served from browser cache with 200 OK and zero indication of staleness.
|
|
|
|
## How it manifests
|
|
|
|
- Code changes are made to `.js` or `.css` files
|
|
- User reports that fixes "don't work" or "nothing happens"
|
|
- The browser serves the cached version from days/weeks ago
|
|
- A hard refresh (Ctrl+Shift+R) temporarily fixes it
|
|
- On the next visit, the cache is still valid — old version returns
|
|
|
|
## Root cause
|
|
|
|
The `immutable` directive tells the browser: "this resource will never change, don't even send a conditional request." Combined with `expires 30d`, the browser caches for 30 days with zero revalidation.
|
|
|
|
In `/etc/nginx/sites-available/shopproquote`:
|
|
```nginx
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
|
|
expires 30d;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
```
|
|
|
|
## Fix
|
|
|
|
```nginx
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
|
|
expires 1h;
|
|
add_header Cache-Control "public, must-revalidate";
|
|
}
|
|
```
|
|
|
|
Then: `sudo nginx -t && sudo nginx -s reload`
|
|
|
|
**`must-revalidate`** means the browser checks with the server after expiry (1 hour). **No `immutable`** means conditional requests are allowed.
|
|
|
|
## When to suspect this
|
|
|
|
- User says "I just changed X and it didn't take effect"
|
|
- Hard refresh fixes the issue temporarily
|
|
- The file on disk differs from what the browser loads (check with browser DevTools → Sources)
|
|
- Multiple pages are affected simultaneously (stale cache of shared modules like `pocketbase.js`)
|
|
|
|
## Prevention
|
|
|
|
After any code deployment, tell the user to hard-refresh (Ctrl+Shift+R). For production, consider cache-busting query strings (`?v=<hash>`) or shorter cache durations during active development.
|