While getting in touch with Docker and playing around with different methods to dockerize web services and websites, I came across some interesting articles, blog posts and tutorials. As mentioned in the introduction of my little series of self-hosted websites, I did not find the perfect tutorial covering all my wishes.

That was the reason for me to share my experiences as a Docker beginner and led to start blogging again. Maybe some individuals with similar wishes out there find useful information in my posts.

When I initially had the idea to blog about my solutions as a Docker beginner, of course there was no other way than running the blog in a Docker container. Due to a widespread use of WordPress, a ton of different ways exist.

By the time I’m writing this post, some months have passed since I initially created my dockerized WordPress blog. So unfortunately, I can’t reproduce if I found an almost-ready solution or if I created the docker-compose.yml partly by myself.

Nevertheless, I will now describe how I’m running this WordPress blog in Docker. For the setup I’m using, three Docker containers are required:

  1. WordPress
  2. Web server
  3. Database

For an easy startup and maintenance, those containers are bundled in a docker-compose.yml file. The web server is the only container allowed to speak to Traefik. It is linked to WordPress and includes WordPress’ files within the corresponding directory of nginx. WordPress again is linked to the database.

Setup of Docker containers to run Wordpress

Setup of Docker containers to run Wordpress

1. Wordpress

As you might expect, WordPress is providing a Docker image on Docker Hub. The configuration is pretty straightforward. I created a named volume to provide the web server access to the WordPress files. Of course, a link to the database container is required. As shown in the figure, Traefik is not aware of the WordPress container.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
volumes:
  wordpress_files:
    driver: local-persist
  driver_opts:
    mountpoint: /path/to/wordpress

services:
  wordpress:
    image: wordpress:fpm
    restart: always
    volumes:
      - wordpress_files:/var/www/html
    links:
      - db:mysql
    networks:
      - internal
    labels:
      - traefik.enable=false

2. Web server

Because WordPress’ Docker image I’m using is shipped without a web server, I need to create one in a separate Docker container. For this, I’m using an already existing nginx image from Docker Hub, tailored to the official WordPress container.

As shown in the figure, I need to link the web server container to the WordPress container and use the existing named image to get access to WordPress’ files.

The remaining configuration just increases PHP’s post_max_size and specifies the connection to Traefik.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
nginx:
  image: raulr/nginx-wordpress
  restart: always
  links:
    - wordpress
  volumes:
    - wordpress_files:/var/www/html
  environment:
  POST_MAX_SIZE: 128m
  networks:
    - internal
    - proxy
  labels:
    - traefik.enable=true
    - traefik.backend=blog
    - traefik.frontend.rule=Host:blog.domain.net
    - traefik.docker.network=proxy

3. Database

Now that I have a WordPress instance and a web server, I still need a database to get WordPress to work. I chose a MariaDB Docker container which is of course officially provided on Docker Hub.

Accessing the database should at least be secured by a password protected user. So username and password, as well as the name of the database and a root password need to be set. Because my docker-compose.yml file is tracked via Git, I put those variables in a separate file (wp_db.txt). This file is then .gitignored.

1
2
3
4
MYSQL_ROOT_PASSWORD=123456
MYSQL_PASSWORD=654321
MYSQL_DATABASE=mydatabase
MYSQL_USER=user

By nature, when a Docker container stops, crashes or is being deleted, the files changed within the container are also being deleted. In this case, our database would have been gone. That’s why I need to create a volume, to still have MariaDB’s files outside the Docker container when deleting the container.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db:
  image: mariadb:10.3.8
  restart: always
  secrets:
    - wp_db
  volumes:
    - /my/local/path/to/mysql:/var/lib/mysql
  networks:
    - internal
  labels:
    - traefik.enable=false

Summary

Setting up WordPress in Docker was rather easy. There is a ton of tutorials, examples, Docker images, Dockerfiles etc. and setting up websites in Docker containers follow a certain pattern.

Putting all three parts together, my docker-compose.yml file is looking like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
version: '3.1'

networks:
  proxy:
    external: true
  internal:
    external: false

volumes:
  wordpress_files:
    driver: local-persist
  driver_opts:
    mountpoint: /my/local/path/to/wordpress

services:
  wordpress:
  image: wordpress:fpm
  restart: always
  volumes:
    - wordpress_files:/var/www/html
  links:
    - db:mysql
  networks:
    - internal
  labels:
    - traefik.enable=false

nginx:
  image: raulr/nginx-wordpress
  restart: always
  links:
    - wordpress
  volumes:
    - wordpress_files:/var/www/html
  environment:
  POST_MAX_SIZE: 128m
  networks:
    - internal
    - proxy
  labels:
    - traefik.enable=true
    - traefik.backend=blog
    - traefik.frontend.rule=Host:blog.florianfranke.net
    - traefik.docker.network=proxy

db:
  image: mariadb:10.3.8
  restart: always
  secrets:
    - wp_db
  volumes:
    - /my/local/path/to/mysql:/var/lib/mysql
  networks:
    - internal
  labels:
    - traefik.enable=false

secrets:
  wp_db:
    file: wp_db.txt