I'm setting up Apache caching on CentOS using mod_cache and mod_cache_disk with the configuration at the bottom of this post but the page is not cached. I included CacheDetailHeader on to get some debug info.

When I hit the page, the HTTP response shows X-Cache-Detail: "Expires header already expired; not cacheable" and the Expires header is set to some date in 1981, despite the date being correct.

Date: Mon, 19 Aug 2019 23:39:03 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT

The test is being done using Chrome Incognito browser on a public WordPress page.

The full configuration. CacheRoot exists and is writable for the Apache user.

# The following line could be required or not depending on your Apache installation
LoadModule cache_module modules/mod_cache.so

<IfModule mod_cache.c>
    CacheQuickHandler off
    CacheDetailHeader on 

    CacheIgnoreNoLastMod On
    CacheDefaultExpire 7200

    CacheIgnoreCacheControl On
    CacheLastModifiedFactor 0.5
    CacheIgnoreHeaders Set-Cookie Cookie
    CacheHeader on
    CacheLock on
    CacheDisable /wp-admin
    CacheDisable /wp-login.php
    CacheDisable /wp-cron.php

    SetOutputFilter CACHE
    AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/rss+xml text/xml image/svg+xml

    # The following line could be required or not depending on your Apache installation
    LoadModule cache_disk_module modules/mod_cache_disk.so

    <IfModule mod_cache_disk.c>
        CacheRoot /var/cache/apache2/mod_cache_disk
        CacheEnable disk /
        CacheDirLevels 2
        CacheDirLength 1
        CacheMaxFileSize 2000000

FYI - The reason I'm using mod_cache with WP is that this project is based on the Bedrock framework which doesn't seem to work well with WP Super Cache and other plugins. They recommend using Memcached, Nginx or Varnish, none of which I have access to install.


  • WP_CACHE is set to true
  • Added CacheMaxExpire 86400 to config and the X-Cache-Detail error changed to s-maxage or max-age zero and no Last-Modified or Etag and the Cache-Control header is now Cache-Control: private, proxy-revalidate, s-maxage=0
  • Added mod_expires:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access 1 month"
  • Good God, they recommended Batcache and to stay away from W3TC and Super Cache? That makes me think they're doing things they really shouldn't be doing, and makes me suspicious of the whole framework, at least with respect to caching. – Michael Hampton Aug 20 '19 at 17:36
  • It's a good framework in that it moves the site config out of the web application which improves security but to do that the folder hierarchy has to be changed and it's this that causes problems with the caching plugins. I haven't found one that works with Bedrock yet - I did try hacking the code of WP Super Cache but the pre-load still doesn't work. – Daniel Aug 20 '19 at 17:49

PHP is configured to send cache disabling headers, including the Expires: header you show, on pages which start a session. This date corresponds to the birthday of the PHP developer who implemented this feature.

You can configure this behavior by setting session.cache_limiter in php.ini.

If you are running WordPress there should not be a need to change this from its default of nocache, as pages with this header correspond to pages being sent to users logging in or already logged in and thus shouldn't be cached by Apache anyway. You might change it to private or private_no_expire to allow logged in users' browsers to cache the pages, though.

To test your cache, use an incognito window and hit your WordPress site while logged out.

  • Huh, interesting, thanks! Yes this is PHP and WP, however this is not a page with a session - I've been running all tests using Chrome Incognito while logged out. Updated post. – Daniel Aug 20 '19 at 16:46
  • 1
    @Daniel Check your plugins. Some badly written WP plugins try to start a session on every page load, whether a user is logged in or not. – Michael Hampton Aug 20 '19 at 17:14
  • Thanks, will investigate. I added CacheMaxExpire 86400 and the error message changed to s-maxage or max-age zero and no Last-Modified or Etag – Daniel Aug 20 '19 at 17:19
  • I've tried all the variants of session.cache_limiter in every php ini but the headers are always returned as Expires header already expired; not cacheable – Daniel Aug 20 '19 at 18:49
  • @Daniel I still suspect your third party code, such as Bedrock. Try this with a plain WordPress installation. – Michael Hampton Aug 20 '19 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.