Setup WordPress with Apache and phpMyAdmin in a Docker container

Advantages run Word-Press in docker container:

My environment:

lsb_release -d

Description: Debian GNU/Linux 11 (bullseye) – Raspberry PI 4 

Description: Ubuntu 22.04.1 LTS – AWS Cloud instance

Docker version 20.10.18

Docker Compose version v2.5.0

Follow these steps to update it (or steps 3 & 4 to install):

  1. docker stop portainer
  2. docker rm portainer
  3. docker pull portainer/portainer-ce:latest
  4. docker run -d -p 8000:8000 -p 9443:9443 –name portainer –restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

Installation steps:

1. Docker Compose

Please find the step-by-step process in the following article (applicable for Ubuntu as well).
“Install Docker-compose onto Raspberry OS”

2. Portainer

Portainer is needed for access to the container console.

A lot of authors suggest to install a separated container with NGINX server. But WordPress docker image includes Apache server. So, I don’t see any reason to install one more web-server for it.

But, the configuration for included web-server is embedded into the container. Hence, Apache config files have to be extracted to the host and attached to the container as a volume. 

Using potrainer is the easiest way to perform this trick.

host:# docker stop portainer
host:# docker rm portainer
host:# docker pull portainer/portainer-ce:latest
host:# docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
3. Obtain SSl certificate

Nowadays HTTPS (SSL certificate) is must-have for any site.

Unfortunately, WordPress creates all links accordingly to your first installation. So, you will need some plugins to fix your links if you set up your WordPress with “http://” instead of “https://”. 

WordPress has the same issue if you setup it with IP address http(s):// instead of http(s)://

Hence, there is strong recommendation to set up your WordPress with the real site name (public domain) to avoid additional exercises.

Please read the article about getting a free SSL certificate with LetLet’s Encrypt and CertBot in Docker container.

4. Prepare working directories:
host:# mkdir /opt/wordpress
host:# cd /opt/wordpress
5. Prepare docker-compose.yml:
touch /opt/wordpress/docker-compose.yml

Please open your preferred text editor and configure your certbor containers.
Please be aware that this is an example and you have to replace the following values with your real info:

  • line 13,32,49: YourTimeZone
  • line 14,17,34,53: Your passwords 
  • line 56: Must be commented with “#” at first launch, because Apache2 can’t be launched with empty configuration folder
version: '3.8'


    image: mariadb:latest
    container_name: mariadb
    hostname: mariadb
      - /opt/wordpress/mysql:/var/lib/mysql
      - /opt/wordpress/etc/mysql:/etc/mysql
     - TZ=YourTimeZone
     - MYSQL_DATABASE=wordpress
     - MYSQL_USER=wordpress
      - wordpress

    image: phpmyadmin:latest
    container_name: phpmyadmin
    hostname: phpmyadmin
      - mariadb
      - wordpress
      - '8080:80'
     - TZ=YourTimeZone
     - PMA_HOST=mariadb
      - wordpress

    image: wordpress:latest
    container_name: wordpress
    hostname: wordpress
     - mariadb
      - 80:80
      - 443:443
      - TZ=YourTimeZone
      - WORDPRESS_DB_HOST=mariadb:3306
      - MYSQL_DATABASE=wordpress    
      - WORDPRESS_DB_USER=wordpress
      - /opt/wordpress/html:/var/www/html
#      - /opt/wordpress/etc/apache2:/etc/apache2
      - /opt/wordpress/etc/letsencrypt:/etc/letsencrypt
      - wordpress

    driver: bridge  

Launch containers:

docker-compose up --remove-orphans

The process takes some time depending on your Internet connection bandwidth and the productivity of your system.

As a result WordPress should be accessible with 80th port and and phpMyAdmin with 8080.

host:# netstat -nlp | grep :80
 tcp        0      0  *               LISTEN      809850/docker-proxy 
 tcp        0      0    *               LISTEN      809707/docker-proxy 
6. enable to configure apache server outside of container:

By default WordPress container is configured with HTTP only, but not HTTPS.
Of cause, you can configure it inside the container, but your configuration will be lost if you redeploy it.
Hence, you have to take out Apache config from the container.
Please follow step 2 of this article if Portainer is not launched still.
 So, connect to console of WordPress container as a root and copy /etc/apache2 directory to /var/www/html and close console in Portainer.

Now you have to disconnect from Portainer console and back to your system’s terminal.

The next step is attaching the taken-out configuration to your WordPress container as a volume.
Please stop your Docker-compose – you can just press Cntr-C in a terminal where it launched.

CGracefully stopping... (press Ctrl+C again to force)
[+]Running 3/3
⠿ Container phpmyadmin      Stopped     5.3s
⠿ Container wordpress       Stopped     3.3s
⠿ Container mariadb         Stopped     3.0s
mv /opt/wordpress/html/apache2 /opt/wordpress/etc

Copy Apache configuration to the directory for the config volume:

Don’t forget to uncomment line 56 in your docker-compose.yml

      - /opt/wordpress/etc/apache2:/etc/apache2

Run your containers again to be sure that your set up is working.

6. configure https for your wordpress with Let’s Encrypt SSL certificate and certbot:

Please follow steps in the article Obtain Free SSL certificate for your site and save your  certificate: fullchain.pem and private key: privkey.pem.

 Please pay attention to symlinks which CertBot provides for last versions of files.

Hence, don’t forget -L option for cp command and replace with your domain name:

host:# cp -L /opt/certbot/etc/letsencrypt/live/ /opt/wordpress/etc/apache2/
host:# cp -L /opt/certbot/etc/letsencrypt/live/ /opt/wordpress/etc/apache2/

Let’s enable HTTPS in the Apache configuration.
Please remember that paths in your system and inside a container are different.
So, you have to use relative symlinks, but not absolute!

Firstly you have to enable necessary Apache modules:

host:#  cd /opt/wordpress/etc/apache2/mods-enabled/
host:#  ln -s ../mods-available/ssl.conf ssl.conf
host:#  ln -s ../mods-available/ssl.load ssl.load
host:#  ln -s ../mods-available/socache_shmcb.load socache_shmcb.load

Enable and configure Apache SSL:

host:#  cd /opt/wordpress/etc/apache2/sites-enabled/
host:#  ln -s ../sites-available/default-ssl.conf default-ssl.conf
Please use your preferred  text editor to find and update the following options in the config file

  • SSLCertificateFile

  • SSLCertificateKeyFile

Please remember that you have to use paths from container point of view but not for your system.
SSLCertificateFile /etc/apache2/fullchain.pem
SSLCertificateKeyFile /etc/apache2/privkey.pem

Launch your docker-compose and check if your WordPress is accessible from browser with link

host:# cd /opt/wordpress
host:# docker-compose up --remove-orphans

Please remember that your domain can be accessed from your local network in the following cases:

  • If your domain is resolved by public DNS.
    But, your router has to permit access to your public IP with port forwarding from your local network.
  • If you have your own DNS server in your local network and it’s configured to resolve your domain into your local IP.
  • You added appropriate record for your WordPress instance to hosts file on your desktop.
7. Backup or migrate WordPress with docker:

As a result, you can simply migrate your WordPress to another instance with the following steps:

  • Stop your docker-composer
  • Archive and copy directory /opt/wordpress to another instance.
  • Unarchive your directory and run docker-compose.
7. Run wordpress container as a service with systemd:

A manual run and stop of a container is suitable for debug and experiments, but this approach isn’t convenient for everyday usage.

 Let’s prepare wordpress.service config file for systemd:

host:# cd /opt/wordpress
host:# touch wordpress.service

Your WorPress service is depended on launched docker. 

Description=WordPress Docker Container

ExecStartPre=/usr/local/bin/docker-compose -f docker-compose.yml down
ExecStart=/usr/local/bin/docker-compose -f docker-compose.yml up -d --remove-orphans
ExecStop=/usr/local/bin/docker-compose -f docker-compose.yml down


Enable and run your service:

host:# cp wordpress.service /etc/systemd/system
host:# systemctl enable wordpress.service
host:# systemctl start wordpress

You can check your service launching with getting logs in another terminal session:

host:# tail -f /var/log/syslog | grep docker-compose
docker-compose[2892621]: wordpress  Warning: No resource found to remove
docker-compose[2892638]: Network wordpress_wordpress  Creating
docker-compose[2892638]: Network wordpress_wordpress  Created
docker-compose[2892638]: Container mariadb  Creating
docker-compose[2892638]: Container mariadb  Created
docker-compose[2892638]: Container wordpress  Creating
docker-compose[2892638]: Container wordpress  Created
docker-compose[2892638]: Container phpmyadmin  Creating
docker-compose[2892638]: Container phpmyadmin  Created
docker-compose[2892638]: Container mariadb  Starting
docker-compose[2892638]: Container mariadb  Started
docker-compose[2892638]: Container wordpress  Starting
docker-compose[2892638]: Container wordpress  Started
docker-compose[2892638]: Container phpmyadmin  Starting
docker-compose[2892638]: Container phpmyadmin  Started

Leave a Reply

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