For the currently running WordPress site, I envisioned and applied the architecture below.

All the components in the rectangle are Docker containers. NGINX container accepts HTTP(S) requests routes them to the WordPress container listening on port 80 only within Docker internal network. I could have exposed WordPress container listening to port 80 but it wasn’t going to be able to handle HTTPS requests, so I decided to have NGINX container to handle SSL cert.
version: "3.9"
services:
db:
image: mysql:5.7
volumes:
- ./db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: hogehogehogehoge
MYSQL_DATABASE: mydatabase
MYSQL_USER: buhibuhi
MYSQL_PASSWORD: foobar
networks:
proxynet:
phpmyadmin:
depends_on:
- db
image: phpmyadmin/phpmyadmin
restart: always
ports:
- '8080:80'
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: hogehogehogehoge
networks:
proxynet:
wordpress:
image: wordpress:latest
container_name: wordpress
depends_on:
- db
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: buhibuhi
WORDPRESS_DB_PASSWORD: foobar
WORDPRESS_DB_NAME: mydatabase
WORDPRESS_DEBUG: 'true'
volumes:
- ./html:/var/www/html
- ./wp-content:/var/www/html/wp-content
networks:
proxynet:
reverse:
image: nginx:latest
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d:/etc/nginx/conf.d
ports:
- "80:80"
- "443:443"
restart: always
networks:
proxynet:
volumes:
db_data: {}
wordpress: {}
networks:
proxynet:
Paste the whole YAML to docker-compose.yaml file. There is some more steps to do before you can spin up the containers.
Let’s set up a firewall on the OS side. Ubuntu utilizes ufw. Execute the command to install it.
sudo apt install ufw
Let’s open a few necessary ports…
sudo ufw allow 80 # for NGINX http request redirect handling
sudo ufw allow 443 # for SSL (HTTPS) requests
sudo ufw allow 8080 # for myPHPAdmin access
sudo ufw allow 22 # for SSH access
You will need to get the firewall to start when the OS starts, so execute the following command.
sudo ufw enable
In the directory you created docker-compose.yaml file, create nginx/nginx.conf file with the following configuration.
user nginx;
worker_processes 2;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
accept_mutex off;
}
http {
include /etc/nginx/mime.types;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
client_max_body_size 300m;
client_body_buffer_size 128k;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 6;
gzip_min_length 0;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
client_max_body_size 300m;
client_body_buffer_size 128k;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 6;
gzip_min_length 0;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
return 301 https://hayato-iriumi.net$request_uri;
}
include /etc/nginx/conf.d/*.conf;
}
You need another configuration file at nginx/conf.d/ssl.conf. As you could see, this file handles HTTPS requests with the certificate and routes the requests to the wordpress container listening to the port 80 within the Docker network. So the port 80 is not exposed to the host side.
upstream wordpress_upstream {
server wordpress:80;
}
server {
server_name hayato-iriumi.net;
listen 443 ssl;
ssl_certificate /etc/nginx/conf.d/ssl/certificate.crt;
ssl_certificate_key /etc/nginx/conf.d/ssl/private.key;
location / {
proxy_set_header Host $host:$server_port;
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;
resolver 127.0.0.11;
proxy_redirect http:// https://;
proxy_pass http://wordpress_upstream;
# Required for new HTTP-based CLI
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_buffering off; # Required for HTTP-based CLI to work over SSL
}
}
Obviously, you need to have your SSL cert ready. I have blogged about a free SSL solution here, so please refer to it for your SSL cert. Place the SSL cert files at the specified location in the ssl.conf file.
Finally, if you go back to the directory where you created docker-compose.yaml file, and execute docker-compose up -d
, you will be able to see the WordPress initial UI.
If you run through the WordPress installation process, you are half way there. Once you run through the installation process, it creates necessary tables in the MySQL database. Once you have the basic data structure automatically created, you need to export the data from the following tables and import them in the new database. It is easy to export and import data using myPHPAdmin UI even if you don’t know anything about SQL. (Knowing basics of SQL helps when there are problems in importing data)
- wp_posts
- wp_terms
- wp_termsrelationships
- wp_comments
- wp_commentmeta
- wp_postmeta
- wp_term_taxonomy
Your WordPress site still lacks the images. Backup all files under wp_contents/uploads and restore it at the wp_contents/uploads directory of docker-compose.yaml location. And what I had to do was to run the following command to be able to upload files from WordPress UI.
sudo chmod 777 wp_contents
This may be too open. I may tighten it up a little more later.
I put too much information alraedy in this blog post. I will write about Dockerizing WordPress more as I have some time.