WordPress uses the is_ssl() function to determine if SSL is being used in the server. In order to do this, it uses $_SERVER['HTTPS'] and $_SERVER['SERVER_PORT'] to check if they are set. The problem when you use a reverse proxy, like in almost all the installations I run, is that Apache serves the content in HTTP trough port 80 inside a Docker container, then Caddy Server manages the HTTPS connection to the outside world.

Because this, WordPress is not aware of the SSL context and the visitor sees the classic “Could not open the page, too many redirects.”. Is what happened to one of my instances in Alicloud.

 

What is Caddy, anyway?

According to their website, Caddy is the only web server that uses HTTPS by default. A hardened TLS stack with modern protocols preserves privacy and exposes MITM attacks. Written in Go, Caddy binaries are entirely self-contained and run on every platform, including containers. You don’t even need libc.

Caddy reverse proxy server logo saying "Every site on HTTPS"

Caddy Server

 

Wait, you talk about reverse proxy and Docker. I’m lost

Wikipedia says that a reverse proxy is a type of proxy server that retrieves resources on behalf of a client from one or more servers. These resources are then returned to the client as if they originated from the Web server itself. Contrary to a forward proxy, which is an intermediary for its associated clients to contact any server, a reverse proxy is an intermediary for its associated servers to be contacted by any client.

The image shows how a reverse proxy works.

Reverse proxy

Quite often, popular web servers use reverse-proxying functionality, shielding application frameworks of weaker HTTP capabilities.

 

The Solution to make WordPress work with Reverse proxy

It should be part of your deployment process to include your wp-config.php file. So, add the following code as high of the file as you can:

/**
 * For WordPress, force the protocol scheme to be HTTPS
 * when is_ssl() doesn't work, e.g. on a reverse proxied server
 * where _SERVER['HTTPS'] and _SERVER['SERVER_PORT'] don't
 * indicate that SSL is being used.
 */if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
    $_SERVER['HTTPS'] = '1';

if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}

Et voilà, WordPress should work now!