How to fix WordPress HTTPS issues when behind an Amazon Load Balancer?

33,607

Solution 1

Like the link, you gave suggested, for WordPress the issue lies in the is_ssl() function, which like most PHP software explicitly checks the $_SERVER['HTTPS'] and $_SERVER['SERVER_PORT'] to check if the current page is being accessed in the https:// context.

When your page is accessed over HTTPS, but the Amazon Load Balancer is performing SSL offloading and actually requesting your content on the non-SSL port 80, the webserver, PHP, or anything else for that matter, does not understand or see that it's being accessed over https://.

The fix for this is that Amazon's ELB sends the de-facto standard X-Forwarded-Proto HTTP header, which we can use to figure out which protocol the client is actually using on the other side of the Load Balancer.

With Apache 2.2, you could use something along the lines of:

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

This simply reads the X-Forwarded-Proto header. If this value equals https then the HTTPS environment variable is set to 1. PHP will see this environment variable, and eventually, it will become $_SERVER['HTTPS'] that equals 1 -- just like it would be for a "real" native SSL request.

Solution 2

Another option from the WordPress documentation is to add this to your wp-config.php:

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

Solution 3

In case anyone else was looking for the Nginx equivalent to this, here's what you need to do:

For rewrite setup you should add the following under the server block:

if ($http_x_forwarded_proto != 'https') {
    rewrite ^ https://$host$request_uri? permanent;
}

And for setting the HTTPS param you should add the following under the location ~ \.php$ block:

if ($http_x_forwarded_proto = 'https') {
    set $fe_https 'on';
}
fastcgi_param HTTPS $fe_https;

Remember to remove any other fastcgi_param HTTPS command if you have any (I had it in my fastcgi_params file).

Solution 4

Use this 4 step method to remove the redirect loop and mixed content problems when using ssl in WordPress.

1) Replace 'http://' with '//' in database - This create all the relative url's for images and other assets

2) in wp-config, define generic wp_home and wp_siteurl variables.

define('WP_HOME','//'. $_SERVER['SERVER_NAME']);
define('WP_SITEURL','//'. $_SERVER['SERVER_NAME']);

3) If you are using load balancer, use 'HTTP_X_FORWARDED_PROTO' server variable to figure out protocol used. To do this, add this line in wp-config

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

4) Finally in .htaccess, use this line if you are behind loadbalancer to redirect all traffic to https.

 # http to https
 RewriteCond %{HTTP:X-Forwarded-Proto} =http
 RewriteRule . https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]

Solution 5

Neither of the above solved the Mixed Content errors for me unfortunately. However what did work was adding the protocol to the WP_HOME && WP_SITEURL variables in wp-config.php e.g.

define( 'WP_HOME', 'https://' . $_SERVER['HTTP_HOST']); define( 'WP_SITEURL', WP_HOME );

After that all URLs in the source began with https and all the Mixed Content errors disappeared.

Share:
33,607
A.B. Carroll
Author by

A.B. Carroll

Father, Husband, and Software Developer from the Mississippi Hill Country. I live and breathe development of most languages with a soft spot for PHP. I am particularly interested in programming language design and development, high performance and high availability software solutions, and solving complex problems with simple and novel solutions.

Updated on July 09, 2022

Comments

  • A.B. Carroll
    A.B. Carroll almost 2 years

    I've had this issue before. When running WordPress (or other PHP scripts) behind Amazon's EC2 Load Balancer, the scripts do not realize they are being ran on the https:// protocol and results in issues such as endless redirect loops, and HTTPS warnings ("Some content on this page is being requested in a non-secure way...").

    I found a solution here, but requires modifying WordPress core, which is no good for updatability: https://wordpress.org/support/topic/when-behind-amazon-web-services-elastic-load-balancer-causes-endless-redirect

    Is there a way to fix this without modifying WordPress core? I am using Apache 2.2.

  • Matt Winer
    Matt Winer over 7 years
    This is the method I used. Any idea how to force people to HTTPS if they access the page via HTTP?
  • zeroimpl
    zeroimpl over 7 years
    You could try adding force_ssl_content(true); to the wp-config.php as well. Normally I would do that via an Apache rewrite rule or in the load balancer config though.
  • Diana
    Diana about 7 years
    Works fine, you need to make sure you've enabled the apache2 module setenvif.
  • Paté
    Paté over 6 years
    You saved my butt in production! Cheers!
  • Gal Talmor
    Gal Talmor over 6 years
    Glad to help. Cheers :)
  • sebge2
    sebge2 over 6 years
    simply added to the apache configuration (image from bitnami) and it works.
  • djsadinoff
    djsadinoff over 6 years
    Note that many proxy situations use X-Forwarded-Scheme in a synonmous fashion. Generally safe to set both.
  • Action Dan
    Action Dan about 6 years
    @MattWiner if you're using AWS ELB, you need to configure a separate listener on port 80, route that through to your EC2 server on another port (81 for example) and there do a url rewrite to redirect any requests to the HTTPS version of the original URL. Then the web browser will request the HTTPS url instead.
  • emmdee
    emmdee over 5 years
    On your step 1, where in the database?
  • Jeremy
    Jeremy over 5 years
    Works on Apache2.4 as well
  • ejazazeem
    ejazazeem over 5 years
    Simple and clean solution +1. Worked for my WordPress site serving on HTTP behind AWS load balancer, which has SSL enabled.
  • wkhatch
    wkhatch about 5 years
    you can now configure redirects from http to https on the application load balancer directly
  • Amirul
    Amirul almost 5 years
    This solution could be pointed out the ELB from port 443 to 80
  • Tan Jia Ming
    Tan Jia Ming about 4 years
    This answer works best for me because it doesn't only just work on Wordpress, it works on Laravel as well.