3

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?

2 Answers 2

7

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.

3
  • This is what I ended up doing--putting the assignment in wp-config.php. I just set it to true though. I don't see any necessity to test for all those headers, since one deployment will not change and if it does, you're probably replacing the whole wp-config file anyhow.
    – Octopus
    May 12, 2021 at 3:25
  • 1
    Yes, this is the usual solution, however it has a small problem. Wordpress can’t open connections to itself. This is usually used when Wordpress is running behind some reverse proxy that handles SSL termination and wordpress is running on a container or VM in another webserver without SSL. In those setups wordpress will try to connect to itself for automated plugin updates / cron and will fail because it will be expecting the server to handle SSL. The site url stored on the database also includes “https” complicating things further. How does one fix that?
    – TCB13
    Jul 19, 2022 at 9:10
  • 1
    That's an interesting question. If the URL has https:// and the full host name, won't it request out to the proxy and then back into the site, and everything will just work? Unless you have the host name in your hosts file for this machine too. You could also run an HTTPS server locally with a certificate that this host will trust (which doesn't have to be globally valid), or you could probably hook into the outbound HTTPS connections code to cope with this case: anything localhost or hostname is HTTP only, and add one of the forwarded SSL headers tested by the above code.
    – Rup
    Jul 19, 2022 at 12:18
1

This is an older thread, but I like to share the solution.

Step 1: access DB > wp_options > siteurl : https://domain.com

Step 2: access DB > wp_options > home : https://domain.com

Step 3: edit /var/www/wordpress/wp-config.php >

  define('WP_SITEURL', 'https://domain.com');
  define('WP_HOME', 'https://domain.com');

and paste the code below to the next line:

 /** Fix for SSL behind Proxy **/
  $parsedUrl = parse_url(WP_HOME);
  $scheme = $parsedUrl['scheme'];
  if ($scheme == 'https') {$_SERVER['HTTPS'] = 'on';}
  else {$_SERVER['HTTPS'] = 'off';}
2
  • That looks like it's testing if your site URL is HTTPS, not whether the request actually came over HTTPS?
    – Rup
    Jun 23, 2023 at 8:06
  • That is correct. - When a web server is behind a load balancer or reverse proxy, the HTTPS request is handled by the proxy and forwarded as a normal HTTP request. In this case, WordPress thinks that it is running in HTTP mode, even though the request came in over HTTPS, causing WordPress to serve all links to static files as HTTP, which leads to mixed content warnings or even the content not loading at all. Using the URL provided in the config file to determine the protocol allows setting $_SERVER['HTTPS'] correctly. This way, WordPress will serve static files with the correct URL Jun 24, 2023 at 9:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.