Nginx – Turning an Apache http site into secure https site via Nginx reverse proxy

apache-2.4dockernginxssl

I have to support an old WordPress site running on Apache web server. To make things safer, this Apache server is in a Docker container, and it is accessible to the world via Nginx reverse proxy configuration. This site is currently served via http, and I'd like to move it to https.

I think I have two options:

  1. The SSL certificate is installed for the Nginx site, and it does proxy_pass to the plain http site on Apache container:

    server {
        listen      443 ssl;
        server_name www.example.com;
    
        ssl_certificate /etc/nginx/ssl/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/letsencrypt/live/www.example.com/privkey.pem;
    
        access_log  /var/log/nginx/example.com.access.log;
    
        location /  {
            proxy_pass       http://Apache2-PHP5.6:80;
            proxy_set_header Host            $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         }
    }
    

    In this scenario from the viewpoint of Apache server, it is still serving the site over http

  2. This is more laborous: the SSL certificate is installed on both the gateway Nginx server, and the proxied Apache site. Then it would be needed to change http to https in the proxy_pass config value.

I wish all was fine with the 1st scenario. But the fact that Apache feels it is serving stuff over http introduces some problems: there are some hidden URL redirects that I'd really like not to reconfigure/debug. And those URL redirects do something like this: if the requested URL is http://www.example.com, it is rewritten (http status 301) as http://www.example.com/main. This redirect is received by the browser, and so, even though the first request was over https, now the redirected URL is http one. Also the sites html contains serveral full-path hrefs to it's own resources (JavaScript and CSS files) that include also the protocol reference. It is not clear at this point if those hrefs adopt the protocol from how the request was made, or it is hardcoded. Anyway, unfortunately this doesn't work without some serious digging in.

So, I am left with option 2. I tried, it works, I can set up the same SSL certificate on both Nginx and the containerized Apache. But I'd like to know if this is really how it should be left running. Because although the Apache server now knows that the content is being served over https, now there's double SSL-ing happening for every request. It doesn't feel right.

Best Answer

You can solve the problem in your option #1 (which, as you said, is a much better approach) by setting the HTTP_X_FORWARDED_PROTO in your nginx config with

proxy_set_header X-Forwarded-Proto $scheme;

and configuring WordPress to recognize it by appending this line to wp-config.php

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

See also Wordpress support article for a variation of this solution.