How do I handle SSL properly when WP is behind a reverse proxy?

The question:

I am running WordPress behind a proxy. The is_ssl() function in wp_includes/load.php will never be able to work in an environment like this because $_SERVER[‘HTTPS’] has no idea how the browser sees the page. All requests are normalized by the proxy.

I can make my site work by changing the is_ssl() function, but now, periodically, WordPress “fixes” my fix when it does auto-updates.

What is the preferred way to deal with this situation? I am currently on v5.7.1 and I don’t even see a way to disable updates. I would rather not disable updates anyhow.

How can I tell WordPress that is_ssl() is always true, and keep it permanently throughout updates?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

You can’t hook is_ssl() to override the result, and as you’ve noticed you can’t edit WordPress Core itself or your changes will get lost if you’re using built-in automatic updates.

So the usual approach – see the WordPress documentation – is to set $_SERVER['HTTPS'] = 'on';, which is the property is_ssl() tests. Add the following block to wp-config.php (which is preserved during updates), somewhere before the final require_once:

if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
    $_SERVER['HTTPS'] = 'on';
}

This tests whether your reverse proxy added a header X-Forwarded-Proto: https to the proxied request and if it did it sets the HTTPS flag for WordPress, so that the SSL flag does try and reflect the original request. The Really Simple SSL plugin has a more comprehensive version of this that I’ve used too that tests more values from other proxies:

//Begin Really Simple SSL Load balancing fix
if ((isset($_ENV["HTTPS"]) && ("on" == $_ENV["HTTPS"]))
  || (isset($_SERVER["HTTP_X_FORWARDED_SSL"]) && (strpos($_SERVER["HTTP_X_FORWARDED_SSL"], "1") !== false))
  || (isset($_SERVER["HTTP_X_FORWARDED_SSL"]) && (strpos($_SERVER["HTTP_X_FORWARDED_SSL"], "on") !== false))
  || (isset($_SERVER["HTTP_CF_VISITOR"]) && (strpos($_SERVER["HTTP_CF_VISITOR"], "https") !== false))
  || (isset($_SERVER["HTTP_CLOUDFRONT_FORWARDED_PROTO"]) && (strpos($_SERVER["HTTP_CLOUDFRONT_FORWARDED_PROTO"], "https") !== false))
  || (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && (strpos($_SERVER["HTTP_X_FORWARDED_PROTO"], "https") !== false))
  || (isset($_SERVER["HTTP_X_PROTO"]) && (strpos($_SERVER["HTTP_X_PROTO"], "SSL") !== false))
) {
  $_SERVER["HTTPS"] = "on";
}
//END Really Simple SSL

And there’s an alternative approach here on StackOverflow where you can use Apache configuration to set HTTPS=1 instead if that’s easier:

<IfModule mod_setenvif.c>
  SetEnvIf X-Forwarded-Proto "^https$" HTTPS
</IfModule>

rather than editing wp-config.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment