Installing multiple WordPress using Docker
Looking to install and run multiple containerized WordPress sites on a single host machine?
Let’s do it.
WordPress has 2 components: the actual WordPress installation files and the database. As a bonus we have Certbot, which gives us free HTTPS. We put each in it’s own container.
Since it’s a multi-container setup I like to use Docker Compose.
The folder structure
Create 3 empty folders inside a parent folder:
- my-site (will contain a WordPress installation)
- nginx (will contain Nginx)
- certs (will contain shared files between WordPress and Nginx)
mkdir -p /docker/my-site
mkdir -p /docker/nginx
mkdir -p /docker/certs
WordPress
Each of our WordPress installations will be in a folder of their own. Let’s start off with the first one, which we will set up inside my-site
folder.
Create the WordPress docker-compose.yml
file with your favourite editor:
vim /docker/my-site/docker-compose.yml
The file will configure 3 containers:
- WordPress (the wordpress installation files)
- Database (the database for wordpress)
- Certbot (for fetching the HTTPS certificate)
# WordPress containers definition /docker/my-site/docker-compose.yml
version: '3.5'
services:
wordpress:
image: wordpress
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppass
WORDPRESS_DB_NAME: wpdb
volumes:
- ./volume_wp:/var/www/html
networks:
- my_net
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: wpdb
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- ./volume_db:/var/lib/mysql
networks:
- my_net
certbot:
image: certbot/certbot
volumes:
- ../certs/conf:/etc/letsencrypt
- ../certs/www:/var/www/certbot
command: certonly --webroot -w /var/www/certbot --email ME@EXAMPLE.ORG -d EXAMPLE.FI -d WWW.EXAMPLE.FI --agree-tos
networks:
my_net:
external: true
Note: Edit the certbot command to include your email and domain(s).
Certbot has two volumes.
../certs/conf
will contain the fetched HTTPS certificates../certs/www
is Certbot’s webroot which is served by Nginx
In addition to the services, the above configuration includes an external network definition, my_net. The purpose of my_net is to enable communication between the WordPress and Nginx environments.
Nginx, the web server
Create the Nginx docker-compose.yml
file with your favourite editor:
vim /docker/nginx/docker-compose.yml
The file defines a single container:
- Nginx (for serving the wordpress site content)
# Nginx container definition at /docker/nginx/docker-compose.yml
version: '3.5'
services:
nginx:
image: nginx
restart: always
ports:
- 80:80
- 443:443
volumes:
- ./conf.d:/etc/nginx/conf.d:ro
- ../certs/www:/var/www/certbot:ro
- ../certs/conf:/etc/nginx/ssl:ro
networks:
- my_net
networks:
my_net:
external: true
Note Nginx environment is attached to the same my_net network as is the WordPress environment.
A few words about the 3 mounted volumes:
./conf.d
will contain site configurations Nginx should serve../certs/www
is used by certbot as the web root../certs/conf
is where the HTTPS certificates are saved to
Next, create an initial Nginx conf for our WordPress site, using your favourite editor:
mkdir /docker/nginx/conf.d
vim /docker/nginx/conf.d/my-site.conf
# /docker/nginx/conf.d/my-site.conf
#
# Initial conf used for fetching the HTTPS cert.
#
server {
listen 80;
server_name EXAMPLE.FI;
location ~ /.well-known/acme-challenge {
root /var/www/certbot;
}
}
Note: Replace the example domain with your own domain.
Start your Nginx server:
cd /docker/nginx
docker compose up -d
Fetch the HTTPS certs by running the certbot service:
cd /docker/my-site
docker compose up certbot
Great! Now you should have HTTPS certificates in /docker/certs/conf
.
Check the certs were created, and we’re ready to enable HTTPS.
Replace the initial Nginx conf with the HTTPS enabled conf:
vim /docker/nginx/conf.d/my-site.conf
# /docker/nginx/conf.d/my-site.conf
#
# Conf for the WordPress site.
#
server {
listen 80;
server_name EXAMPLE.FI WWW.EXAMPLE.FI;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name EXAMPLE.FI;
return 301 https://WWW.EXAMPLE.FI$request_uri;
ssl_certificate /etc/nginx/ssl/live/EXAMPLE.FI/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/EXAMPLE.FI/privkey.pem;
}
server {
listen 443 ssl;
server_name WWW.EXAMPLE.FI;
location ~ /.well-known/acme-challenge {
root /var/www/certbot;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://wordpress/;
}
ssl_certificate /etc/nginx/ssl/live/EXAMPLE.FI/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/EXAMPLE.FI/privkey.pem;
}
Note: Replace the EXAMPLE domains with your own domain.
Launch it!
Fire up WordPress:
cd /docker/my-site
docker compose up -d
Tip: To see possible errors inside the containers you can either use docker compose logs
or drop the -d
param above.
Without -d
the containers are launched on the foreground. To exit hit CTRL+C, which will also exit your newly set up services. Use -d
to launch into the background.
Reload the Nginx process to enable your newly edited my-site.conf:
docker exec -it nginx-nginx-1 nginx -s reload
(If the above fails because your container is not named nginx-nginx-1 use docker ps
to find the correct name.)
Open your domain on your favourite browser. You should be greeted by the WordPress installer.
Adding multiple WordPress sites
So far we have a single WordPress up and running. How to add more? It’s easy:
# Create the docker compose configuration for the second WordPress
mkdir /docker/my-second-site
vim /docker/my-second-site/docker-compose.yml
# Create the initial nginx conf for fetching the HTTPS cert
vim /docker/nginx/conf.d/my-second-site.conf
docker exec -it nginx-nginx-1 nginx -s reload
# Launch the certbot service, which will fetch the HTTPS cert and exit
cd /docker/my-second-site
docker compose up certbot
# Edit the nginx conf to the HTTPS enabled version
vim /docker/nginx/conf.d/my-second-site.conf
docker exec -it nginx-nginx-1 nginx -s reload
# Launch your second WordPress!
cd /docker/my-second-site
docker compose up -d
Alright, second WordPress up and running!
There are far fewer steps when setting up your second (or third, or fourth) WordPress. The details for the steps are as in the steps before.
Enjoy!