How to Implement Apache Redirects with Custom Cache-Control Headers


2 views

When implementing redirects in Apache, we often need to control caching behavior. The standard approach using RedirectMatch from mod_alias unfortunately strips away any custom headers we try to set. Here's what actually happens when you combine them:


    ServerName example.com
    Header set Cache-Control "no-store, no-cache, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "0"
    RedirectMatch ^.*$ https://new.example.com/

The issue stems from how Apache processes these directives. The RedirectMatch creates an immediate response, bypassing later header modifications. You can verify this by checking the response:

curl -I http://example.com
HTTP/1.1 302 Found
Location: https://new.example.com/
# Missing Cache-Control headers here

Here are three reliable approaches to implement redirects with proper cache control:

1. Using mod_rewrite


    ServerName example.com
    Header always set Cache-Control "no-store, no-cache, must-revalidate"
    Header always set Pragma "no-cache"
    Header always set Expires "0"
    
    RewriteEngine On
    RewriteRule ^.*$ https://new.example.com/ [R=302,L]

2. Using Location with Header


    ServerName example.com
    Header always set Cache-Control "no-store, no-cache, must-revalidate"
    Header always set Pragma "no-cache"
    Header always set Expires "0"
    
    
        Redirect 302 / https://new.example.com/
    

3. Custom ErrorDocument (For Specific Status Codes)


    ServerName example.com
    Header always set Cache-Control "no-store, no-cache, must-revalidate"
    
    ErrorDocument 302 https://new.example.com/
    RewriteEngine On
    RewriteRule ^.*$ - [R=302,L]

  • Use Header always set instead of just Header set to ensure headers are applied to all responses
  • For permanent redirects (301), browser caching behavior differs from temporary (302) redirects
  • Test with curl -v to verify both the redirect and headers are present
  • The Vary header might need adjustment depending on your caching requirements

While implementing these solutions, remember:

# For better performance with many redirects:
Header always unset ETag
FileETag None
Header always merge Cache-Control "public"

The optimal solution depends on your specific Apache version and modules enabled. Always test in your environment.


When configuring Apache to handle redirects while setting cache-control headers, many developers encounter an unexpected behavior: the redirect works, but the cache headers disappear from the response.

<VirtualHost *:80>
    ServerName __default__
    Header set Cache-Control "no-store, no-cache, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Thu, 01 Dec 1994 16:00:00 GMT"
    RedirectMatch ^.*$ http://portal.example.com/
</VirtualHost>

The core issue stems from how Apache processes directives from different modules. mod_alias (handling RedirectMatch) executes late in the request cycle, often overriding headers set earlier by mod_headers.

For full control over both redirects and headers, replace RedirectMatch with mod_rewrite and explicit Header directives:

<VirtualHost *:80>
    ServerName __default__
    
    # Force no-caching
    Header always set Cache-Control "no-store, no-cache, must-revalidate"
    Header always set Pragma "no-cache"
    Header always set Expires "Thu, 01 Dec 1994 16:00:00 GMT"
    
    # Handle redirect via mod_rewrite
    RewriteEngine On
    RewriteRule ^.*$ http://portal.example.com/ [R=302,L]
</VirtualHost>
  • always keyword ensures headers are set even for redirect responses
  • mod_rewrite executes earlier in the request processing pipeline
  • Explicit 302 status code maintains the temporary redirect behavior

Test with curl to confirm both redirect and headers are present:

curl -I http://your-server.example.com
HTTP/1.1 302 Found
Date: Mon, 01 Jan 2024 00:00:00 GMT
Server: Apache
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Location: http://portal.example.com/

For even more control over the response body during redirects:

<VirtualHost *:80>
    ErrorDocument 302 "<html><body>Redirecting...</body></html>"
    Header always set Cache-Control "no-store, no-cache, must-revalidate"
    RewriteEngine On
    RewriteRule ^.*$ - [R=302,L]
</VirtualHost>