3

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.

  • 1
    I would just get rid of Apache; it's entirely redundant here. – Michael Hampton Oct 12 at 17:19
  • As far as I can see, your main issue with option 1 is the browser requesting unsecured content when everything should be secured, from the point of view of the browser. That should be solved with the Strict Transport Security header, which, being served at first place, tells the browser to request every content in a secure manner. You could configure NGINX for that. – Xtreme Biker Oct 13 at 12:58
  • @MichaelHampton it might well be true, but I'm just afraid to get into elaborate migration process, with all the php extensions and database configurations and what not. I'm just looking for the simplest way. – Passiday Oct 14 at 19:07
  • @XtremeBiker that would just make the site inaccessible, as it is now. – Passiday Oct 14 at 19:08
  • 1
    The simplest way is to do nothing. Obviously you won't do that. But remember you also have to change the URL in WordPress's settings. – Michael Hampton Oct 14 at 19:08
3

You should be able to tell Apache that the incoming request is being proxied from a HTTPS request with the proxy_set_header X-Forwarded-Proto "https"; declaration in the first setup

| improve this answer | |
  • 1
    Completely true with the addendum that the website/application (code) on Apache then still needs to do something based on the presence of that header (For example generate https URI’s rather than http ) – HermanB Oct 12 at 13:56
  • Thank you, this is an important thing to learn. I will definately check, but I am not too hopeful that this poorly maintained site respects the value of this header. – Passiday Oct 12 at 15:05
3

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.

| improve this answer | |
1

Normally I would prefer to do all the heavy lifting on the reverse proxy and keep the backend site that gets exposed as original as possible.

Your problem seems to be in essence that the (WordPress) backend generates and uses (absolute) URI’s that differ from what you want visitors to use.

You can remedy that by rewriting the (HTML) content that WordPress generates in nginx with the ngx_http_sub_module. That will also allow you to rewrite absolute URL's with something similar to:

    location / {    
         sub_filter 'http://example.com/' 'https://www.example.com/' ;
         sub_filter 'http://www.example.com/' 'https://www.example.com/' ;
         sub_filter_once off;
         proxy_pass       http://Apache2-PHP5.6:80;
         proxy_set_header Host            $host;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;                
    }
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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