WordPress is_ssl() doesn’t work behind some load balancers

WordPress has a function is_ssl() that it uses to check whether a page is loaded with the HTTPS protocol, so that it can use the same protocol to load scripts, stylesheets, and other assets. It relies on the web server giving it a couple of clues, but when your website is hosted behind a load balancer, those clues aren’t always available. In particular, websites hosted by Network Solutions get no clues at all when pages are loaded over HTTPS.

I ran into this recently when someone using my SSL Insecure Content Fixer plugin wasn’t getting any joy, and basic WordPress functions that should have automatically adapted to SSL were all still returning HTTP protocol links. After a brief investigation, it turns out that Network Solutions sites behind load balancers don’t get any clues at all indicating whether a page was loaded over SSL.

Normally, when a page is loaded with the HTTPS protocol, the web server passes a special server variable to tell the website; in PHP it can be checked by looking at $_SERVER['HTTPS']. If that fails, you can check the IP port that the request came in on, to see if it was port 443 (the standard port for SSL); in PHP, you can get that from $_SERVER['SERVER_PORT'].

When your website is behind a load balancer, the load balancer gets that information because that’s what the user’s browser is actually connecting to. It in turn connects to the real web server, but it uses the HTTP protocol, not SSL, so the real web server can’t tell the difference. Amazon’s load balancers apparently provide an extra variable, $_SERVER['HTTP_X_FORWARDED_PROTO'], so you can check for that. If you have some control over the load balancer configuration, you can make it pass some information. But not everyone is so lucky.

To fix the problem on hosts like Network Solutions, you need to trick WordPress into thinking it was passed useful information. It isn’t safe to just assume you’re on SSL, however, so you need to have some idea that you are. The easiest way around this is to put the whole site on SSL by setting the home and site URLs to HTTPS, and then adding the $_SERVER['HTTPS'] variable yourself. Here’s a brief snippet that does that:

// if site is set to run on SSL, then force-enable SSL detection!
if (stripos(get_option('siteurl'), 'https://') === 0) {
    $_SERVER['HTTPS'] = 'on';
}

Of course, a user can always edit the URL in their browser to put it back to HTTP, so we need another way to ensure that pages end up on HTTPS. This little JavaScript snippet will do that when added to all pages:

<script>
if (document.location.protocol != "https:") {
    document.location = document.URL.replace(/^http:/i, "https:");
}
</script>

To save you time and headaches, I’ve put those things together into a simple WordPress plugin. Download this script from gist and save the .php file into the WordPress plugins folder on your website, then activate it in the Plugins admin. It detects when your site’s URL uses HTTPS, and then activates those code snippets above.

Job is done, even on Network Solutions!

facebooktwittergoogle_plusredditpinterestlinkedinmailfacebooktwittergoogle_plusredditpinterestlinkedinmail
  • http://supahmarket.com amy beth

    I would kiss you for this post if i could. I was working on this problem off and on for at least a week. Thank you!!!!!!!!!!!!!!!!

  • http://blog.netflowdevelopments.com Ryan Wiancko

    [Edit: Ryan has contacted me again and said that this method blocks people from logging in! Please read his second message below, and don't add this code to your wp-config.php]

    aaahhhhh, man you are amazing.. Thank you so much.. that wordpress-https plugin just hung the site for me and then your plugin didn’t work at first and then I found this post, put

    if (stripos(get_option(‘siteurl’), ‘https://’) === 0) {
    $_SERVER['HTTPS'] = ‘on’;
    }

    into my wp-config.php file as I’m running nginx and viola! it works..
    instead of using a js to handle the redirect you can just put this in your httpd.conf or vhost.conf file

    ServerAdmin webmaster@domain
    ServerName domain.com
    ServerAlias *.doman.com
    Redirect permanent / https://domain.com/

    No getting around that, even with scriptblockers on

    • http://snippets.webaware.com.au/ Ross McKay

      G’day Ryan, good tip about the .htaccess rules. That’ll fix it!

      cheers,
      Ross

    • paul

      Another note, don’t attempt to put this in your functions.php either, it will also block you from logging into wordpress.

  • Pingback: Fixing ‘This page includes script from unauthenticated sources’ problem with ssl wordpress install on apache+nginx server - Netflow Developments

  • http://blog.netflowdevelopments.com Ryan Wiancko

    God, what a nightmare.. So you should probably delete my above post as addin that into the wp-config or wp-settings file causes users to see the good ole You do not have sufficient permissions…. message when logging in. It fixes everything else but you are no longer able to access your admin area. Installing the little plugin you made here however fixes it completely

    • http://snippets.webaware.com.au/ Ross McKay

      No worries, Ryan. I’ve edited your comment above so that it can be read as a “what not to do” :)

      cheers,
      Ross

  • Ed Roms

    Will this plugin be required in future versions of WordPress? If so, how long will it be before a fix for the problem is put into WordPress core? BTW, thanks much for sharing this excellent work.

    • http://snippets.webaware.com.au/ Ross McKay

      G’day Ed,

      I doubt that WordPress will build this into the core because the exact problem is very specific to the hosting environment in which you run WordPress. This is a kludge that gets your site working, but it has its drawbacks — for example, someone visiting your site with JavaScript disabled can edit the URL in their browser to visit a page without SSL, and your site will just assume they’re using SSL. That’s unlikely to happen, and it won’t really have an impact on most websites but might be important for some sites.

      Some hosting environments support HTTP_X_FORWARDED_PROTO which WordPress could feasibly check for as well in its is_ssl(), but even that is problematic: it’s a simple HTTP header that can easily be forged, thus fooling a site into thinking it’s delivering SSL, so it can only really be relied upon in specific environments.

      So no, this isn’t something that WordPress can easily put into core, unfortunately.

      cheers,
      Ross

  • Jessie

    Thank you SO much!

    I have been banging my head getting constant “redirect loop” errors. I’ve tried EVERY .htaccess method, wordpress ssl plugin, wordpress https plugin and STILL couldn’t figure it out. I am SO glad that it’s actually a Network Solutions error because I was starting to feel crazy!

    This worked wonders! You saved me! Thanks so much!!

  • henry

    Thank you so much!
    This code combined the 2 solutions I spent so long looking for; and was trying unsuccessfully to merge!!!

    Although I am now running into issues with the Advanced Custom Field plugin. It still wants to pull in content (css, js) using HTTP. I checked other forums and blogs and the plugin was patched months ago to use get_content_url() and get_plugin_url() so that it wouldnt have this problem. However I am still having this very issue.

    Any light any one could shed on this conflict would be greatly appreciated ;)

  • Alvin

    Help! This solution isn’t working for me!! Has this stopped working with newer versions of wordpress?

    I’ve tried these plugins with no success: Force SSL URL Scheme, SSL Insecure Content Fixer, WordPress HTTPS. Still my site is displaying without most scripts and stylesheets!

    Network Solutions support doesn’t have a clue! I’m losing years of my life stressing out over this!!

    Any help would be very greatly appreciated.

    • http://snippets.webaware.com.au/ Ross McKay

      G’day Alvin, have you installed and activated Force SSL URL Scheme and then changed your Home (WordPress Address) URL and Site URL to both use https? If you don’t change your home and site URLs to https, Force SSL URL Scheme won’t do anything.

      Yes, I have confirmed the script still works with WP 3.8.

      cheers,
      Ross

      • Alvin

        Thanks so much for your reply!

        I’m actually looking to only secure individual pages on the site, not the whole site. Was trying to use the ‘WordPress HTTPS’ plugin for that, but it isn’t working. Is there an alternate method?

        I did try your solution temporarily just to see if it would work site-wide. It’s much better, but not everything is there, and I’m still getting the “unauthenticated sources” message. Any clues?

        • http://snippets.webaware.com.au/ Ross McKay

          G’day Alvin,

          This is my blog, I suggest you post a full description of your problem complete with a link to your site over at the support forum for my SSL Insecure Content Fixer plugin.

          cheers,
          Ross

  • Paul Sipos

    Many thanks Ross,

    I use your plugin on a website behind a Zeus appliance Load Balancer.
    The Load Balancer is not yet configured to set the HTTPS or the X_FORWARDED_PROTO environment variables so I had to trick the is_ssl() function by setting the HTTPS variable to on in vhosts.conf in apache


    SetEnv HTTPS “on”

    I tested the wp-admin interface and other sections of the website using the wp-login.php and all seems to work just fine with define(‘FORCE_SSL_LOGIN’, true); in wp-config.php

    I hope my experience helps others take advantage of your great plugin.

    Cheers,
    Paul

  • http://www.cooshtee.com Chris Howard

    Lifesaver! I had the same issue with 123-reg in the UK, works a treat.

    • http://www.mathewporter.co.uk/ Mathew Porter

      Hi Chirs, how did you implement out of interest?

      Ive got a client using 123 Reg and only want ssl on checkout in woocommerce.

  • GOStickITdotBiz

    Any help please? I have an SSL working only on the CHECKOUT page but clearly there is a FONT issue. http://vape20.com only if you get to the checkout page though it happens across the top! Thanks!

    • http://snippets.webaware.com.au/ Ross McKay

      the support forum is over there, not here on this blog :)