I’ve finally taken more of a dip into docker than “docker run hello-world”.
If you haven’t heard of docker before (I don’t judge!) here’s what Docker.com says:
Docker is a platform for developers and sysadmins to develop, deploy, and run applications with containers. The use of Linux containers to deploy applications is called containerization. Containers are not new, but their use for easily deploying applications is.
My requirements are pretty simple. Someone mentioned a thing called “WordPress” on the weekend which is, apparently, a thing.
Spoiled by a first look with an AWS marketplace image I wanted to get the shiniest, bells and whistles version of WordPress going on my permanent server. Boo! My server is running Ubuntu 16.04 – and its idea of modern packages leaves a bit to be desired.
To the rescue comes a WordPress docker container – which bundles in all the prerequisites that would be a pain to get going on 16.04.
I already have an Apache web server, Postfix mail server and MariaDB database server, so I just needed to spin up the container and wire it in to the existing services.
Simple right? And see how nicely the arrows extend the stick figure legs – it’s stilt walking day.
It works like this:
- Browser contacts the Apache server
- Apache terminates the SSL connection and proxies request over HTTP to the WordPress container (on port 8080)
- The WordPress container does its thing (pulling content from the existing (non-docker) MariaDB server, and the page is returned by Apache.
Data persistence
WordPress inside a container works nicely, but if we want the uploaded content and any changes to configuration files to persist across container starts it has to have some persistent storage.
After creating a folder for the html content we can expose it to the container with “-v /var/lib/docker/datadir/wp-testingtesting/html:/var/www/html”
Networking and Security
The default network connectivity for a container is to use a bridged docker network. For simplicity I used –add-host to put a “dockerhost” entry in the container’s host resolution file:
docker container run --add-host dockerhost:172.17.0.1 ...
My Postfix allows connections from anywhere (it hosts my domain, so needs to accept mail). As the bridged docker subnet doesn’t use the local address range Postfix won’t let it relay – which is fine for now, and easily fixed by adding to the Postfix main.cf if/when I open registration/subscription from the internet.
... ErrorInfo: SMTP Error: The following recipients failed: [email protected]: : Relay access denied Host: dockerhost Port: 25
MariaDB did need some changes, it was only listening on the loop back address (127.0.0.1). A simple change to listening on 0.0.0.0 (so mariadb would listen on all addresses) and then inserting a firewall rule allowing connections from the docker0 interface got it going:
iptables -I INPUT -i docker0 -p tcp -m state -m tcp --dport 3306 -j ACCEPT
Reverse proxy
The reverse proxy (Apache) was more troublesome – mainly because of WordPress.
I put in a site file to answer the SSL and forward to http://127.0.0.1:8080. I’ll leave the forwarding of HTTP to the HTTPS site as an exercise for the reader.
<IfModule mod_ssl.c> <VirtualHost _default_:443> ServerName testingtesting.net SSLCertificateFile /etc/letsencrypt/live/mycert/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/mycert/privkey.pem ProxyPass "/" "http://127.0.0.1:8080/" ProxyPassReverse "/" "http://127.0.0.1/" ProxyPreserveHost On </VirtualHost> </IfModule>
That all looks right, so why was WordPress responding with bizarre redirections like http://127.0.0.1 or even http://testingtesting.netwp-admin/…
It turns out that WordPress really, really doesn’t handle reverse proxy, and doesn’t cope with HTTPS termination well either. A few lines of PHP added at the start of wp-config.php gave WordPress enough context to return pages with the right redirections. I’m still pertty disappointed that it’s using absolute links which include the site path, but there’s probably an exceptionally good reason…
Prepended to wp-content.php :
<?php define('WP_HOME','https://testingtesting.net/'); define('WP_SITEURL','https://testingtesting.net/'); $_SERVER['HTTP_X_FORWARDED_PROTO']='https'; $_SERVER['HTTPS'] = 'on'; ?>
Voila!