How to Properly Configure Favicon Expires Headers in Apache .htaccess for Optimal Caching


2 views

When implementing browser caching through Apache's mod_expires, many developers encounter unexpected behavior with favicon.ico files. While other static assets like CSS, JS, and images respond correctly to Expires headers, the favicon often remains stubbornly uncached.

The issue typically stems from one of these scenarios:

  • The favicon isn't served from the expected location (root directory)
  • Incorrect MIME type configuration
  • Browser-specific handling of favicon requests
  • Conflicting directives in .htaccess

Here's a complete solution that handles all favicon scenarios:

# Enable mod_expires
ExpiresActive On

# Standard favicon.ico
ExpiresByType image/x-icon "access plus 1 year"

# For newer browsers using PNG favicons
ExpiresByType image/png "access plus 1 year"

# Legacy GIF favicons (though not recommended)
ExpiresByType image/gif "access plus 1 year"

# Additional directives to ensure proper serving
<Files "favicon.ico">
    Header set Cache-Control "public"
    Header unset ETag
    FileETag None
</Files>

After implementing these changes:

  1. Clear your browser cache completely
  2. Restart Apache: sudo service apache2 restart
  3. Use browser dev tools to inspect the favicon response headers
  4. Verify with tools like YSlow or WebPageTest

For sites using Content Delivery Networks (CDNs), ensure your CDN configuration respects these headers. Some CDNs may require additional configuration for favicon caching.

If you're using multiple favicon formats for different devices (ICO, PNG, SVG), make sure each format has corresponding Expires directives:

# For SVG favicons
ExpiresByType image/svg+xml "access plus 1 year"

# For Apple touch icons
ExpiresByType image/png "access plus 1 year"

While implementing browser caching via mod_expires in Apache, many developers encounter a peculiar issue with favicon.ico files not respecting the configured expiration headers. Even though other static assets like images and CSS files cache properly, the favicon often refuses to comply with caching directives.

The problem typically stems from:

  • Multiple possible favicon locations (/favicon.ico, /images/favicon.ico)
  • Browser-specific handling of favicon requests
  • Case sensitivity in .htaccess pattern matching
  • Improper MIME type configuration

Here's the complete solution that works in most Apache environments:

<IfModule mod_expires.c>
    ExpiresActive On
    
    # Standard favicon.ico
    ExpiresByType image/x-icon "access plus 1 year"
    
    # For older IE versions
    ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
    
    # GIF favicons
    ExpiresByType image/gif "access plus 1 year"
    
    # PNG favicons
    ExpiresByType image/png "access plus 1 year"
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "favicon\.(ico|gif|png)$">
        Header set Cache-Control "max-age=31536000, public"
    </FilesMatch>
</IfModule>

After implementing these rules:

  1. Clear your browser cache completely
  2. Use Chrome DevTools (Network tab) to verify the response headers
  3. Check for proper Cache-Control and Expires headers
  4. Confirm the correct MIME type is being served

If issues persist, consider these additional steps:

# Force MIME type for .ico files
AddType image/x-icon .ico

# Handle case-sensitive requests
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} favicon\.ico [NC]
RewriteRule ^(.*)$ /favicon.ico [L]

Remember that some browsers (particularly mobile browsers) may still behave differently with favicon caching. Always test across multiple browsers.