WordPress SSL (https) and Reverse Proxy (Nginx, Apache httpd)

As you can see, this blog is accessible through SSL (https) encryption only. Normally this is not a huge problem but Wordpress is a little bit clunky if it comes to a setup that also includes a reverse proxy.

General

The following text is a sum up some pages which can be found on the internet but often lacks information. This Wordpress blog that you are currently reading is running on an Apache httpd on localhost. In front of it, there is a second Apache httpd which acts as reverse proxy for different tasks. One of these tasks is to offload SSL (https) encryption.

Wordpress installation

In the described setup you should first install the Wordpress software on http (port 80) without SSL. If you enable SSL at this time chances are good that you end up in a redirect loop.

Configure SSL (https)

On the reverse proxy configure SSL as usual but be aware, that you have to set RequestHeader set X-Forwarded-Proto "https" inside the SSL virtual host! This information is important as otherwise the URL's generated by Wordpress will be http links and therefore you will get browser warnings later. Do not force a permanent redirect from http to https at this point or you will not be able to install the necessary Wordpress plugin which take care on your URL's. After you have enabled basic https support install the Wordpress extension SSL Insecure Content Fixer and configure it to use the X-Forwarded-Proto header. Afterwards you have to modify the wp-config.php to reflect this settings. If you want use Jetpack, you also have to specify SERVER_PORT otherwise you will receive a error message on wordpress.com during the configuration of your social media connections (There was an error retrieving your site settings.). You also have to force admin SSL usage. Hopefully this will help some people out there to get this up and running. If this config does not help you, leave a comment! -M

Apache http reverse proxy config

<VirtualHost ${IP}:443>
        ServerName  n0r1sk.com
        ServerAlias www.n0r1sk.com

        ErrorLog ${APACHE_LOGS}/n0r1sk.com.error.log
        TransferLog ${APACHE_LOGS}/n0r1sk.com.access.log

        ProxyPreserveHost on
        RequestHeader set X-Forwarded-Proto "https"

        SSLEngine on
        SSLHonorCipherOrder on
        SSLProxyVerify none
        SSLProxyCheckPeerCN off
        SSLProxyCheckPeerName off
        SSLProxyCheckPeerExpire off
        SSLProtocol ALL -SSLv2 -SSLv3
        SSLCipherSuite "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"
        SSLCertificateFile "ssss"
        SSLCertificateKeyFile "ssss"
        SSLCertificateChainFile "ssss"

        <Location /server-status>
                SetHandler server-status
                Order Deny,Allow
                Deny from ALL
        </Location>

        ProxyPass /server-status !

        ProxyPass / http://127.0.0.1:8880/
        ProxyPassReverse / http://127.0.0.1:8880/
</VirtualHost>

<VirtualHost ${IP}:80>
        ServerName  n0r1sk.com
        ServerAlias www.n0r1sk.com

        Redirect permanent / https://www.n0r1sk.com/
</VirtualHost>

Nginx reverse proxy (in an Docker environment)

<VirtualHost ${IP}:443>
worker_processes auto;

events {
  worker_connections  4096;
}

http {
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 5m;
    ssl_prefer_server_ciphers on;

    server_tokens off;

    log_format basic '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';

    upstream n0r1sk_wp {
        hash $remote_addr;
        server tasks.n0r1sk_wp_app:80;
    }

    server {
        listen 443 ssl http2;
        server_name n0r1sk.com www.n0r1sk.com;

        ssl on;
        ssl_certificate ;
        ssl_certificate_key ;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA
256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;

        error_log /var/log/nginx/n0r1sk_error.log info;
        access_log /var/log/nginx/n0r1sk_access.log basic;

        location / {
                sendfile off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-Host $host;
                proxy_set_header X-Forwarded-Server $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-Proto $scheme;

                proxy_pass http://n0r1sk_wp;
        }
    }

    server {
        listen 80;
        server_name n0r1sk.com www.n0r1sk.com;

        return 302 https://$server_name$request_uri;

        error_log /var/log/nginx/n0r1sk_error.log info;
        access_log /var/log/nginx/n0r1sk_access.log basic;
    }
}

Wordpress wp-config.php

define('FORCE_SSL_ADMIN', true);
$_SERVER['SERVER_PORT'] = 443;