A comprehensive overview of the setup for a WordPress Multisite subdirectory install hosted on WPENGINE running through a Fastly Load Balancer to a client’s server in Reverse Proxy configuration
This tutorial represents much time, frustration, and eventual joy. Our team hopes it will be helpful to others. Please feel free to comment and help us make this better.
If you need help, reach out to us. If you find it valuable, please share, like, and comment!
Special thanks to the amazing teams at: Fastly, WPENGINE, Kapost, YourAmigo, and our gracious client for whom this was built with <3
Tutorial Version 1.1.2
Goal
To use a Reverse Proxy and have a site at originalsite.com appear to live at finalsite.com/blog and SEO-migrate from one to the other.
Definitions
Originating site http://originalsite.com
Original multisite blogs originalsite.com/site1/, originalsite.com/site2/ , etc.
Final site https://www.finalsite.com/blog/
Final multisite blogs finalsite.com/blog/site1/, finalsite.com/blog/site2/ , etc.
Final admin site http://admin.originalsite.com
Final admin multisite blogs admin.originalsite.com/site1/, originalsite.com/site2/ , etc.
Example domains to protect client privacy
Why have a site in this set up?
Having a site on a subdirectory (originalsite.com/blog/) rather than a subdomain (blog.originalsite.com) can have vastly greater positive SEO impact. This impact goes both for the actual WordPress site but anything else on the primary domain. Ranking potential is far greater having a site in .com/blog format as it gets the benefit of the domain strength in a far tighter manner than a subdomain.
Often a WordPress site can’t be actually installed on the root domain’s server. It can make sense to have it segmented for security or on WordPress-specific hosting. This lets the main site keep its server and application siloed. In Reverse Proxy setup a subdirectory like this can be excluded from PCI-compliance if the main site is running Ecommerce or similar.
WordPress Setup
One of the main advantages of this setup is that you can keep WordPress accessible at a subdomain and let the WPENGINE staging setup stay intact. You aren’t then fighting against WordPress or the hosting platform! While we chose to have ours located at admin.originalsite.com, there is no reason you couldn’t also have it live at admin.finalsite.com or similar.
There ends up being an entire multisite that lives at admin.originalsite.com. This allows you to create a global 301 redirect on originalsite.com and www.orginalsite.com to make sure all existing rankings and references are properly redirected.
All the site URLs on the backend will stay http://admin.originalsite.com
Using a special Reverse Proxy WordPress plugin, the URLs will be rewritten to match the end destination of https://www.finalsite.com/blog/
Quick Tip! It is important that WordPress URLs are all set to http or WPENGINE will interfere with the process.
WordPress – Reverse Proxy Plugin
This plugin is partially inspired by this one by JamesPaden. You Network Activate the plugin.
What this plugin will do is test if we’re on the front-end of our correct site (so we don’t mess up the admin controls as well as any testing or staging sites). If so, we’ll update all the original site URLs and replace with “https” versions of the final site URLs.
Additionally, if using the Yoast SEO plugin this will replace all the canonical URLs globally so there will never be any versions of the admin controlled version of the site getting indexed as the original source for the content.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Make sure to have the CDN filled in with your final site full URL or finalsite.com/blog may not render.
WordPress – wp-config.php
The wp-config.php file will stay much the same as you would expect for a multisite setup. Primary thing to add are your Purgely keys to help Fastly work well using the Purgely plugin.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The .htaccess file in the root of Original Site has a typical setup for WordPress Multisite. There is nothing special about the setup of this file for the Reverse Proxy.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The originalsite.com domain’s A record point to the WPENGINE install IP address or install CNAME if you are using CloudFlare CNAME Flattening. The WWW CNAME points to the install CNAME.
The originalsite.com admin CNAME record points to Fastly e.g. global.prod.fastly.net
If you are pointing to a Fastly SSL the CNAME will be different and you’ll need to first add a TXT verification record.
Original Site – Global Redirects
We are using a global 301 redirect to send any requests to the original site to new equivalent URLs. This way the SEO trust of the original site gets passed on and rankings preserved. As well, if any blogs have linked to the old URLs, we’ll preserve the user experience.
Source: ^(/)?(.*)
Destination: https://www.finalsite.com/blog/$2
[Thanks J. Withee for the RegEx help]
Make sure there is only one 301 “hop”. The more hops in the chain, the more it reduces the SEO strength being passed. (Redirect Checker Tool) This is why I have www and non-www added as separate domains in WPENGINE…
SSL Certificates
If the final site is https then you will for sure need your admin.orginalsite.com to be properly SSLed or you will have mixed content warnings and things won’t work right.
This was a tricky part of the process and key to it working. Here is what our SSL configuration looked like in WPENGINE. Don’t force non-SSL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
That is for an Apache Virtual Host but similar configurations can be created for nginx or Microsoft IIS setups.
Fastly CDN / Load Balancer
This is an important part of the whole equation. It caches and ensures that the bulk of the load is handled by the Fastly network, not WPENGINE. You wouldn’t (likely) be able to leverage WPENGINE’s caching and architecture if you went direct. A traffic spike would then be crippling. Post-launch without much optimization our site is consistently loading between 1 and 1.3 seconds.
Fastly is built on Varnish and can use VCL (Varnish Configuration Language). Here is a link to our anonymized complete VCL that is assembled from all the following. One of the Pre-Launch checks is to look over the generated VCL and make sure all the URLs are correct.
There were several custom rules that were created so that our headers from finalsite.com/blog/ were getting passed through to end up being able to be addressed by the WordPress Reverse Proxy plugin.
Fastly – Domain
Fastly – Backend Origins
If you are using WPENGINE, make sure that for the secure host (443) not just Certificate Hostname but also SNI Hostname are both set to admin.originalsite.com.
Fastly – Override Host
Fastly – Headers forwarded
There are 5 headers configured to be passed. (“Ignore if set” on all of them)
IF No headers for Original req.http.Host != “admin.originalsite.com”
HTTP_X_FORWARDED_SERVER required by WPEngine
Destination: http.HTTP_X_FORWARDED_SERVER
Source: "admin.originalsite.com"
X-Forwarded-Server for WPEngine backend
Destination: http.X-Forwarded-Server
Source: "admin.originalsite.com"
Kapost Integration
This particularly client uses Kapost for editorial management. The brilliant folks there were kind enough to get us a custom patch plugin that would make sure the URLs returned to the Kapost instance were the final URLs and not admin URLs. This is key for the Social sharing and Google Analytics components of the Kapost backend.
There is also a separate Multisite plugin for Kapost that is needed as well. So alongside the primary Kapost WordPress plugin, there are two others
WP Engine
We are big fans of WPENGINE but in the case of a Reverse Proxy you have to sidestep some of the platform features in order to make this work right.
Disable WPENGINE’s object caching
Disable WPENGINE’s auto-update WordPress Core – so we can properly test before major upgrades
De-couple WPENGINE CDN if you were using it
Tips & Troubleshooting
Resaving permalinks can be your friend
In WPENGINE it may be helpful to “Reset File Permissions” and “Clear Cache”
If admin.originalsite.com is appearing in the source on finalsite.com/blog you can go to WordPress’s Settings>>Writing for each install and uncheck “Convert emoticons like 🙂 and 😛 to graphics on display”
It may be helpful to have the finalsite.com IP location set in your local Hosts file if there is other caching involved. In our case Akamai was in play as well.
In Yoast SEO’s “Dashboard” >> “Company Info” we had to change the URL to be the finalsite.com image URL for the Company Logo
I wear many hats running the day-to-day operations of LimeCuda. I enjoy strategy and seeing theory turn into real wins. I'm a confessed INTJ.
When not playing in the web work world I enjoy woodworking, pretentious beer, and living in East Lansing, MI with my wife, our three sons, and theoretically a cat...
Reader Interactions
Comments
Daniel kadoshsays
Blake,
Thanks for documenting this so well!
We’re considering using the solution outlined here, and wanted to check if you have had any issues running this way since you wrote this almost a year ago?
Asking because a solutions engineer from WPEngine told us:
“Proxying traffic over to us is not fully supported, and it does add another point of failure for issues to arise. This typically isn’t a concern, but there are rare instances where the proxy is the issue.”
You’re welcome 🙂
We had the same interaction with them. It is not officially supported and you end up turning off a lot of the more powerful WPENGINE features but overall it has worked well for us.
I have a problem with reverse proxy setup. Google has indexed both the staging blog (where reverse proxy setup) and the live blog. I want to block staging blog to be indexed in Google but cannot do it in a usual way either disallowing in robots.txt or adding ‘no index’ tags as that will replicate the same on live blog.
I had setup multisite with subdirectories mode on WPEngine, but I found the variable “WP_SITEURL” is not defined, it make this plugin not functioning. How about use $_SERVER[‘HTTP_HOST’] to replace WP_SITEURL??
Thanks for your post, super helpful. I ended up taking a similar approach at Poparide but using Nginx as our reverse proxy, which due to its powerful HTTP header and body rewrite capabilities let us treat the WordPress site as a black-box.
If you’re alright with me linking to it here, I thought some readers might find the Nginx equivalent of what you’ve achieved useful:
Blake,
Thanks for documenting this so well!
We’re considering using the solution outlined here, and wanted to check if you have had any issues running this way since you wrote this almost a year ago?
Asking because a solutions engineer from WPEngine told us:
“Proxying traffic over to us is not fully supported, and it does add another point of failure for issues to arise. This typically isn’t a concern, but there are rare instances where the proxy is the issue.”
You’re welcome 🙂
We had the same interaction with them. It is not officially supported and you end up turning off a lot of the more powerful WPENGINE features but overall it has worked well for us.
instead of using wpengine, im using my own droplet at digital ocean and implimenting more or less this solution.
My problem is… my htaccess is not writeable…. wordpress is looking in the wrong place.
Have you experienced this? Got a solution for it?
Thanks for the information.
I have a problem with reverse proxy setup. Google has indexed both the staging blog (where reverse proxy setup) and the live blog. I want to block staging blog to be indexed in Google but cannot do it in a usual way either disallowing in robots.txt or adding ‘no index’ tags as that will replicate the same on live blog.
How can I block staging blog in this case?
I had setup multisite with subdirectories mode on WPEngine, but I found the variable “WP_SITEURL” is not defined, it make this plugin not functioning. How about use $_SERVER[‘HTTP_HOST’] to replace WP_SITEURL??
Hi Blake!
Thanks for your post, super helpful. I ended up taking a similar approach at Poparide but using Nginx as our reverse proxy, which due to its powerful HTTP header and body rewrite capabilities let us treat the WordPress site as a black-box.
If you’re alright with me linking to it here, I thought some readers might find the Nginx equivalent of what you’ve achieved useful:
https://www.poparide.com/blog/how-to-host-wpengine-blog-in-subdirectory-using-reverse-proxy/
Thanks – would love your eyes on our approach if you had a mo!
Luke