Who said WordPress is slow on Windows Server IIS? Gzip compress and serve WP-Super-Cache or Cache Enabler static HTML files, to supercharge your WordPress blog. Here is how to serve gzip compressed HTML files through Windows Server IIS: create smaller, compressed, static HTML files, that are downloaded faster. This works with WP-Super-Cache and Cache Enabler on IIS!

Configure WP-Super-Cache to serve Gzip compressed static files

WP-Super-Cache is a great caching plugin for WordPress. WP-Super-Cache has multisite support, Gzip compression, mod_rewrite, PHP caching, and support for plugins like minify, WP Touch, Bad Behavior, and so forth.

Creating static supercache HTML files of your blog content is great for speed, but Gzip compressing the static HTML files is even more! Unfortunately, this often is a difficult task on Windows Server IIS.

To serve Gzip compressed files to the browser, I have enabled the following WP-Super-Cache settings enabled. All available under Advanced:

  • Cache hits to this website for quick access. (Recommended)
  • Use mod_rewrite to serve cache files.
  • Compress pages so they’re served more quickly to visitors. (Recommended)
  • Don’t cache pages for known users. (Recommended)

Setting mod_rewrite to serve cache files generates a WP-Super-Cache notification:

Mod rewrite may not be installed!
It appears that mod_rewrite is not installed. Sometimes this check isn't 100% reliable, especially if you are not using Apache. Please verify that the mod_rewrite module is loaded. It is required for serving Super Cache static files. You will still be able to use legacy or PHP modes.

Just ignore that, because this check isn't 100% reliable, especially if you are not using Apache, and we are on IIS :-) .

Next, it's time to allow additional Server Variables in IIS, in this case HTTP_ACCEPT_ENCODING and HTTP_X_ORIGINAL_ACCEPT_ENCODING.

Add server variables with IIS Manager

In the URL Rewrite section of your website in IIS Manager, you can configure additional server variables through View Server Variables... under Manage Server Variables in the Actions pane and by clicking Add.... Fill out HTTP_ACCEPT_ENCODING and click OK, do the same for HTTP_X_ORIGINAL_ACCEPT_ENCODING.

You need to be an administrator for this, or ask your hosting provider for support.

IIS Manager Allowed Server Variables

Please excuse the lack of more screenshots and its quality, you can find similar screenshots in my Drupal optimization post. You need these server variables available to URL Rewrite to set up appropriate URL Rewriting rules later on.

Configure text/html MIME-Type for .gz files

If you want to serve Gzip compressed index.html.gz files through the browser, without displaying garbage, you need to configure a MIME-Type for the .gz file extension. The MIME-type you want is text/html, because a browser needs to uncompress and display the contents.

Open up your web.config file and add to your system.webServer node:

<staticContent>
<remove fileExtension=".gz" />
<mimeMap fileExtension=".gz" mimeType="text/html; charset=UTF-8" />
</staticContent>

The staticContent node is where you can define all MIME-types. However, changing other MIME-types is not relevant for this post, and therefore I left that out. This configures IIS to serve .gz files with a MIME-type text/html, otherwise the browser can't display the content.

WP-Super-Cache web.config URL Rewrite Module rules

Almost everything is in place now, you're almost done. If all went well, you'll see static HTML and gzipped HTML files being created in the wp-content/cache/supercache/[domain]/ directory. All you need to configure now is to rewrite requests to those files.

Below, I added all my WP-Super-Cache rewrite rules. Some may be specific to my environment, use them with care and always test new settings in a development environment first! Don't forget that one tiny error or duplicate line causes an HTTP 500 error.

my environment is a WordPress Multisite. You must match the rules to your WordPress environment, for example if your "WordPress Address (URL)" differs.

Add the following rewrite rules to your web.config:

<rule name="WP_Super_Cache_HTTPS_mobile_gz" stopProcessing="true">
<match url="^(.*)" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="POST" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="^.*(comment_author|wordpress_logged_in|wp-postpass)_.*$" negate="true" />
<add input="{HTTP_X_WAP_PROFILE}" pattern="^[a-z0-9\"]+" />
<add input="{HTTP_PROFILE}" pattern="^[a-z0-9\"]+" />
<add input="{HTTP_USER_AGENT}" pattern="^.*(2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800|w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-).*" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
<add input="{HTTPS}" pattern="on" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https-mobile.html.gz" matchType="IsFile" />
</conditions>

<serverVariables>
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_ACCEPT_ENCODING" value=""/>
</serverVariables>

<action type="Rewrite" url="/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https-mobile.html.gz" />
</rule>

<!-- SSL in WordPress: How To Move Your WordPress Site to HTTPS? The Definitive Guide -->
<!-- https://www.saotn.org/ssl-wordpress-move-wordpress-site-https-definitive-guide/ -->
<rule name="WP_Super_Cache_HTTPS_mobile" stopProcessing="true">
<match url="^(.*)" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="POST" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$" negate="true" />
<add input="{HTTP_X_WAP_PROFILE}" pattern="^[a-z0-9\"]+" />
<add input="{HTTP_PROFILE}" pattern="^[a-z0-9\"]+" />
<add input="{HTTP_USER_AGENT}" pattern="^.*(2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800|w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-).*" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" negate="true" />
<add input="{HTTPS}" pattern="on" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https-mobile.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https-mobile.html" />
</rule>

<rule name="WP_Super_Cache_HTTPS_gzip" stopProcessing="true">
<match url="^(.*)" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="POST" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
<add input="{HTTPS}" pattern="on" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https.html.gz" matchType="IsFile" />
</conditions>

<serverVariables>
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_ACCEPT_ENCODING" value=""/>
</serverVariables>

<action type="Rewrite" url="/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https.html.gz" />
</rule>

<rule name="WP_Super_Cache_HTTPS" stopProcessing="true">
<match url="^(.*)" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="POST" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" negate="true" />
<add input="{HTTPS}" pattern="on" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index-https.html" />
</rule>

<!-- rewrite everything else to WP-Super-Cache's index.html cache file -->
<rule name="WP_Super_Cache_HTTP" stopProcessing="true">
<match url="^(.*)" ignoreCase="true" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="POST" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$" negate="true" />
<add input="{HTTPS}" pattern="on" negate="true" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="/wp-content/cache/supercache/{SERVER_NAME}/{R:1}/index.html" />
</rule>

The read magic happens in these outboundRules, were you rewrite the output stream and set all appropriate Content-Encoding and Content-Type HTTP response headers.

WP-Super-Cache default .htaccess

For future reference, here is WP-SuperCache's default .htaccess

# BEGIN WPSuperCache
# The directives (lines) between `BEGIN WPSuperCache` and `END WPSuperCache` are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

#If you serve pages from behind a proxy you may want to change 'RewriteCond %{HTTPS} on' to something more sensible
AddDefaultCharset UTF-8
RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{HTTPS} on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html.gz -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html.gz" [L]

RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{HTTPS} !on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html.gz -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html.gz" [L]

RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTPS} on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index-https.html" [L]

RewriteCond %{REQUEST_URI} !^.*[^/]$
RewriteCond %{REQUEST_URI} !^.*//.*$
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{HTTP:Cookie} !^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$
RewriteCond %{HTTP:X-Wap-Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTP:Profile} !^[a-z0-9\"]+ [NC]
RewriteCond %{HTTPS} !on
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html -f
RewriteRule ^(.*) "/wp-content/cache/supercache/%{SERVER_NAME}/$1/index.html" [L]
</IfModule>
# END WPSuperCache

When stuff breaks: website hangs, application pool becomes unresponsive, etc.

As always with IIS, rewrite rules, and in particularly outboundRules: sometimes stuff breaks. It just does. You know when something got messed up in IIS when the gzipped garbage content is printed in your browser, when your browser wants to download the file, or when the website application becomes unresponsive.

This doesn't happen often, and when it does, I usually purge my wp-content/cache directory and recycle the application pool. This always solves it.

WP-Super-Cache enhancement request

After some consideration I decided to submit an enhancement request for IIS support in WP-Super-Cache to Automattic. You can find my enhancement request on GitHub: Windows Server IIS web.config support.

Cache Enabler WordPress plugin
The Cache Enabler WordPress plugin

5 URL Rewrite rules for WordPress Cache Enabler plugin to serve gzip compressed files

As I already mentioned above, you can use KeyCDN's Cache Enabler for WordPress plugin as well, as a replacement cache plugin for WP-Super-Cache. Cache Enabler by KeyCDN is more lightweight than WP-Super-Cache and provides a lot of the same functionality. Certainly the most important ones: caching and gzip compression.

The WordPress Cache Enabler plugin is a lightweight caching plugin that creates static HTML files and stores them on your web server. This means that a static HTML file will be delivered whenever possible to provide users with the response data that would otherwise involved the resource intensive process of using the WP core, plugins, and database. This simple, yet powerful plugin is easy to use, needs minimal configuration and best of all helps improve site load time.

WordPress Cache Enabler Plugin, KeyCDN's Knowledge Base article

I created five (5) URL Rewrite rules to use with Cache Enabler, so you can choose the rules that fit your site best. The five rewrite rules are:

  1. Accelerated Mobile Pages (AMP) over HTTPS / SSL with gzip (mobile device users will love this!)
  2. HTTPS / SSL with gzip (gzip compressed HTML)
  3. HTTPS / SSL without gzip (static HTML)
  4. HTTP with gzip (gzip compressed HTML)
  5. HTTP without gzip (static HTML)

Note: the same IIS Server Variables caveats apply with these rules to serve index.html.gz files! See above for how to allow extra server variables to URL Rewrite in IIS.

Without further ado, here are the 5 URL Rewrite rules for Cache Enabler:

<!-- Add above WordPress' default URL Rewrite rule -->
<rule name="Saotn.org_Cache_Enabler_HTTPS_AMP_gzip" stopProcessing="true">
<match url="^(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{URL}" pattern="^.*/amp/.*$" negate="false" />
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="(wp-postpass|wordpress_logged_in|comment_author)_" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
<add input="{HTTPS}" pattern="on" ignoreCase="true" negate="false" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html" matchType="IsFile" />
</conditions>
<serverVariables>
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
<action type="Rewrite" url="/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html.gz" />
</rule>

<rule name="Saotn.org_Cache_Enabler_HTTPS_gzip" stopProcessing="true">
<match url="^(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="(wp-postpass|wordpress_logged_in|comment_author)_" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
<add input="{HTTPS}" pattern="on" ignoreCase="true" negate="false" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html.gz" matchType="IsFile" />
</conditions>
<serverVariables>
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
<action type="Rewrite" url="/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html.gz" />
</rule>

<rule name="Saotn.org_Cache_Enabler_HTTPS_html" stopProcessing="true">
<match url="^(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="(wp-postpass|wordpress_logged_in|comment_author)_" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" negate="true" />
<add input="{HTTPS}" pattern="on" ignoreCase="true" negate="false" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html" />
</rule>

<rule name="Saotn.org_Cache_Enabler_HTTP_gzip" stopProcessing="true">
<match url="^(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="(wp-postpass|wordpress_logged_in|comment_author)_" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
<add input="{HTTPS}" pattern="on" ignoreCase="true" negate="true" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html.gz" matchType="IsFile" />
</conditions>
<serverVariables>
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
<action type="Rewrite" url="/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html.gz" />
</rule>

<rule name="Saotn.org_Cache_Enabler_HTTP_html" stopProcessing="true">
<match url="^(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{URL}" pattern="^(.*)$" />
<add input="{URL}" pattern="^/wp-admin/.*" negate="true" />
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern=".*=.*" negate="true" />
<add input="{HTTP_COOKIE}" pattern="(wp-postpass|wordpress_logged_in|comment_author)_" negate="true" />
<add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" negate="true" />
<add input="{HTTPS}" pattern="on" ignoreCase="true" negate="true" />
<add input="{DOCUMENT_ROOT}/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="/wp-content/cache/cache-enabler/{SERVER_NAME}/{R:1}/index.html" />
</rule>

<!-- Add beneath WordPress' default rewrite rule, beneath "\</rules\>" -->
<outboundRules rewriteBeforeCache="false">

<rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
<match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
<action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
</rule>

<rule name="SetContentEncodingheaderGzip" preCondition="IsGZ" stopProcessing="true">
<match serverVariable="RESPONSE_Content_Encoding" pattern=".*" />
<conditions>
<add input="{REQUEST_URI}" pattern="\.gz$" />
</conditions>
<action type="Rewrite" value="gzip" />
</rule>

<preConditions>
<preCondition name="IsGZ">
<add input="{PATH_INFO}" pattern="\.gz$" />
</preCondition>
<preCondition name="NeedsRestoringAcceptEncoding">
<add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
</preCondition>
</preConditions>

</outboundRules>

Conclusion speeding up WordPress by serving gzip compressed static cache files

WP-Super-Cache and Cache Enabler are great WordPress cache plugins. Both plugins create static HTML files of your posts, and serving these HTML files mostly bypasses PHP and database processing. Your pages and posts are served to the browser faster. Also, both cache plugins have the ability to gzip compress those HTML files, making them even smaller.

You can, however, add additional URL Rewrite or .htaccess rewrite rules, to fully bypass PHP if cache files exists. If you don't add these rules, there is always a PHP process to rewrite requests internally in WordPress to find cached files. If they exist. Or to display the dynamically generated contents when no cache file is found.

The URL Rewrite rules I provided for you here practically do the same thing: look in a directory for the existence of cache files (.html or .html.gz) and rewrite requests if they're found. This fully bypasses PHP processing and speeds up your WordPress site. For Windows Server IIS, extra configuration is required though, to successfully serve gzip compressed files.

If you have a question, or ran into problems, please don't hesitate to leave a comment here. And don't forget to share this post with your colleagues, friends and family. Thanks!

Donate a cup of coffee
Donate a cup of coffee

Thank you very much! <3 ❤️

7 Comments

  1. mershid

    Hello
    And thanks for your good codes, A question please:
    ( I am using IIS and Cache enabler )
    Already I have ready to use WebP version of media side-by-side. What will be the solution to server WebP.
    I check and noticed WebP’s correctly addressed in https-index-webp.html files but in front-end still show jpeg/png

    Regards

  2. Just debugged those rules a bit. The standard config gave me a 500. in the third rule there is a bug that generates a 500. I fixed it but dont ask me how its 0357 at night and my eyes are closing now.

    • Hi Sander, thank you for your comment.

      With the third rule you mean WP_Super_Cache_HTTPS_gzip? This one gives an HTTP 500 error if the serverVariables aren’t available to the website in IIS (add them using IIS Manager GUI, through URL Rewrite → View Server Variables). The Outbound Rules needs to be in place too. Just drop me a note if you’d like me to copy my web.config to web.config.txt for download.

      • Sander Kooger

        on azure it is impossible to add them using IIS interface but…. you can always add and mod the applicationhost.xdt file in root/site with the folowing code.

        J reilink. When aour site is ready for a go live id like it af you gave the config a once over. See if the dutchies could help each other out.

        REgards,
        Sander Kooger

        • Hi Sander,
          I put my web.config file here: . I’ve deleted the irrelevant items and added a few comments. It’s important to first set up your serverVariables in URL Rewrite before putting in the URL rewrite rules. And don’t forget to set up the .gz MIME-type to serve it as text/html.

  3. This is great, simple and comprehensive tutorial.
    I just noticed that following rules not well performed as xml pattern=”^[a-z0-9\”]+” I can make it works by using pattern=”^[a-z0-9]+”.
    Other than that this just awesome.

    • Hi Wigid, thank you very much for your comment.

      I converted the .htaccess generated by WP-Super-Cache to IIS’ web.config (using IIS Manager) and pasted the contents in this post. I didn’t realize the &quot; got decoded to a double quote (") in the post. I’ve changed the code in this post now, thanks.

      I’m not really sure about pattern="^[a-z0-9\"]+" (I would assume pattern="^[a-z0-9]+" as well), but it was in WPSC’s .htaccess too.

Comments are closed