Securing the Default WordPress Container on Cycle

In my last post, we went through the process of deploying a basic WordPress instance on Cycle. It was easy to set up and deploy and required almost zero customization. However, due to the way the default WordPress image is configured on Docker Hub, it isn’t possible to enable TLS/SSL encryption without doing some modifications. Since this is a bit more advanced, I’ve separated it into its own post.

We’ll start by building on top of the default Docker image, making a couple modifications to some Apache files, and re-uploading to Docker Hub before finally deploying on Cycle. If you’re just interested in the end result, I’ve pushed an image maintained by Cycle that is ready to go. Just follow along with my previous post, but instead of importing a wordpress image, import cycleplatform/wordpress .

Modifying the Default WordPress Image

If you haven’t already, head over to and set up their command line program. We’ll be using it to build/upload our container image. Our goal with this new container is to build on top of the existing image, but alter Apache config files so that they know how to use our TLS/SSL certificates. Cycle automatically handles renewal and installation of those certificates, so most of the hard work is done. We’ll copy the files out of the existing installation and inject our modified Apache config instead.

Open up your terminal and point it to an empty working directory. The first thing we need to do is get the default WordPress container image:

docker pull wordpress

That will automatically download the latest tagged version of the default WordPress image for us. Since that could take a couple minutes to download depending on your internet speed, use this time to open up your favorite text editor to the working directory (I use VSCode).

We need to modify a couple config files in the container image to enable SSL . Unfortunately we can’t just pull them out of the image, we actually need to run the container first.

docker run --name wp --rm -d wordpress

That will start the container up in the background, allowing us to “dial in”. Next, we need to pull out the relevant files into our working directory.

Note: If you are using Windows Subsystem for Linux you will need to remove sudo from the commands below.

sudo docker cp wp:/etc/apache2/sites-available/default-ssl.conf . sudo docker cp wp:/var/www/html/.htaccess .

These two commands reach into our running container and pull out the files we plan to modify. If you type ls -a you should see the two files listed.

Don’t forget to kill the container so it’s not left as a ghost eating up resources:

docker kill wp

Set TLS Certificate Paths

The first modification will be updating the default-ssl.conf file to point to our Cycle-installed certificates. Open it up in your editor and find and modify the following lines to:

SSLCertificateFile /var/run/cycle/tls/current.crt
SSLCertificateKeyFile /var/run/cycle/tls/current.key

SSLCertificateChainFile /var/run/cycle/tls/current.chain*

Notice the SSLCertificateChainFile. By default it has a # in front of it. Be sure to remove the #.

Technically, you can set /var/run/cycle/tls to whatever directory you prefer, but that is what Cycle defaults to. If you do change it, remember to match it on the container deploy form as well.

The platform installs two copies of each certificate file. One called current (i.e. current.key), so that you do not need to know the domain or anything, and one that matches the domain set to the container (i.e

Enable HTTPS Redirect

The final modification we need to make forces all regular traffic to be redirected to a secure version of the site. Open up .htaccess in your text editor and copy it to match the following:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{HTTPS} off
RewriteRule ^(.*)?$ https://%{HTTP_HOST}/$1 [R=301,L]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

The rule we added tells Apache that any matching URL gets redirected to the same URL, but with https:// in front.

Package It Up!

The last thing we need to do is containerize this bad boy and push it up to Docker Hub so we can deploy it on Cycle.

We need a Dockerfile to tell Docker how to build our image, so make one now:

touch Dockerfile

Open it up and paste the following into it:

FROM wordpress:latest

COPY default-ssl.conf /etc/apache2/sites-available
RUN ln -s /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf

COPY .htaccess /var/www/html

RUN ln -s /etc/apache2/mods-available/ssl.load /etc/apache2/mods-enabled/ssl.load

RUN ln -s /etc/apache2/mods-available/ssl.load /etc/apache2/mods-enabled/ssl.load

RUN ln -s /etc/apache2/mods-available/socache_shmcb.load /etc/apache2/mods-enabled/socache_shmcb.load


Let’s break it down so every line’s purpose is clear.

FROM wordpress:latest

Our image is based on the wordpress:latest image, and this says our modifications will just be another layer on top of the base image.

COPY default-ssl.conf /etc/apache2/sites-available

This is pretty straightforward. This copies in our modified default-ssl.conf.

RUN ln -s /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf

ln -s creates what is called a symlink . It is an alias, and basically it means the file name on the right just links back to the file on the left. We are moving it into the sites-enabled folder, so now our default-ssl.conf file is ‘active’.

COPY .htaccess /var/www/html
RUN ln -s /etc/apache2/mods-available/ssl.load /etc/apache2/mods-enabled/ssl.load

We copy in our .htaccess file into where the WordPress volume is mounted. Luckily for us, in the init script for this image, it checks to see if there is a .htaccess so it doesn’t override it meaning our changes will persist.

RUN ln -s /etc/apache2/mods-available/ssl.load /etc/apache2/mods-enabled/ssl.load

RUN ln -s /etc/apache2/mods-available/ssl.conf /etc/apache2/mods-enabled/ssl.conf

RUN ln -s /etc/apache2/mods-available/socache_shmcb.load /etc/apache2/mods-enabled/socache_shmcb.load

We create three more symlinks, enabling the SSL Apache module + its configuration file, and we enable the session caching module for speedier delivery.


TLS is served over port 443, so we need to let our container know to allow that traffic in.

Now, let’s build it. Be sure to change the [YOUR_DOCKERHUB_NAME] to your own account.

docker build -t \[YOUR_DOCKERHUB_NAME\]/wordpress .

To The Cloud!

Once your image is done building, it’s time to push. I’m pushing mine to Docker Hub but feel free to host your own private registry on Cycle as well. You will probably need to log in as well if you haven’t already.

docker login
docker push [YOURDOCKERHUBNAME]/wordpress

That’s it! Our image is ready for us to import and use in Cycle. Go ahead and follow my previous post, but instead of using the default wordpress image, use your new, secure one instead (or just cycleplatform/wordpress ).