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

WordpressAmazon Web-ServicesAmazon Ec2HttpsAmazon Elb

Wordpress Problem Overview


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.

Wordpress Solutions


Solution 1 - Wordpress

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 - Wordpress

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 - Wordpress

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 - Wordpress

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 - Wordpress

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.

Solution 6 - Wordpress

My Server Environment is: Ubuntu 20.04.3 LTS, PHP 8.0.11, nginx/1.18.0

The following settings in /etc/nginx/sites-available/default worked for me:

server {

    listen 80;
    listen [::]:80;
    root /var/www/html;
    index  index.php index.html index.htm;
    server_name ChangeDomainName.com www.ChangeDomainName.com;

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

    location / {
            try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php8.0-fpm.sock;
            if ($http_x_forwarded_proto = 'https') {
                set $fe_https 'on';
            }
            fastcgi_param HTTPS $fe_https;
            fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionA.B. CarrollView Question on Stackoverflow
Solution 1 - WordpressA.B. CarrollView Answer on Stackoverflow
Solution 2 - WordpresszeroimplView Answer on Stackoverflow
Solution 3 - WordpressGal TalmorView Answer on Stackoverflow
Solution 4 - WordpressAnkit AnandView Answer on Stackoverflow
Solution 5 - WordpressMikeView Answer on Stackoverflow
Solution 6 - WordpressMuhammad Abu ul FazalView Answer on Stackoverflow