Using Apache RewriteMap to handle redirects for WordPress multisite
I’m assuming you’re here for answers, so I’m going to put the solution first and the backstory details later.
Quick solution: How to use Apache RewriteMap
Step 1: Create the redirect mapping file
One entry per line. Source URI, single space, then the destination URI. Remember, RewriteMap only handles simple redirects (no regex, wildcard, or conditional redirects are allowed).
Choose the scenario that fits your needs:
Scenario A
If you’re mapping redirects from the same domain, simply provide source/destination URIs in ~/redirects.txt
# Comments are OK
/about-us/ /company/about/
/products/roadrunner-traps/ /discontinued-products/
/return-policy/ /really-there-are-no-returns-allowed/
Scenario B
If you have a WP multisite install, you’ll need to specify the full URL for each redirect, otherwise the redirects you set will apply to all sites in your multisite collection. Leave HTTP/HTTPS off for the source URLs, but use them for the destination URLs to eliminate HTTP→HTTPS redirects.
# Comments are OK
www.acmeinc.com/about-us/ https://www.acmeinc.com/company/about/
www.acmeinc.com/products/roadrunner-traps/ https://www.acmeinc.com/discontinued-products/
www.acmeinc.com/return-policy/ https://www.acmeinc.com/really-there-are-no-returns-allowed/
Step 2: Create the indexed flat-file database to improve lookup speed
sudo httxt2dbm -f db -i ~/redirects.txt -o /var/www/acmeinc/redirects.db
If your server complains that httxt2dbm
isn’t installed, try installing the apache2-utils
package.
Step 3: Tell Apache to use the redirect mapping file
Edit /etc/apache2/sites-available/acmeinc.conf
and update the VirtualHost to include the new mapping file.
<VirtualHost *:443>
ServerName www.acmeinc.com
# Declare the rewritemap
RewriteMap acmeredirects "dbm:/var/www/acmeinc/redirects.db"
# Prevent serving the redirects.db file
<Files "redirects.db">
Require all denied
</Files>
<Directory /var/www/acmeinc>
Options FollowSymLinks MultiViews
AllowOverride All
Require all granted
RewriteEngine On
# Make these the first rewrite/redirect rules, before the WP stuff.
# Uncomment the lines for the scenario that meets your needs:
# (SCENARIO A) For a single domain, just process URI
# RewriteCond ${acmeredirects:$1} !=""
# (SCENARIO B) For multisite, handle the hostname and URI
# RewriteCond ${acmeredirects:%{HTTP_HOST}%{REQUEST_URI}} !=""
# RewriteRule .* ${acmeredirects:%{HTTP_HOST}%{REQUEST_URI}} [R=301,END]
# Regular WP redirect lines goes here
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
</Directory>
</VirtualHost>
Step 4: Restart Apache!
sudo systemctl restart apache2
Test out the redirects to make sure they work. At this point, you’re done!
Results
(This section added: 2020-06-11)
Now that our system has been running for a few days, I wanted to compare site performance to see if there were any noticable improvements.
It turns out that removing the WordPress redirection plugin and allowing Apache to handle the redirects has resulted in significant performance gains for our website. Overall page load time has decreased by a full second. TTFB has been cut in half, along with first contentful paint. Onload and fully loaded page times are seeing huge improvements as well.
Index | Before | After | Reduction |
---|---|---|---|
TTFB | 439 | 219 | -50% |
FCP | 1300 | 600 | -54% |
Onload | 2500 | 1400 | -44% |
Fully loaded | 2700 | 1700 | -37% |
Backstory
WordPress has some great redirect plugins, but in order to improve performance and ensure stability, I avoid third-party plugins as much as possible.
I have used RewriteMap before for site redirect handlers, but learning how to use it for a multi-domain WordPress multisite install took some intense sleuthing.
What’s Apache RewriteMap?
It’s a really fast way to handle thousands of redirects at the server level, before the request even gets to PHP. A simple, plain text file stores the mapping of all(1) redirects you want to handle.
# An example Apache RewriteMap file with two redirects
/from/this/url /to/this/url
/old/url /new/url
Apache even comes with a utility to create an indexed database of that list, so that URL lookups are ordered and nearly instantaneous.
(1) Regex redirects need to be put in your VirtualHost file.
Why use RewriteMap?
By taking PHP out of the equation and allowing Apache to handle your redirects, just look at all the processing steps that are saved on each page request:
- Apache receives the incoming HTTP request.
- An SSL handshake happens, and a secure connection is opened.
- ⇒ Apache parses the request and applies any redirect rules. ⇐
Apache sends the request to the PHP engine.PHP loads the WordPress core and theme files (hopefully from the in-memory opcache) and starts executing WordPress:wp-config.php is parsed and executed.Default constants are set up.Connection to the DB is established.wp-includes/cache.php runs.sunrise.php runs (if applicable).Localization library is loaded.MU plugins run.Active plugins run.[plugins_loaded] action runs.Rewrite rules execute.Instantiate $wp and $wp_query.Setup the theme.Run the child theme functions.Run the parent theme functions.Run init.Setup widgets.Run wp().⇒ Parse the HTTP request and handle any redirects. ⇐
Get started
For this example, pretend you own www.acmeinc.com
and you want the following redirects:
From: www.acmeinc.com/about-us/
→ To: www.acmeinc.com/company/about/
From: www.acmeinc.com/products/roadrunner-traps/
→ To: www.acmeinc.com/discontinued-products/
From: www.acmeinc.com/return-policy/
→ To: www.acmeinc.com/really-there-are-no-returns-allowed/
If you have just a few redirects, it’s easier to just toss them into your VirtualHost config file. But if you have dozens, hundreds, or even thousands of redirects, RewriteMap is the tool for you.
Step 1: Map out your redirects
First, make a list of all of the redirects you want to handle. Group them into these two groups:
- Simple redirects, like
/a/
→/b/
. - Complex redirects with wildcards or regular expressions, like
/c/(.*)
→/d/$1
.
Remember, RewriteMap only handles simple redirects.
Now, jump up to the top of this guide to continue implementing this cool feature!