The WordPress sites we host can run behind a full-page cache. Visitors who aren’t logged in get a stored copy of the page instead of waiting for WordPress to build it, which is a big part of why those pages load fast. Twice this summer that cache showed the wrong page to everyone, and the two cases had different causes.
A one-second error that stayed
In July a customer’s homepage started showing “503 Service Unavailable” to every visitor, even though the site itself was working again by then. For a moment it had been overloaded by a burst of background requests from a social plugin, WordPress answered one request with a 503, and our cache stored that error like any other page. Every anonymous visitor after that got the stored error until the cache entry expired.
The cache should never store an error, and in nginx that is one extra condition on proxy_no_cache that looks at the status code WordPress returned:
map $upstream_status $no_cache_5xx {
default 0;
~^5 1;
}
proxy_no_cache $no_cache $no_cache_5xx;
A redirect that pointed to itself
In August a different homepage sent visitors into an endless redirect loop and browsers showed “too many redirects”. It took us longer to find, because three separate things had lined up.
Our WordPress plugin marked responses as cacheable early in the request, before WordPress decided whether to redirect, so a redirect could be stored in the cache like a normal page. At some point WordPress had redirected the homepage to its own address, and that response ended up in the cache. On top of that the site was in maintenance mode, which answers with a 503, and we had told the cache to keep serving the last good copy whenever a site answered 503. Instead of the maintenance page, visitors kept getting the old stored redirect.
What we changed
After the second incident the cache stopped storing redirects altogether, so a 301 or 302 now always comes straight from WordPress. We also removed the rule that served an old copy on a 503, because maintenance mode and WordPress updates use 503 on purpose, and visitors should see that page. Finally, a request carrying a cookie we don’t recognize, such as the cookie a maintenance plugin sets to let the site owner in, can still be served from the cache but can no longer save a new copy into it. Common analytics and consent cookies are on an allow list, so normal visitors still get cached pages.
If you run a page cache in front of WordPress, check that it never stores 5xx responses or redirects.