Making WordPress Happy With HTTPS Behind the OS X Server Proxy

Photo of Greg
Photo by Sister72 - http://flic.kr/p/nEAhL

When figuring out whether they’re communicating with the outside world over HTTPS, applications can check whether they’re behind a reverse proxy which forwarded an HTTPS request over plain HTTP. Unfortunately, WordPress doesn’t do that, so here are two ways to get it working again on Server 5.

It’s very easy for a PHP script to check headers indicating whether it is sitting behind a reverse proxy which has forwarded on a request that was originally received over HTTPS. And although the WordPress developers have been aware for several years that users can experience nasty, show-stopping problems with WordPress when it is behind a reverse proxy or load balancer, for some reason the party line has been that it’s a “server configuration thing” and therefore not something they should fix.

(It’s worth observing that a reverse proxy is a fairly common “server configuration thing” and one which does not itself need fixing. In other words, it’s not that WordPress has problems because there’s something wrong with the way a reverse proxy has been set up; it’s that WordPress has problems because the two lines of code which would enable it to work correctly behind a reverse proxy have been intentionally left out.)

An entry in the WordPress function reference does at least include a nod to the simple fix that, when dropped into wp-config.php, will fake the HTTPS environment variable for the benefit of the rest of WordPress by checking the appropriate header:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
    $_SERVER['HTTPS'] = 'on';

Note that Server’s own httpd_server_app.conf reminds us that X-Forwarded headers, except for the last comma-delimited value, can contain injected text. Given the architecture of OS X Server’s reverse proxy setup, it’s not clear to me whether this particular fix should be considered immune to header spoofing — i.e., convincing WordPress that it’s communicating over HTTPS when it is not — but provided that any HTTPS sites include rewrites to force non-HTTPS requests to use HTTPS, it makes no difference anyway: go ahead and spoof an X-Forwarded header if you really feel like it, but your request is still going to be bounced to HTTPS all the same.

If you’d prefer not to add this fix to all the wp-config.php files on your server, or if you are running other code which, like WordPress, makes assumptions about whether it is running behind a reverse proxy, a second approach is to fake the HTTPS environment variable right in an Apache config added to each virtual host. This is especially useful if you’re already making use of a global virtual host tweak web app that you routinely include in the configuration for new sites: change the one file, and every site gets the fix. (This could be used in .htaccess files, too, but for performance reasons, .htaccess files shouldn’t be used anyway except when really necessary.)

<IfModule mod_rewrite.c>
	RewriteEngine On
	# Check the ways it could have been https...
	RewriteCond %{HTTPS} =on [OR]
	RewriteCond %{SERVER_PORT} ^443$ [OR]
	RewriteCond %{SERVER_PORT} ^34543$ [OR]
	RewriteCond %{HTTP:X-Forwarded-Proto} https [NC]
	# ...and if it was https, then set HTTPS
	RewriteRule .* - [E=HTTPS:on]
</IfModule>

In other words, we’re creating a new environment variable called HTTPS, and that environment variable will be indistinguishable from the ‘real’ one when a script checks $_SERVER to see if a request came over HTTPS. The rewrite code above, which is intended to be ‘backward compatible’ in the sense that will work regardless of whether a reverse proxy is active, first checks whether it was a normal non-proxied HTTPS request, then checks whether it was over the normal HTTPS port 443, then checks whether it was over the proxy’s HTTPS port 34543, and finally checks whether X-Forwarded-Proto was set to indicate HTTPS; if any of these turns out to be true, then it sets the new environment variable appropriately.

This should ensure that any scripts which check the value of the HTTPS variable will understand that the original page request came in over HTTPS, regardless of whether a proxy is involved.

All material on this site is carefully reviewed, but its accuracy cannot be guaranteed, and some suggestions offered here might just be silly ideas. For best results, please do your own checking and verifying. This specific article was last reviewed or updated by Greg on .

This site is provided for informational and entertainment purposes only. It is not intended to provide advice of any kind.