Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
VGSOURCES
Get listed

ApachePATCH 2026.10.15

How to Set Up Expires Headers on Apache with mod_expires

By VGSources Team 10 min read

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

Set Apache’s mod_expires rules in the configuration scope that serves your files, turn generation on with ExpiresActive On, then define a fallback and MIME-type-specific lifetimes. A practical starting policy is a short lifetime for HTML and longer lifetimes for versioned CSS, JavaScript, and images.

The module writes both an HTTP Expires date and the corresponding max-age value in Cache-Control. The exact result depends on the response’s MIME type, the rule that matches it, and whether another component has already supplied cache headers.

As an Amazon Associate I earn from qualifying purchases.

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

What Apache Expires headers do

Browsers and intermediary caches use response freshness information to decide whether a stored response can be reused or must be requested again. Apache’s mod_expires module controls two related response fields:

  • Expires, an absolute date and time after which the response is considered stale.
  • Cache-Control: max-age, a relative lifetime in seconds.

The Apache Software Foundation describes the module as controlling “the setting of the Expires HTTP header and the max-age directive of the Cache-Control HTTP header in server responses.” The two values are generated from the same rule, so you normally configure them together rather than writing separate header expressions.

Expiration is not the same as invalidation. A cache can continue to hold an object after its freshness lifetime, but it should revalidate or fetch a fresh response before using it as current. Your policy therefore needs to reflect how often a resource changes and how quickly clients must see a change at the same URL.

Prerequisites and configuration scope

Enable mod_expires where the response is generated

The directives in this guide require Apache’s mod_expires module. The module can be configured in the main server configuration, a virtual-host configuration, a directory context, or an .htaccess file. Apache documents ExpiresActive as accepting those contexts, with the Indexes override class applying when it is used in .htaccess.

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.

Whether you can use an .htaccess file depends on the host’s permitted overrides. If the server rejects the directive or returns a configuration error, move the rule to the virtual host or directory configuration, or ask the administrator to permit the required override class. Do not assume that a rule in one virtual host affects another.

Turn generation on explicitly

ExpiresActive is Off by default. Put this directive in the scope that handles the files for which you want generated expiration metadata:

ExpiresActive On

Turning the module on does not by itself choose a useful lifetime for every response. You still need an ExpiresDefault rule, matching ExpiresByType rules, or both.

A minimal working configuration

This example establishes a one-hour fallback, asks clients to revalidate HTML immediately, and gives versioned static assets a month of freshness:

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

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

# Documents should be checked frequently
ExpiresByType text/html "access plus 0 seconds"

# Use longer lifetimes when deployment changes the asset URL
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/* "access plus 1 month"

# A specific type can override the image wildcard
ExpiresByType image/gif "access plus 1 week"

The quoted interval is an algorithm, not a literal header value. Apache calculates the expiration date for each response and emits the equivalent Cache-Control: max-age value. The fallback applies only when no more specific type rule matches.

Understanding ExpiresDefault

ExpiresDefault supplies the default expiration algorithm for responses handled in the current configuration scope. It is the safety net for content that does not match an ExpiresByType entry.

For example:

ExpiresActive On
ExpiresDefault "access plus 1 hour"

With this policy, a response that reaches this scope and has no matching type-specific rule receives an expiration one hour after the request access time. A default is useful because it makes the policy explicit, but it should be conservative: an unclassified response may be a page, an API response, or a file whose update pattern you have not reviewed.

A default does not override a matching ExpiresByType entry. Once Apache identifies a matching MIME type, that type-specific algorithm determines the result.

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.

Using ExpiresByType for MIME-specific lifetimes

ExpiresByType sets the Expires value and Cache-Control: max-age for responses with the selected MIME type. It works only when ExpiresActive On is enabled in the applicable scope.

The basic form is:

ExpiresByType MIME-TYPE "algorithm"

Examples:

ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/png "access plus 1 month"

Matching is based on the response’s Content-Type. If a file is being served with an unexpected type, the rule you intended may never be selected. Always inspect the actual response type while troubleshooting.

Wildcard major types

You can use a major-type wildcard such as image/* to cover image subtypes without listing each one:

ExpiresByType image/* "access plus 1 month"

A specific entry takes precedence over the wildcard. In the following example, GIF files receive one week while other image subtypes covered by the wildcard receive one month:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ExpiresByType image/* "access plus 1 month"
ExpiresByType image/gif "access plus 1 week"

If neither a specific entry nor a wildcard matches, Apache falls back to ExpiresDefault, if one is configured.

Choosing access time or modification time

Apache supports two bases for calculating an expiration date:

  • Access time: the interval is measured from the request time. Readable forms use access or now, such as "access plus 1 hour".
  • Modification time: the interval is measured from the file’s modification time. Readable forms use modification.

The numeric form makes the base explicit with a leading letter. For example:

ExpiresByType text/html M604800

Here, M means modification time and 604800 is the lifetime in seconds. The access-time equivalent uses A:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ExpiresByType text/html A604800

Use the readable form when maintainers need to understand the policy at a glance. Use the numeric form when a fixed number of seconds and an explicit base make the rule easier to audit. Whichever form you choose, keep the base consistent with your deployment and invalidation strategy.

Designing a cache policy that will not surprise users

HTML and other frequently changing documents

HTML often contains navigation, prices, account state, or links to newly deployed assets. A short lifetime or immediate revalidation reduces the time a client can use an old document. The example policy expresses that intent with:

ExpiresByType text/html "access plus 0 seconds"

That rule still generates expiration metadata; it does not mean Apache refuses to cache the response. The client receives a zero-second freshness lifetime and should check with the origin before reusing a stored copy.

Versioned static assets

CSS, JavaScript, and image files can safely receive longer lifetimes when every content change also changes the URL, for example by adding a version or content hash to the filename. A new URL is a cache miss, so clients retrieve the new bytes without waiting for the old URL to expire.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/* "access plus 1 month"

If your deployment overwrites the same URL, a long lifetime can leave users with stale assets until the cache expires. In that case, shorten the interval or adopt URL versioning before increasing it.

Fallback content

A fallback should be deliberately conservative because it covers every response not classified by a more specific rule. The one-hour example is only a starting policy; Apache’s documentation does not prescribe a universal duration. Select a value according to the resource’s update frequency and the consequences of stale content.

Precedence: which rule wins

Apache evaluates the configured rules in a predictable order:

  1. If a matching specific ExpiresByType entry exists, it supplies the algorithm.
  2. If no specific entry matches but a wildcard major-type entry applies, the wildcard supplies the algorithm.
  3. If no type-specific rule applies, ExpiresDefault supplies the algorithm.

For example:

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

A GIF response receives one week because the specific image/gif rule overrides image/*. A PNG response receives one month from the wildcard. A response such as text/plain receives one hour from the default, assuming no other matching rule exists.

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

Configuring the rules in .htaccess

When directory-level overrides are permitted, place the directives in the .htaccess file governing the requested files:

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"

The directory scope matters. A rule in a parent directory can apply to descendants, while a rule in another virtual host or unrelated directory does not. If a host has disabled the necessary overrides, Apache will not apply these directives from .htaccess; configure the virtual host or server instead.

Keep one authoritative policy where possible. Splitting overlapping rules among several directory files makes it harder to identify the effective default and the type-specific override.

How to verify the headers

Always test a real response after changing configuration. Use browser developer tools or an HTTP header inspection command and check all three items together:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • The response’s Content-Type.
  • The Expires date.
  • The Cache-Control header and its max-age value.

Testing different resource classes is more useful than testing only the home page. Inspect one HTML document, one stylesheet or script, and one image so that you can confirm both the fallback and the type-specific rules.

Compare the observed lifetime with the rule you intended. A one-month rule should produce a max-age measured in roughly that interval, while an HTML rule of 0 seconds should produce a zero-second maximum age. The exact absolute Expires timestamp changes with the request time, so the relative max-age is usually the easiest value to audit.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why Expires headers may be missing or unchanged

The module is not active in the serving scope

If ExpiresActive On is absent, misspelled, or placed in a configuration scope that does not handle the request, mod_expires will not generate the fields. Confirm the directive is present in the active server, virtual host, directory, or permitted .htaccess context.

No default or MIME rule matches

Turning the module on does not guarantee a header for every response. A response needs a matching ExpiresByType rule or an applicable ExpiresDefault. If you configured only rules for CSS and images, an unclassified response may have no generated expiration metadata.

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

The response has an unexpected Content-Type

ExpiresByType matches the MIME type Apache sends, not the filename extension you had in mind. Inspect Content-Type and add a rule for the actual type, or correct the type mapping if it is wrong.

Another component already supplied headers

When an Expires header has already been generated by the server, a CGI script, or a proxied origin response, mod_expires does not change or add an Expires or Cache-Control header. An apparently unchanged value can therefore be evidence that another layer owns the policy.

Check the response at the client-facing endpoint, not only at the origin. A reverse proxy or application may add, replace, or preserve headers after Apache’s module has run.

The edited file is not the file being served

Virtual hosts, directory inheritance, and proxies can make a different configuration or origin responsible for the response. Verify the hostname, path, and deployment environment you tested, then inspect the effective response headers again.

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

Common configuration mistakes

  • Forgetting activation: defining ExpiresDefault or ExpiresByType without ExpiresActive On leaves generation disabled.
  • Expecting a default to override a type rule: a matching ExpiresByType entry always takes precedence over ExpiresDefault.
  • Using a long lifetime on unversioned URLs: clients can retain old CSS, JavaScript, or images after a deployment that reused the same filename.
  • Reading only one header: verify both Expires and Cache-Control: max-age; they are generated together by the module.
  • Assuming every response is eligible: pre-existing headers from the server, CGI, or a proxied origin are not replaced by mod_expires.
  • Testing only the browser cache: use the actual response headers to distinguish an Apache rule from a locally stored result.

A repeatable setup procedure

  1. Choose the serving scope. Decide whether the policy belongs in the main server configuration, a virtual host, a directory, or an allowed .htaccess file.
  2. Confirm module availability. Ensure the Apache instance serving the request has mod_expires available and that the chosen scope accepts the directives.
  3. Enable generation. Add ExpiresActive On.
  4. Add a conservative fallback. Set ExpiresDefault for responses without a type-specific rule.
  5. Classify important MIME types. Add ExpiresByType entries for HTML, stylesheets, scripts, images, or other resource classes whose update patterns differ.
  6. Decide the time base. Use access/now for a lifetime measured from the request, or modification (or the numeric M form) when file modification time should be part of the calculation.
  7. Account for invalidation. Give long-lived assets stable freshness only when deployments change their URLs or otherwise provide a reliable way for clients to obtain new content.
  8. Reload through your normal Apache change process. A configuration edit must be accepted by the running server before it can affect responses.
  9. Inspect real responses. Check Content-Type, Expires, and Cache-Control: max-age for each resource class.
  10. Trace conflicts. If a value is missing or unchanged, look for an unmatched type, a disabled override, a different serving scope, or headers already supplied by Apache, CGI, or a proxy.

Reference policy patterns

Conservative mixed-content policy

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

This pattern limits the fallback and keeps common assets relatively fresh. It is appropriate when URLs are reused and deployments need changes to appear without a long waiting period.

Versioned-asset policy

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"
ExpiresByType image/gif "access plus 1 week"

This pattern gives versioned static files a longer lifetime while retaining immediate HTML revalidation. The GIF exception demonstrates how a specific rule can shorten the wildcard lifetime for one subtype.

What the directives do not decide

These directives do not determine whether a response is public or private, whether an application should be cached, or how a proxy handles every other cache-control directive. They calculate expiration metadata for responses that match the configured criteria. Existing headers and other server components can remain authoritative.

They also do not provide a universally correct duration. A one-hour fallback, one-week asset rule, or one-month asset rule is a policy choice illustrated by the syntax, not a requirement imposed by Apache. Review each resource’s change frequency, URL-versioning practice, and tolerance for stale data before selecting the interval.

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.

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.

ApacheExpires headersHTTP cachingmod_expiresWeb server configuration

Leave a reply

Your email address will not be published. Required fields are marked *

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

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.