.htaccess Tweaks to Improve Site Speed

Add the following to the top of your .htaccess for some nice performance boosts, and meet a lot of the Yahoo Best Performance Practices:

# Enable Gzip on textual files.
# Best and easiest form of optimisation - sacrifice CPU cycles to encode for much smaller data transfer - well worth it.
# Don't gzip images - they are already compressed.
# For even more benefit, write alphabetical CSS key:value pairs and HTML attributes! (Google saved about 1.5% data transfer by doing this)

    SetOutputFilter DEFLATE
    # Deactivate compression for buggy browsers
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

# BEGIN Expire headers
# Makes cached files stay cached for longer (304 Not modified) = fewer 200 responses.
# Aim for at least 1 month for images, ideally a year (not longer - that'll break RFC specs)

  ExpiresActive On
  ExpiresDefault "access plus 1 seconds"
  ExpiresByType image/x-icon "access plus 1 year"
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/gif "access plus 1 year"
  ExpiresByType application/x-shockwave-flash "access plus 1 year"
  ExpiresByType text/css "access plus 604800 seconds"
  ExpiresByType text/javascript "access plus 1 month"
  ExpiresByType application/x-javascript "access plus 1 month"
  ExpiresByType text/html "access plus 600 seconds"
  ExpiresByType application/xhtml+xml "access plus 600 seconds"

# END Expire headers

# BEGIN Cache-Control Headers
# Only using the private/public values here - not max-age (Expires headers cover the same thing, and are more widely supported)

    Header set Cache-Control "public"
    Header set Cache-Control "private"
    Header set Cache-Control "private, must-revalidate"

# END Cache-Control Headers

# BEGIN Turn ETags Off
# Inherently misconfigured, especially for server clusters

  Header unset ETag

FileETag None
# END Turn ETags Off

# BEGIN Remove Last-Modified Header
# We're using Expires header to check for freshness, so save bytes by not returning this header.

  Header unset Last-Modified

# END Remove Last-Modified Header

Improving WordPress Default Code

The above code works for all sites. The next suggestion comes from the Canonical SEO site, and applies if you’re running WordPress as a single site. Swap out the default code added by WordPress in .htaccess:

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

And replace it with:

# BEGIN WordPress
RewriteEngine on
# Unless you have set a different RewriteBase preceding this
# point, you may delete or comment-out the following
# RewriteBase directive:
RewriteBase /
# if this request is for "/" or has already been rewritten to WP
RewriteCond $1 ^(index\.php)?$ [OR]
# or if request is for image, css, or js file
RewriteCond $1 \.(gif|jpg|css|js|ico)$ [NC,OR]
# or if URL resolves to existing file
RewriteCond %{REQUEST_FILENAME} -f [OR]
# or if URL resolves to existing directory
RewriteCond %{REQUEST_FILENAME} -d
# then skip the rewrite to WP
RewriteRule ^(.*)$ - [S=1]
# else rewrite the request to WP
RewriteRule . /index.php [L]
# END wordpress
About Gary Jones

Gary Jones is a UK-based WordPress Engineer, code consultant, and father of extremely premature twins. Driven by a passion for excellence, he creates elegant WordPress plugins and theme solutions for clients, and provides services, including code audits, for other designers and developers.

Gary is a key contributor to the Genesis Framework and has contributed to all except one major branch of WordPress Core since 3.3. He has contributed to many open source projects in the community, and is a co-host on the UK Genesis podcast.

A former teacher in schools and prisons, Gary's goal is to educate WordPress professionals on how they can improve their code. His motto is knowledge is power.


  1. Thanks this has saved me a bunch of work and now my wordpress is scoring a B on most pages.

  2. How does the “Improving WordPress Default Code” works with WP Multi site directory installations? for instance, my current Network Setup says to replace any other wordpress rules in .htaccess with:

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ – [L]

    # uploaded files
    RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) wp-includes/ms-files.php?file=$2 [L]

    # add a trailing slash to /wp-admin
    RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ – [L]
    RewriteRule ^[_0-9a-zA-Z-]+/(wp-(content|admin|includes).*) $1 [L]
    RewriteRule ^[_0-9a-zA-Z-]+/(.*\.php)$ $1 [L]
    RewriteRule . index.php [L]


    • The first half of the post would still apply. For multisite, I’d suggest leaving the default code alone.

  3. this time I’ve been using w3 total cache, but the results of my tests showed F, what should I do

    I still have to use the above code


  1. […] I chose 12 hours for most files, you may want to set longer times. I don't remember where I got these directives, it may have been from Gary Jones. […]

Speak Your Mind