Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Set Apache’s Expires and Cache-Control: max-age response headers with the mod_expires module. Turn the module on with ExpiresActive On, define a fallback with ExpiresDefault, and add MIME-type rules with ExpiresByType. Then inspect an actual response to confirm that Apache matched the intended Content-Type and duration.

A practical starting policy is to revalidate HTML immediately, give versioned CSS, JavaScript, and images a longer lifetime, and use a conservative fallback for everything else. The correct duration depends on how often each URL changes and whether deployments change asset filenames.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What Apache expire headers do

HTTP caching uses two related pieces of information. The Expires header contains an absolute HTTP date. The Cache-Control header can contain a relative max-age value in seconds. Apache’s mod_expires module calculates both values for matching responses. The Apache HTTP Server documentation describes the module as controlling the Expires header and the max-age directive in Cache-Control.

These headers tell a browser or an intermediary how long a response may be considered fresh. They do not change the file, compress it, or invalidate copies already stored by a cache. They also do not make a resource immutable by themselves: if the same URL serves new bytes after a deployment, a cache can continue using the old response until its freshness lifetime ends.

The module is disabled by default. A configuration containing only ExpiresActive On enables processing, but it does not necessarily create a header for every response. At least one matching expiration rule—an ExpiresDefault fallback or an ExpiresByType rule—must supply the calculation.

Check the configuration scope before editing

The three directives used for a normal policy are valid in server configuration, a virtual-host configuration, a directory context, and (when the host permits it) .htaccess:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • ExpiresActive switches generation on or off.
  • ExpiresDefault defines the fallback calculation.
  • ExpiresByType defines a calculation for a response MIME type.

Apache documents these directives with the Indexes override class for .htaccess. That means a hosting provider can allow or deny them independently of whether the file itself is readable. If Apache reports that a directive is not allowed, move the rule into the virtual-host or server configuration, or ask the administrator to permit the required override class. Do not assume that placing a file named .htaccess in the document root gives it permission to change every Apache setting.

The module must also be loaded. On a server managed by an administrator, the relevant module is normally enabled in the main Apache configuration and made available to the virtual host. If Apache returns an error such as an unknown ExpiresActive directive, the problem is module availability rather than the duration syntax. A shared host may not allow you to load modules yourself.

A safe baseline configuration

Place the following in the applicable virtual-host, directory, or permitted .htaccess context:

ExpiresActive On

# Conservative fallback for responses without a type-specific rule
ExpiresDefault "access plus 1 hour"

# Revalidate document markup frequently
ExpiresByType text/html "access plus 0 seconds"

# Longer lifetime for assets whose URLs change when their contents change
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/* "access plus 1 month"

# A more specific rule overrides the image wildcard
ExpiresByType image/gif "access plus 1 week"

The fallback prevents an unclassified response from silently receiving no expiration rule. The HTML rule makes the freshness lifetime zero, so clients must revalidate rather than treating the document as fresh for a period. The CSS, JavaScript, and image rules use a month in this example because those resources are assumed to be versioned at deployment. The GIF rule demonstrates that a specific MIME type can replace the broader image/* rule.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

These are policy examples, not universal values. Apache’s documentation does not prescribe one cache duration for every site. Choose each lifetime from the resource’s change frequency and your deployment’s invalidation method.

How the three directives interact

ExpiresActive

ExpiresActive On enables expiration processing in the current configuration scope. Its default is Off. Use ExpiresActive Off in a narrower scope when a broader server or virtual-host policy must be disabled for a directory.

ExpiresDefault

ExpiresDefault supplies the algorithm used when no matching ExpiresByType rule exists. It is a fallback, not a second header that is added alongside a type rule. A response matching a type-specific rule uses that rule instead.

ExpiresByType

ExpiresByType matches the response’s MIME type and sets both the calculated Expires value and the Cache-Control max-age. It works only while ExpiresActive is on. Matching is based on the MIME type Apache sends in Content-Type, not simply on the filename extension.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A wildcard major type such as image/* is considered before Apache falls back to ExpiresDefault. A more specific entry such as image/gif takes precedence over that wildcard. Keep the wildcard and specific entries together in the configuration so the intended policy is easy to audit.

Expiration syntax and the choice of base time

Apache accepts a readable expression or a numeric-seconds expression. The readable form is easier to review; the numeric form is useful when an exact number of seconds is required.

Form Meaning Example
access or now Calculate from the time the response is served. ExpiresByType text/html "access plus 0 seconds"
modification Calculate from the resource’s modification time. ExpiresByType text/css "modification plus 1 month"
Readable interval Use units such as years, months, weeks, days, or hours after the base. ExpiresDefault "access plus 1 hour"
A followed by seconds Use access time as the base and add the stated number of seconds. ExpiresByType text/html A0
M followed by seconds Use modification time as the base and add the stated number of seconds. ExpiresByType text/html M604800

The first character in the numeric form is significant: A means access time and M means modification time. For example, M604800 represents seven days after modification, while A604800 represents seven days after the response is accessed. The readable form can express the same policy without requiring you to convert the interval to seconds.

Access-based rules are predictable for generated responses because they do not require a filesystem modification timestamp. Modification-based rules can be useful for files whose mtime reflects publication, but they need a meaningful and correctly maintained mtime. If a deployment copies every file while preserving an old timestamp, a modification-based expiration date may not reflect the actual release. If a response is generated dynamically and has no useful file mtime, prefer an access-based rule.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Design a policy around URL invalidation

The central decision is not whether one month or one week sounds reasonable; it is how a client learns that a URL now serves different bytes.

Versioned static assets

If each release changes the CSS, JavaScript, or image URL—for example, by adding a content hash or release version—an old URL can safely remain cached after deployment because new pages point to a new URL. A longer lifetime reduces revalidation traffic. The example configuration uses one month for this case, but you can choose a longer value when your release process and storage strategy support it.

Stable asset URLs

If a file keeps the same URL while its contents change, a long freshness lifetime delays discovery of the update. Use a shorter access-based lifetime or change the URL when publishing. Do not advertise a long lifetime for an unversioned URL merely because the file is an image or stylesheet; the MIME type says what the resource is, not how often it changes.

HTML documents

HTML commonly contains the links to the newest asset URLs. A zero-second rule in the example asks clients to revalidate the document on each use while still allowing normal HTTP validation mechanisms. If your application intentionally serves rarely changing documents, a nonzero HTML lifetime may be appropriate, but it should be an explicit publishing decision.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fallback content

A fallback is useful for responses that do not have a dedicated type rule, but it should be conservative. A broad fallback can accidentally cache an endpoint, download, or administrative response for longer than intended. Add explicit rules for important types rather than relying on a wildcard that obscures the behavior of new responses.

Where to put the rules

Server or virtual-host configuration

In centrally managed Apache, place the directives inside the relevant virtual host or directory block. This is the clearest option because the administrator can load the module, validate the complete configuration, and apply one policy to many sites or paths. A server-level default can be narrowed in a virtual host or directory context.

Directory configuration

A directory block can apply a policy to one part of a site. This is useful when static assets and application responses are served from different paths. Make sure the directory’s effective Content-Type values are what your ExpiresByType rules expect.

.htaccess

Use .htaccess only when you cannot edit the main configuration and the host permits the directives. Put the file in the directory whose responses should inherit the policy. A rule in a parent directory can affect descendants unless a narrower configuration changes it. Keep comments that explain the invalidation assumption, especially when a long lifetime depends on versioned filenames.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Step-by-step: configure and verify in .htaccess

  1. Confirm that overrides are permitted. Ask the server administrator or inspect the site’s existing configuration process. If Apache rejects the directives as forbidden, no edit inside .htaccess will bypass that restriction.
  2. Confirm that mod_expires is available. An unknown-directive error indicates that the module is not loaded in the Apache instance serving the request.
  3. Create or edit the applicable file. Place the baseline policy in the correct document directory. Preserve any existing directives and avoid adding a second, conflicting policy in a child directory without a reason.
  4. Start with a fallback and a few explicit types. Enable processing, add ExpiresDefault, then add only the MIME rules you can justify. Expand the list after checking actual response types.
  5. Validate Apache’s configuration before reloading. Use the configuration-test procedure provided by your operating system or hosting control panel. Correct quotation, spelling, and context errors before applying the change.
  6. Request a real resource. Test an HTML page, a stylesheet, a script, and an image that are actually served by the target virtual host. A request to a different host or an upstream proxy can produce headers from another configuration.
  7. Inspect the response headers. Confirm the Content-Type, Expires, and Cache-Control values. Check that max-age corresponds to the intended interval and that the date is plausible for the chosen base.
  8. Test after a deployment change. If the policy relies on versioned URLs, verify that the page references the new names. If URLs remain stable, verify that the selected lifetime gives users an acceptable update window.

How to inspect the result

Browser developer tools show the response headers for an individual request. Open the browser’s Network panel, reload the page, select the resource, and inspect the response-header section. Look for all three values:

  • Content-Type tells you which ExpiresByType rule could match.
  • Expires is the absolute expiration date generated by Apache or another component.
  • Cache-Control should contain the expected max-age when mod_expires supplied the policy.

For a command-line check, request headers without downloading the body:

curl -sSI https://example.com/path/to/app.css

Use the final response after redirects when necessary, and test the hostname that maps to the virtual host you edited. Compare the response’s Content-Type with the exact type in your rule. For example, a rule for application/javascript will not match a response sent as text/javascript; add the type that Apache actually emits if that distinction is intentional.

A correct header does not prove that every cache will immediately discard an older object. Existing browser, proxy, or CDN entries retain their prior metadata until they revalidate or expire. Test a fresh request and account for any intermediary that may add, replace, or preserve headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why the headers are missing or unchanged

ExpiresActive is missing or disabled

Without ExpiresActive On, the module does not generate the policy. A broader configuration may also have turned it off in the directory serving the resource. Check the effective scope rather than only the file you edited.

No rule matches

Turning the module on is not enough if neither ExpiresDefault nor an applicable ExpiresByType rule exists. Add a conservative fallback, or add a rule for the response’s actual MIME type.

The MIME type is different from the filename assumption

ExpiresByType uses the response MIME type. A file named script.js can fail to match a rule if Apache sends an unexpected Content-Type. Inspect the header and correct either the MIME mapping or the expiration rule.

Another component already generated the header

If the server, a CGI script, or a proxied origin response has already generated an Expires header, mod_expires does not replace it or add a competing Expires or Cache-Control value. Find the component that owns the existing header and change the policy there, or remove the conflicting generation so Apache can apply the intended rule.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The request is reaching a different configuration

DNS, redirects, a reverse proxy, or a second virtual host can send the request somewhere other than the directory you changed. Inspect the final URL and the server-specific response headers. Verify that the test hostname, protocol, and path select the expected virtual host.

The configuration was not reloaded or contains an error

Main and virtual-host configuration changes normally require a successful configuration test and reload. A syntax error can leave the old configuration active or prevent the service from reloading. With .htaccess, Apache reads the file per request, but a malformed directive still causes an error response; check the Apache error log.

A cache is showing an older response

Use a fresh request and compare headers from the origin and any intermediary. A browser’s memory or disk cache can hide a server-side change. A proxy can also retain an older Expires or Cache-Control header. The fix is to identify which hop supplied the observed response, not to keep adding duplicate expiration directives.

Common policy mistakes

  • Using a long fallback for everything. A fallback also applies to newly introduced response types, including endpoints that should be revalidated quickly. Keep it conservative and add intentional type rules.
  • Assuming an extension controls matching. Apache matches Content-Type, so verify the MIME header rather than relying on .css, .js, or .jpg in the URL.
  • Choosing modification time for generated content. If there is no reliable file modification time, an M rule may not represent publication time. Use an access-based expression or set headers in the application that owns the response.
  • Long-caching stable URLs that change in place. A cache cannot know that the bytes changed until the freshness lifetime ends or the URL changes. Add versioning to the URL or shorten the lifetime.
  • Adding overlapping wildcard rules without checking specificity. A specific type such as image/gif overrides image/*. Document the exception so a later editor does not mistake it for a duplicate.
  • Expecting ExpiresActive On to override application headers. Existing expiration generated by a CGI script or proxied origin remains authoritative to the extent that mod_expires declines to replace it.

Example policies for different release models

Versioned frontend assets

ExpiresActive On
ExpiresDefault "access plus 1 hour"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/* "access plus 1 month"

Use this shape when every asset change produces a new URL. The HTML is checked frequently, while old asset URLs can remain fresh without preventing the page from selecting the newest versions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Unversioned files that must update promptly

ExpiresActive On
ExpiresDefault "access plus 0 seconds"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/css "access plus 5 minutes"
ExpiresByType application/javascript "access plus 5 minutes"
ExpiresByType image/* "access plus 5 minutes"

This policy favors timely revalidation when URLs stay unchanged. The five-minute values are an example of a short operational window, not an Apache requirement.

Different treatment for one image type

ExpiresActive On
ExpiresDefault "access plus 1 hour"
ExpiresByType image/* "access plus 1 month"
ExpiresByType image/gif "access plus 1 week"

The wildcard covers image responses that have no more specific rule. The GIF entry narrows the lifetime for that exact MIME type.

Operational checklist

  • Is mod_expires loaded in the Apache instance serving this host?
  • Is ExpiresActive On effective in the directory or virtual host?
  • Does a fallback or matching MIME rule exist?
  • Does the response’s Content-Type exactly match the intended rule?
  • Is the base time—access or modification—appropriate for this resource?
  • Does the lifetime match the way deployments invalidate URLs?
  • Is another server, script, proxy, or origin already setting Expires or Cache-Control?
  • Did you inspect a response from the final hostname and path after applying the configuration?

When those checks pass, Apache will calculate the expiration date and corresponding max-age for each response that matches the policy. The durable solution is not one universal number; it is a documented relationship between resource type, change frequency, and URL versioning.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.