#2 Containerized WordPress: General troubleshooting and Migration

The docker compose should work out of the box. However this post should shed some light on common troubleshooting or problems which i encountered while preparing the images


I can’t upload any pictures or download plugins.

Independent of using containers a failed upload almost always means, that  the permissions aren’t set right. The PHP module of the webserver will handle uploads thus it needs the right permissions in the directory. The user under PHP is operating is ww-data:www-data and should be set accordingly. This could be achieved as so:

$ sudo chown -R www-data:www-data wp-content/
$ sudo chmod -R 755 wp-content/

You should know that www-data is just a name and is internally mapped to a UID and GID. This problem occured to me with the PHP-fpm module, where within the container the UID and GID of www-data was mapped to 82 however on my host system the UID and GID were 33. Every time PHP would like to write something within the mounted volume under the ID 82 it got denied from the Host. To treat this issue i changed the respective IDs in the Dockerfile.

Caddy doesn’t work anymore, restarts all the time.

This is a general problem when working with a Caddy container. If you have a domain name and specify it in your Caddyfile without any tls specific configuration, Caddy will automatically generate  a certificate from let’s encrypt for your site. However you are only limited to around 20 certificates per domain per week (see this post). Since containers are stateless every time you run the  Caddy container it will generate a new certificate until you hit the limit. That is also why i would suggest you to persist the certificates by mounting the responsible folders. Certificates are stored in the $HOME directory (/home/.caddy) of the Caddy container which you can again configure by passing an environment variable (CADDYPATH) to bend it to your needs.


I had another setup taken from medium which provided a solution around Caddy (v0.9), PHP(v5.6) and MySQL(v5.5).

Why PHP 7

PHP 7 is said to provide a performance boost in comparison to PHP 5 (see this article). Since we are working on a very tiny computer we want to take everything we can get. However PHP 7 was not compatible with MySQL 5.5 anymore which is why i automatically needed a newer version of MySQL as well. Since there was no MySQL 7 image for Raspberry Pi I decided to stick with MariaDB (v10.3.17) which can be used as a stand in.

Database migration

There was not much effort while migrating from MySQL 5.5 to MariaDB 10.3.17. I could just reuse the mounted /var/lib/mysql files meaning it was just a matter of changing image sources in the docker-compose receipt(however better be save and prepare a backup). After I run the MariaDB Container for the first time i had to update my database with the following command:

$ docker exec webservice_mariadb_1 sh -c 'exec mysql_upgrade -uroot -p"[myrootpassword]"' 

I guess because of the update, the hashed user passwords got all mixed up so that i had to update my WordPress admin password. To do so navigate into your MySQL container and run mysql:

$ docker exec -it webservice_mariadb_1 mysql -u root -p

My configured WordPress database is named blog and the user data is stored inside wp_users. You could reset all your users passwords to a default password “passw0rd” like this:

$ UPDATE blog.wp_users SET user_pass=MD5('passw0rd')

Note that the passwords inside this table are all hashed. For the initial password a MD5 hash is accepted  but will be transformed in a more secure hash by WordPress upon first login (source, 17.11.2019).

<<<#1 Installing WordPress on a Raspberry Pi with docker-compose in under 10 minutes

#1 Installing WordPress on a Raspberry Pi with docker-compose in under 10 minutes

Jumping to the meat and potato a short set of instructions are presented on how you can have a WordPress instance up and running in under 10 minutes on your Raspberry Pi.

Preperation / Prerequisite

To start off: what you want is a domain name. Since you will be hosting your Raspberry Pi from home and most likely will not have a static IP you also need to tell your domain provider about your changing IP. Luckily no-IP provides both a DDNS service and free domain names. My router also had an option to inform no-IP about my changing IP.

Also don’t forget to forward the ports 80 and 443 which will be incoming traffic to your website. If you are going bigger and get your own domain name you could configure Cloudflare as your nameserver. By establishing a CNAME link to your free domain name at no-IP your new domain name will automatically resolve to the dynamic IP address. An advantage using Cloudflare is, that as a content delivery network, it can cache your website. Additionally it also provides TLS certificates.

Now i assume you already managed all this and have your Raspberry with an installed OS, mine is Raspbian, ready to go .

Lets get started

First we need to install docker on our Raspberry Pi:

curl -sSL https://get.docker.com | sh

Now we want to install docker-compose. It helps us to run multiple containers with one configuration file.

sudo apt-get install docker-compose

We can now procceed to clone my repository

git clone https://gitlab.com/nm_hung93/dockerized-wordpress-on-raspberry-pi.git

For this setup i am using:

We could now configure the mount points of our docker-compose.yml. Per default they will be created in the same folder in which we cloned the repository.

It is possible to create a database when initiating the MariaDB container. This can be done through injected environment variables which we specify in /data/env_variables/env_file.

Now being still in the root folder we can download WordPress:

curl -sL http://wordpress.org/latest.tar.gz | tar --strip 1 -xz -C data/wp/www

Navigate to our WordPress installation folder and copy the wp-config-sample.php and edit it. If you are still in your root folder it should look like this:

cd data/wp/www/
cp wp-config-sample.php wp-config.php
nano wp-config.php
inside the wp-config.php file should be a line which looks like in this picture

Change the settings accordingly to our initiated database:

    • ‘database_name_here’ into blog
    • ‘username_here’ into UserX
    • ‘password_here’ into 123456
    • ‘localhost’ into mariadb

Save the file with CTRL+X and accept saving the file with Y.

Now we are all set. Navigate into our root folder and run docker-compose with

 docker-compose -f docker-compose.yml up -d
    • -f specifies the file
    • -d means detached meaning it runs in the background

The Console should look like this:

Now find the IP address of your Raspberry Pi for example with:

ip addr show

And look out for eth0 or wlan0 depending on your used network interface. Mine is We can now go to another machine inside our network and insert this IP address into our browser.

SUCCESS we did it

Now the next steps you could do are :

  • mount the folders to another directory
  • edit the Caddyfile such as commenting tls off, and replacing :80 with yourwebsite.com to actually serve your website
  • edit the /data/env_variables/mysql_credentials file to have more customized database credentials

<<< Previous: #0 Introduction to Docker and WordPress

>>> #2 Containerized WordPress: General troubleshooting and Migration

#0 Introduction to Docker and WordPress

A short introduction to Docker and WordPress including the underlying necessary services and how it will interact with each other.

Table of Contents:

1. What is Docker?KubeCon and CloudNativeCon Europe 2018 - Linux Foundation ...

Docker is an open source software and is utilized to bundle software into one container. So what are containers? You can imagine them as a very light version of Virtual Machines being really really fast to boot up. There is a lot more about that but for our understanding it will suffice.

If you shut down a container every data will be lost and by starting a new one the initial state of the image will be restored hence it’s stateless.

2. What is WordPress ?Wordpress - Free social media icons

WordPress is an open source content management system and has a huge community. There is a great variety of templates as a baseline to structure your site might it be a blog, website or e-commerce shop. You can expand the functionality through plugins making it both easy to use and maintain even without prior knowledge. If your requirements call for it you can also code your own templates and plugins.

3. What is behind WordPress?

To run WordPress you will need a Webserver which can “understand” PHP since this is the language WordPress is building on and a database which stores your data.

3.1. Caddy as a Webserver

Websites are just files on another computer which are processed to look good on your screen.  Those files will be served to you upon your request. The webserver is responsible to serve you the correct files. Common webservers are Apache Webserver or NGINX. However Caddy is also a very viable option. It is a lightweight webserver with automated TLS certification and a very easy to understand configuration. Although i did not work with any other webservers yet it was very easy for me to dive into Caddy. It can be downloaded under caddyserver.com/.

3.2. MySQL and MariaDB as database

With WordPress you don’t save every website in a single file. Every content you create, a blog post, website or category tag is saved into a database. WordPress then utilizes PHP to query the database and output the content onto the template hence it is a content management system.  WordPress officially supports the open source database management system MySQL. However you can also use MariaDB since it is a fork of MySQL and can be used as a stand in. There is some historical reason for this forking and although the developers of MariaDB try to synchronize with MySQL in the future some features might be different. For more read this blog post at blog.panoply.io.

3.3. PHP-FPM PHP,Free source code for the taking. Over five million ...

PHP is a scripting language and is usually a module which the server calls to interpret scripts on the server side to serve the output to the requested Client. Normally that module would sit on the webserver. However in the case of PHP-FPM the modules are implemented on a separate server. The webserver can then forward the PHP request to that separate module. This again brings the advantage of scalability. In our case it is not really necessary but just a nice practice to separate every service. A small advantage is that we can then update every component independently. It would come handy if you have a raspberry cluster and separate the PHP engine to another node. For further readings refer to hostek.com.

4. Important files of our WordPress installation

We finished defining our services . At this point i want to explicitly again draw attention to the statelessness of our containers. This means we have to “save” important data to our host system by mounting directories to the container (Telling the container it has to link a specific folder inside the container to a folder outside of the container. If files are getting saved into the folder inside that container it will automatically save them at the host file system). Important files will be:

    • database related data
    • wordpress including the installation, plugins, themes, etc…
    • caddy webserver configuration
    • a folder for saving certificates to serve HTTPS

5. The Raspberry PiRaspberry Pi Icon - Free Download at Icons8

The Raspberry Pi is a powerful small mini Computer . The biggest difference between it and other computers is, it utilizes different processing instructions. Normally that is not a problem but in our case we want to work with Docker. Using the Dockerfile, images are being built with their respective binaries. This means, that images which work on (e.g.) an Intel processor will not work on our Raspberry Pi’s ARM architecture. This can prove problematic in finding the right software version.  For example i did not find any ready to use MySQL v7 image which is why i switched to MariaDB.

>>> Next: #1 Installing WordPress on a Raspberry Pi with docker-compose in under 10 minutes