Order and Stale Caches

Order of Operations, Caching and Stale Behavior

Virtual-host rewrites run before the directory walk, and <Location> merges after .htaccess (Contexts and Merge Order), so a correct file can still lose:

Competing rules and headers, plus a redirect with a bounded lifetimeApache config
# In the virtual host
<Location "/downloads/">
  Header set Cache-Control "no-store"
</Location>
RewriteEngine On
RewriteRule ^/old-blog/(.*)$ /blog/$1 [R=301,L]
# /var/www/example/.htaccess
Header set Cache-Control "max-age=3600"
RewriteEngine On
RewriteRule ^old-blog/(.*)$ /articles/$1 [R=301,L]
RewriteRule ^old-news/(.*)$ /news/$1 [R=301,L,E=MOVED:1]
Header always set Cache-Control "max-age=86400" env=MOVED
Output
/downloads/report.zip     200 no-store
/app.php                  200 max-age=3600
/old-blog/2026/post.html  301  http://localhost:8111/blog/2026/post.html
/old-news/x               301 max-age=86400 http://localhost:8111/news/x

<Location> won, and the virtual host answered /old-blog/ first. app.php sends Cache-Control: private, max-age=60, which Header set replaced under mod_php; under PHP-FPM (PHP-FPM via proxy_fcgi) both values went out, since proxied headers sit in the always table, until the line said Header always set. The last rule caps a redirect's life: RFC 9110 makes 301 and 308 cacheable by default, so a browser may reuse a wrong one without asking again. Test with R=302.

HSTS (HTTPS and HSTS) and cached assets (Cache-Control and ETags) outlast their rules the same way; curl 3,008 -I keeps no cache, so check with it first.