Dockerize and Secure WordPress


I dockerized and secured, using SSL, my WordPress Blog in one swing! Looking at your address bar you should see a shiny lock symbol.

WordPress Docker

I mainly wanted to protect my WordPress admin login but on the other hand also add some privacy in general.
Secondly moving my blog to a WordPress Docker container helped me to better understand container and also will give me great flexibility to easily move the blog to a different host and update.

This post should guide you to achieve a similar goal.

Install WordPress using Docker

I used the official WordPress Docker image from Docker Hub. The installation is quite straight forward and only need three commands.

First of all we are creating a data-only container which will persist our mysql database and also the WordPress wp-content directory in which all of the user data (plugins, media, themes…) is saved. Separating the use data from the database and WordPress container allows us to easily update the environment. I’m leveraging a Debian Jessie image for that.

Next we are starting the official MariaDB docker image, a community-developed fork of MySQL, using the /var/lib/mysql directory from the data only container. The MariaDB root password will be set via an environment variable called MYSQL_ROOT_PASSWORD

The third and final command will start the WordPress container. This container needs to be linked to the MariaDB container and leverage the wp-content directory from the data only container. Finally the VIRTUAL_HOST environment variable is required for the nginx reverse proxy.

# creat data only container for database and wp-content
sudo docker run -d -v /var/lib/mysql -v /var/www/html/wp-content --name wordpress1_data debian:jessie

# start mariadb container
sudo docker run -d --restart=always --name wordpress1_mariadb --volumes-from wordpress1_data -e MYSQL_ROOT_PASSWORD=Passw0rd123 mariadb

# start wordpress container
sudo docker run -d --restart=always --name wordpress1 --volumes-from wordpress1_data --link wordpress1_mariadb:mysql -e VIRTUAL_HOST=blog.domain.com wordpress

If you want to access the WordPress container directly, not using a reverse proxy, you need forward the port with following parameter: -p 80:80.

Add nginx reverse proxy

To be able to run multiple different sites using one (public) IP does require a reverse proxy. Jason Wilder created a very nice project called nginx-proxy that makes this very easy. You only need to specify an environment variable called VIRTUAL_HOST when you’re launching a container. Nginx-proxy does monitor the docker service and will automatically update the nginx configuration.

# start nginx reverse proxy
sudo docker run -d --restart=always --name nginx-proxy --security-opt=label:type:docker_t -p 80:80 -p 443:443 -v /home/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

Secure WordPress with SSL Certificates

To secure your WordPress Blog you will need a SSL certificate.
For development and testing you can simply create your own self-signed certificates with following command.

# create self-signed certificates for nginx
sudo openssl req -x509 -nodes -days 730 -newkey rsa:2048 -keyout blog.domain.com.key -out blog.domain.com.crt

For your production WordPress installation you should really use a certificate from a public certificate authority. Otherwise will your visitors be scared by a big red warning! They don’t like that! 😉
I used for my blog a free certificate from StartSSL. These certificate are free for non commercial uses and are valid for one year. Only revoking a certificate does cost a fee. In the future CAcert will also be an option but currently they lack support for their root certificate in all major browsers.

The private key (“*.key”) and the public certificate (“*.crt) need to match your domain, that you specified with “VIRTUAL_HOST” when starting the WordPress container. The files need to be copied into the folder that is mapped to nginx-proxy. In my case are the certificates stored in /home/certs. If your nginx container was running, please restart with sudo docker restart nginx-proxy

For StartSSL you need to decrypt and reformat the private key with following command:

openssl rsa -in blog.domain.com.key -out blog.domain.com.key

For the StartSSL Free certificate, and maybe other authorities, you need to add the intermediate CA certificate to your personal certificate. This is for example necessary for Firefox support.

wget http://www.startssl.com/certs/sub.class1.server.ca.pem
# your personal certificate has to be the first one
cat blog.domain.com.crt sub.class1.server.ca.pem > blog.domain.com.crt.new
mv -f blog.domain.com.crt.new blog.domain.com.crt

Migrate WordPress

Migrating your “old” WordPress installation to your new docker environment should be done in three steps:

  1. Make a backup of your running installation using UpdraftPlus and import the backup into your dockerized WordPress.
  2. Update your WordPress Address (URL) and Site Address (URL) to reflect the change to https.
  3. Update all static links on your blog to use “https”. This can be accomplished by a plugin called Velvet Blues Update URLs. Enter your blog URL in the “Old URL” field with http and in the “New URL” field with https.  Check all boxes beside the “Update ALL GUIDs” and hit “Update URLs NOW”

If everything worked is your Blog now dockerized and secured!

Update WordPress

Updating your WordPress installation is very simple and similar to installing WordPress. The only difference is that you don’t recreate your data-only container hosting the database and wp-conten directory:

# stop the wordpress, mariadb and nginx container
sudo docker stop wordpress1 wordpress1_mariadb nginx-proxy

# delete wordpress, mariadb and nginx container
sudo docker rm wordpress1 wordpress1_mariadb nginx-proxy

# start new wordpress, mariadb and nginx container
sudo docker run -d --restart=always --name wordpress1 --volumes-from wordpress1_data --link wordpress1_mariadb:mysql -e VIRTUAL_HOST=blog.domain.com wordpress
sudo docker run -d --restart=always --name wordpress1_mariadb --volumes-from wordpress1_data -e MYSQL_ROOT_PASSWORD=Passw0rd123 mariadb
sudo docker run -d --restart=always --name nginx-proxy --security-opt=label:type:docker_t -p 80:80 -p 443:443 -v /home/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

Backup WordPress

Beside continue using UpdraftPlus you can also backup your data-only container from time to time.

# make a backup of the container volumes from wordpress1_data to your current directory
sudo docker run --rm --security-opt=label:type:docker_t --volumes-from wordpress1_data -v $(pwd):/backup debian:jessie tar cvf /backup/wordpress1_data.tar /var/lib/mysql /var/www/html/wp-config

# create a new data only container for database and wp-content
sudo docker run -d -v /var/lib/mysql -v /var/www/html/wp-content --name wordpress1_data debian:jessie

# restore backup
sudo docker run --rm --security-opt=label:type:docker_t --volumes-from wordpress1_data -v $(pwd):/backup debian:jessie tar xvf /backup/wordpress1_data.tar -C /

Lastly do the same steps described in “Update WordPress”


Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

8 thoughts on “Dockerize and Secure WordPress