Setting up wordpress in pretty easy in docker – but we need to set up two things – a database and the wordpress server itself. We can do some funny stuff with the setup though, which will display some nice docker compose features we will later use (a lot).
Setting up the database
Setting up the database, we create a new file, we can call it wordpress-compose.yml, to keep it nice and clean away from the general setup we did last time. Using the same structure as last time, and lookup up a MySQL image on docker hub, we construct the following file
name: wordpress-compose
services:
wordpress-db:
container_name: wordpress-db
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: password
networks:
- wordpress
networks:
wordpress:Now, this will start the database, on it’s own isolated network (so not reachable via traefik, since it is a database where users don’t need direct access). However, we don’t want to have the password just lying there in the definition file – since eventually, we want to check in this setup, and passwords in git histories are a big no-no.
Luckily, docker compose comes with support for secrets, and while that is basically just a (server-local) file that is mounted to a specific path, the MySQL image also supports this easily. We just create two files for the passwords (I put them in a /secrets subfolder) on the server (and don’t check them into your version control), and then bind them like this
name: wordpress-compose
services:
wordpress-db:
container_name: wordpress-db
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/wordpress_db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/wordpress_db_password
secrets:
- wordpress_db_root_password
- wordpress_db_password
networks:
- wordpress
secrets:
wordpress_db_password:
file: ./secrets/wordpress_db_password.txt
wordpress_db_root_password:
file: ./secrets/wordpress_db_root_password.txt
networks:
wordpress:Now, when the service starts up, it will load the files at the paths of MYSQL_ROOT_PASSWORD_FILE and MYSQL_PASSWORD_FILE into the (not ‘_FILE’) environment variables, and run as normal. This allows us to give this service access to these specific secrets, while not having files with content checked into the version control.1
Well, that was easy. Now we just need to add the wordpress image on top.
WordPress itself
If we take a look at the wordpress image on docker hub, we can quickly construct a pretty good service in the docker file.
wordpress-cbrams:
container_name: wordpress-cbrams
depends_on:
- wordpress-db
image: wordpress:latest
environment:
WORDPRESS_DB_HOST: wordpress-db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/wordpress_db_password
WORDPRESS_TABLE_PREFIX: cwp_
WORDPRESS_CONFIG_EXTRA: |
define('DOMAIN_CURRENT_SITE', 'wordpress.cbrams.dk');
secrets:
- wordpress_db_password
volumes:
- /opt/server/data/wordpress/wordpress:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.http.services.wordpress-cbrams.loadbalancer.server.port=80"
- "traefik.http.routers.wordpress.rule=Host(`wordpress.cbrams.dk`)"
- "traefik.http.routers.wordpress.entrypoints=web"
- "traefik.http.routers.wordpress.priority=10"
- "traefik.http.routers.wordpress-secure.rule=Host(`wordpress.cbrams.dk`)"
- "traefik.http.routers.wordpress-secure.entrypoints=websecure"
- "traefik.http.routers.wordpress-secure.priority=10"
- "traefik.http.routers.wordpress-secure.tls=true"
- "traefik.http.routers.wordpress-secure.tls.certresolver=httpchallenge"
networks:
- wordpress
- traefikThere are a few things to note here. First is that this service depends on the other service – which is because we only want to start wordpress, once we already know the database is running. Otherwise we will just get errors.
Another is that the host of the database is just the name of the service the database runs on. This is available because they share a network – the wordpress network. This is an isolated network shared by these two services, and they can easily connect to any ports of each others on this network.
Finally, we only need the wordpress database password here, not the root password, and we have elected to only give this service access to that secret. This is a small thing, but will be nice especially for more advanced setups.
Finally, we consume the traefik network to enable the traefik reverse proxy, but this means that we need to append our network definition to include this network, which is not defined in this file (but rather in the file of the traefik service)
networks:
wordpress:
traefik:
name: traefik
external: trueIf you want, you can inlclude an IP whitelist while you do the initial setup of wordpress, and just remove it after. Any way you do it, you start the services with
docker compose -f wordpress-compose.yml up -dAnd now we have a blog!
But I want another WordPress
If you want another wordpress installation, you can just extend the same wordpress compose file with another. WordPress is already made for coexisting in the same database, but if you copy the whole setup, you can basically create a whole new isolated instance, where no cross contamination can happen. If you elect to run another wordpress on the same database, just change the URL and the “WORDPRESS_TABLE_PREFIX”, and copy the rest, then it will work. (take a look at an old blod about Lord of the Rings Online I ported into lotro.cbrams.dk, which does this exact thing
wordpress-cbrams-lotro:
container_name: wordpress-cbrams-lotro
depends_on:
- wordpress-db
image: wordpress:latest
environment:
WORDPRESS_DB_HOST: wordpress-db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/wordpress_db_password
WORDPRESS_TABLE_PREFIX: lotrowp_
WORDPRESS_CONFIG_EXTRA: |
define('DOMAIN_CURRENT_SITE', 'lotro.cbrams.dk');
secrets:
- wordpress_db_password
volumes:
- /opt/server/data/wordpress/lotro:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.http.services.wordpress-cbrams-lotro.loadbalancer.server.port=80"
- "traefik.http.routers.wordpress-cbrams-lotro.rule=Host(`lotro.cbrams.dk`)"
- "traefik.http.routers.wordpress-cbrams-lotro.entrypoints=web"
- "traefik.http.routers.wordpress-cbrams-lotro.priority=10"
- "traefik.http.routers.wordpress-cbrams-lotro-secure.rule=Host(`lotro.cbrams.dk`)"
- "traefik.http.routers.wordpress-cbrams-lotro-secure.entrypoints=websecure"
- "traefik.http.routers.wordpress-cbrams-lotro-secure.priority=10"
- "traefik.http.routers.wordpress-cbrams-lotro-secure.tls=true"
- "traefik.http.routers.wordpress-cbrams-lotro-secure.tls.certresolver=httpchallenge"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.wordpress-cbrams-lotro.middlewares=redirect-to-https@docker"
networks:
- wordpress
- traefik- If your image does not support these FILE environment variables, or does not support the correct variables you would like to hide, you can create a dockerfile that takes the other as a base image, loads these into the environment, and then runs whatever command the original file ran to start up. It’s pretty easy, I will probably describe it in another post when I need that functionality, and hope I will cross over this again to link it. ↩︎
Leave a Reply