All Products
Search
Document Center

:Configure an Apache caching policy

Last Updated:Jun 10, 2026

Configure mod_expires or mod_headers on your Apache origin server to set Cache-Control and Expires response headers, so that Alibaba Cloud CDN edge nodes and browsers cache your static content for the right TTL (Time to Live).

Choose a module

Apache provides two modules for controlling cache headers. Choose based on your requirements:

Module

Pros

Cons

When to use

mod_expires

Simple syntax; quickly sets Expires and Cache-Control: max-age per MIME type

Cannot set complex directives such as no-store or immutable

Simple scenarios that only need max-age

mod_headers

Full Cache-Control header control; supports all directives including immutable

Slightly more complex syntax

Production environments that need fine-grained cache policies

Prerequisites

Before you begin, verify that the required Apache modules are enabled.

Check which modules are loaded:

apachectl -M | grep -E "expires|headers"

The output should include expires_module and headers_module. If either is missing, enable it:

  • Debian / Ubuntu:

  sudo a2enmod headers expires
  sudo systemctl restart apache2
  • CentOS / RHEL / Alibaba Cloud Linux:

Modules are typically compiled in by default. If a module is missing, check /etc/httpd/conf.modules.d/ and make sure the corresponding LoadModule line is not commented out, then restart Apache:

  sudo systemctl restart httpd
Note

Place configuration in a dedicated file under /etc/httpd/conf.d/ (CentOS/RHEL) or /etc/apache2/conf-available/ (Debian/Ubuntu) — for example, cache.conf. Avoid .htaccess files: Apache parses .htaccess on every request, which adds unnecessary overhead and defeats the performance gains you are trying to achieve.

Configuration examples

All examples use <IfModule> guards so Apache starts without error even if the module is absent. Replace or extend ExpiresByType lines to match your content types.

Set cache TTL by content type

Use mod_expires for straightforward max-age rules, or mod_headers when you need full Cache-Control control.

mod_expires

<IfModule mod_expires.c>
    ExpiresActive On

    # Default TTL for all content types
    ExpiresDefault "access plus 1 day"

    # Images: cache for 1 month
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/png  "access plus 1 month"
    ExpiresByType image/gif  "access plus 1 month"
    ExpiresByType image/svg+xml "access plus 1 month"
    ExpiresByType image/webp "access plus 1 month"

    # CSS and JavaScript: cache for 1 week
    ExpiresByType text/css              "access plus 1 week"
    ExpiresByType application/javascript "access plus 1 week"

    # Fonts: cache for 1 year
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType font/woff  "access plus 1 year"

    # HTML and data: do not cache
    ExpiresByType text/html        "access plus 0 seconds"
    ExpiresByType application/json "access plus 0 seconds"
</IfModule>

mod_headers equivalent

<IfModule mod_headers.c>
    # Images
    <FilesMatch "\.(jpg|jpeg|png|gif|svg|webp)$">
        Header set Cache-Control "max-age=2592000, public"
    </FilesMatch>

    # CSS and JavaScript
    <FilesMatch "\.(css|js)$">
        Header set Cache-Control "max-age=604800, public"
    </FilesMatch>

    # Fonts
    <FilesMatch "\.(woff|woff2)$">
        Header set Cache-Control "max-age=31536000, public, immutable"
    </FilesMatch>

    # HTML and data: no caching
    <FilesMatch "\.(html|json)$">
        Header set Cache-Control "no-store"
    </FilesMatch>
</IfModule>

Set a global default TTL

When most of your content is static, set a global default and override specific types as needed.

mod_expires

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresDefault "access plus 1 week"
</IfModule>

mod_headers equivalent

<IfModule mod_headers.c>
    Header set Cache-Control "max-age=604800, public"
</IfModule>

Disable caching for dynamic content

Prevent CDN edge nodes and browsers from caching responses that change per request.

mod_expires

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/html        "access plus 0 seconds"
    ExpiresByType application/json "access plus 0 seconds"
</IfModule>

mod_headers equivalent

<IfModule mod_headers.c>
    <FilesMatch "\.(html|json|php)$">
        Header set Cache-Control "no-store"
    </FilesMatch>
</IfModule>

Directive reference

mod_expires directives

Directive

Description

ExpiresActive On

Enables Expires header generation for the server or location block

ExpiresDefault "<base> plus <duration>"

Sets the default TTL for all content types not matched by ExpiresByType

ExpiresByType <MIME-type> "<base> plus <duration>"

Sets the TTL for a specific MIME type

Time base options:

Value

Meaning

access / now

TTL is calculated from the time of the request

modification

TTL is calculated from the file's last-modified timestamp

Duration units: years, months, weeks, days, hours, minutes, seconds

Common duration values:

Expression

Equivalent

Use case

"access plus 1 year"

31,536,000 seconds

Versioned assets with cache-busting filenames

"access plus 1 month"

2,592,000 seconds

Images and other infrequently updated assets

"access plus 1 week"

604,800 seconds

CSS and JavaScript files

"access plus 0 seconds"

No caching

HTML pages and API responses

Verify the configuration

After reloading Apache, confirm the headers are present in the response:

curl -I https://<your-domain>/path/to/static-file.jpg

Look for Cache-Control or Expires in the output:

HTTP/1.1 200 OK
Cache-Control: max-age=2592000, public
Expires: Thu, 10 Jul 2026 04:00:00 GMT

Alternatively, open Chrome DevTools, go to the Network tab, reload the page, and click a static resource. The Response Headers panel shows the Cache-Control and Expires values set by your configuration.

Best practices

  • Prefer mod_headers for production. It supports the full range of Cache-Control directives (no-store, immutable, stale-while-revalidate) that mod_expires cannot generate.

  • Use long TTLs for versioned assets. If your build pipeline appends a hash to filenames (for example, app.a1b2c3.js), set TTLs of one year or more. The filename change acts as a cache-busting mechanism.

  • Set no-store for HTML and API responses. This ensures browsers and CDN edge nodes always fetch the latest page structure and data.

  • Reload, do not restart. After editing the configuration file, run apachectl graceful (or systemctl reload apache2 / systemctl reload httpd) to apply changes without dropping active connections.

  • Test with curl -I before going to production. Verify headers on each content type you configured, not just one.