How to Set up Multisite WordPress Behind an Apache Reverse Proxy with New LetsEncrypt SSL Certs: Changing URLs

This article explains how to fix a redirect infinite loop problem that happens on the wp-admin login. It also explains how to set up WordPress multisite backend and Apache reverse proxy frontend with SSL/TLS certificates from LetsEncrypt.

I’ll get to the config changes below, but the fix for the bug is simple.

WordPress Admin Login Redirects Forever on Server Behind Reverse Proxy with https

The problem is that the communication between the reverse proxy and wp is http, not https. The answer was found here:

https://serverfault.com/questions/955110/wp-admin-redirect-loop-when-behind-apache-reverse-proxy/955471#955471

The fix is to add:

$_SERVER['HTTPS'] = 'on';

to wp-config.php.

Maybe there’s a way to detect if HTTPS is being used on the proxy, and then transmit that information back to the application, but this works for now.

Once you do this, you need to make sure the site prefers https over http, because the config says it’s SSL/TLS all the way.

Multisite Issues

With a multisite configuration there’s a primary site and subsites.

Subsites are easy to reconfigure, but the primary site is a pain to configure. You’ll need to use a mysql client and change some values in the database.

Before we do that, however, you can get certificates from LetsEncrypt.

Using Certbot to Make LetsEncrypt Certs for Apache VirtualHosts with Multisite WordPress

Install LetsEncrypt according to their instructions, but don’t make certs yet.

https://certbot.eff.org/

The best way to set up Apache VirtualHost for Multisite WordPress is to create only one VirtualHost section, and use ServerName and ServerAlias to identify the host. Here’s part of my config on the Docker container that serves the site:

<VirtualHost *:80>
    DocumentRoot /opt/docker/apache/www/technote.fyi/public
    ServerName technote.fyi
    ServerAlias riceball.com
</VirtualHost>

My "network" is just some Docker containers, not a real network.

On the reverse proxy, which is on the host, my config is like this:

<VirtualHost 216.240.146.66:80>
    ServerName technote.fyi
    ServerAlias riceball.com
    ProxyPreserveHost on
    ProxyPass "/" "http://172.16.238.1:9876/"
</VirtualHost>

That config covers only HTTP.

What it does is proxy requests for this domain to the server 172.16.238.1:9876, which was configured above. Over on the 172.16.238.1:9876 server, it determines the VirtualHost to use based on the Host header, which is passed to it because ProxyPreserveHost was on.

So, the setup is simple: a request for http://technote.fyi/ matches the VirtualHost on the proxy, and the request is forwarded to 172.16.238.1:9876, where it matches the VirtualHost, again.

LetsEncrypt Certs Should Be Arranged the Same Way as WP Multisite

LetsEncrypt site certs can apply to more than one domain. So you can create a single cert for all your domains.

However, this can get a little confusing, so I set up one cert per Multisite WP installation.

Each cert verifies the primary and subsite domains.

You create it with this command, as root. (Don’t use my domain!):

certbot --apache -d technote.fyi

You use your own domain, of course. The command will alter your Apache configuration and create a VirtualHost for this domain. Double check its work. What it does is copy your existing configuration, set the port to 443, and then add three lines pointing to the cert.

To add domains to the certificate:

certbot --cert-name technote.fyi -d technote.fyi,riceball.com

The VirtualHost on the reverse proxy matches all those domains, and the cert applies to all those domains.

Make Changes in Network Admin

Go back to WordPress’s admin, and go into the Network Admin menu.

Edit all the sites.

For each subsite, fix the URL, so it starts with "https" instead of "http".

You will notice that you cannot change the URL of the primary site.

Makes Changes in the MySQL Database

To change the URL in the primary site, you need to change three rows. One is in wp_sitemeta, and two are in wp_options.

wp_sitemeta

The first row is in the wp_sitemeta table. Look for it with:

mysql> select meta_key,meta_value from wp_sitemeta where meta_key='siteurl';
+----------+-----------------------+
| meta_key | meta_value            |
+----------+-----------------------+
| siteurl  | http://technote.fyi/ |
+----------+-----------------------+
1 row in set (0.01 sec)

To change that value, run this query:

update wp_sitemeta set meta_value='https://technote.fyi/' where meta_key='siteurl';

Use your own URL, of course.

wp_options

There are at least two URLs to change. To find them:

select * from wp_options where option_value like 'http%';

The option names that you must change are site url and home. If you find other URLs, you might want to alter those as well.

Issue commands like this – you are just changing the "http" to "https":

update wp_options set option_value='https://technote.fyi/' where option_name='siteurl';
update wp_options set option_value='https://technote.fyi/' where option_name='home';

If you turned up the wrong URL, it’s possible that the primary site was changed. You will need to search and update in other tables.

The WordPress Multisite table names use this convention %prefix%%blog_id%_tablename. The options table will have names like this:

wp_options
wp_2_options
wp_3_options

You can discover the blog IDs with this query:

select * from wp_blogs;