Response caching in Apache reduces repeated work for public assets and other reusable responses by serving them from a local cache instead of reading or generating them for every request. That lowers response time for clients and reduces avoidable load on the web server and the application behind it.

Apache HTTP caching is provided by mod_cache plus a storage backend such as mod_cache_socache or mod_cache_disk. The flow below uses mod_cache_socache on Ubuntu and Debian to cache small public files while freshness is still controlled by normal HTTP headers such as Cache-Control and Expires.

Cache scope is the real safety boundary. Keep personalized or authenticated URLs out of CacheEnable rules, and leave CacheQuickHandler off when cached content must still pass through the normal authorization flow. Shared-object caching also has entry size limits, so large files may need mod_cache_disk instead.

Steps to enable response caching in Apache:

  1. Enable the Apache modules required for HTTP caching, shared-object storage, and freshness headers.
    $ sudo a2enmod cache cache_socache socache_shmcb expires headers
    Enabling module cache.
    Considering dependency cache for cache_socache:
    Module cache already enabled
    Enabling module cache_socache.
    Enabling module socache_shmcb.
    Enabling module expires.
    Enabling module headers.
    To activate the new configuration, you need to run:
      service apache2 restart

    These helper commands are part of the apache2 package layout on Ubuntu and Debian.

  2. Create a dedicated cache configuration file so the caching rules stay separate from the main server config.
    $ sudo vi /etc/apache2/conf-available/cache-socache.conf

    Use a virtual host file instead when only one site should be cached.

  3. Add the caching directives for the public asset paths that should be reused.
    CacheQuickHandler off
    CacheLock on
    CacheLockPath "/tmp/mod_cache-lock"
    CacheLockMaxAge 5
    CacheHeader on
     
    CacheSocache shmcb:/var/cache/apache2/mod_cache_socache(20971520)
    CacheSocacheMaxSize 512000
    CacheSocacheMaxTime 86400
     
    <LocationMatch "\.(css|js|mjs|png|jpe?g|gif|svg|webp|ico|woff2?)$">
        CacheEnable socache
    </LocationMatch>
     
    <IfModule mod_expires.c>
        <FilesMatch "\.(css|js|mjs|png|jpe?g|gif|svg|webp|ico|woff2?)$">
            ExpiresActive On
            ExpiresDefault "access plus 1 month"
        </FilesMatch>
    </IfModule>

    Keep CacheEnable rules limited to public content. Cached personalized pages, authenticated responses, or one-time downloads can be served to the wrong client or after the wrong login state.

    The parent path for CacheLockPath must be writable by the Apache service account so lock files can be created during cache refresh.

    Directive Use
    CacheQuickHandler Keeps Apache in the normal request path before serving cached content, which is safer when authorization rules still matter.
    CacheLock Reduces duplicate backend work while an entry is first created or refreshed.
    CacheHeader Adds X-Cache to the response so cache hits and misses are visible during validation.
    CacheSocache Selects the shared-object cache backend and its storage size.
    CacheSocacheMaxSize Sets the largest combined headers-and-body entry that socache will store.
    CacheEnable Tells Apache which URL patterns should be cached with the socache backend.
  4. Enable the new configuration snippet.
    $ sudo a2enconf cache-socache

    The command creates a symlink under /etc/apache2/conf-enabled/ so Apache loads the file on the next restart.

  5. Test the configuration before restarting Apache.
    $ sudo apache2ctl configtest
    Syntax OK

    A warning about an unset global ServerName does not block the cache configuration from loading.

  6. Restart Apache so the newly enabled modules and configuration take effect.
    $ sudo systemctl restart apache2

    In non-systemd environments such as some containers, use sudo apachectl -k restart instead.

  7. Request a cacheable asset once to populate the cache.
    $ curl -sI http://127.0.0.1/assets/site.css
    HTTP/1.1 200 OK
    Date: Wed, 08 Apr 2026 04:07:26 GMT
    Server: Apache/2.4.58 (Ubuntu)
    Last-Modified: Wed, 08 Apr 2026 04:07:25 GMT
    ETag: "16-64eeb0999a26b"
    Accept-Ranges: bytes
    Content-Length: 22
    Cache-Control: max-age=2592000
    Expires: Fri, 08 May 2026 04:07:26 GMT
    X-Cache: MISS from web.example.net
    Content-Type: text/css

    Use a public CSS, JavaScript, font, or image URL that matches the LocationMatch pattern. The first request is normally a MISS because the cache starts empty.

  8. Request the same asset again and confirm that Apache serves it from cache.
    $ curl -sI http://127.0.0.1/assets/site.css
    HTTP/1.1 200 OK
    Date: Wed, 08 Apr 2026 04:07:26 GMT
    Server: Apache/2.4.58 (Ubuntu)
    Last-Modified: Wed, 08 Apr 2026 04:07:25 GMT
    ETag: "16-64eeb0999a26b"
    Accept-Ranges: bytes
    Content-Length: 22
    Cache-Control: max-age=2592000
    Expires: Fri, 08 May 2026 04:07:26 GMT
    Age: 0
    X-Cache: HIT from web.example.net
    Content-Type: text/css

    If X-Cache stays at MISS, confirm the response is not marked private or no-store and that the object fits within CacheSocacheMaxSize.

    After validation, change CacheHeader to off if X-Cache should not be exposed in production responses.