So first up lets get Traefik set-up so that we can give all our public services a domain to make it easier to access.
Create a new docker-compose.yml file in an empty folder and paste the following
version: '3.8'
services:
traefik:
image: traefik:latest
restart: always
ports:
- 80:80
- 443:443
command:
- --accesslog
- --log.level=INFO
- --api.dashboard=true
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.web-secure.address=:443
#- --certificatesresolvers.letsencrypt.acme.tlschallenge=true
#- --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
#- [email protected]
#- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- traefik:/letsencrypt
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`${TRAEFIK_URL}`)
- traefik.http.routers.api.entrypoints=web
- traefik.http.routers.api.service=api@internal
#- traefik.http.services.traefik.loadbalancer.server.port=8080
#- traefik.http.routers.api.entrypoints=web-secure
#- traefik.http.routers.api.tls=true
#- traefik.http.routers.api.tls.certresolver=letsencrypt
If you’ve looked at my previous post on WordPress and Traefik, this Traefik configuration script is essentially the same.
Next up configuring WordPress, WordPress by default works with Apache webserver, now while that setup isn’t much of a problem for very small sites, as your website grows and gets bulkier you’ll soon realize you need a bit more performance, thus Nginx.
First inside the same folder we just created for the docker-compose.yml file, create a new folder called nginx, and inside the nginx folder create another folder called conf, inside the conf folder create a new file called default.conf
Inside the default.conf file add the following:
# Upstream to abstract backend connection(s) for php
upstream php {
#server unix:/var/run/php/php-cgi.socket;
server wordpress:9000;
}
server {
## Your website name goes here.
server_name localhost;
## Your only path reference.
root /var/www/html;
## This should be in your http block and if it is, it's not needed here.
index index.php;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
location / {
# This is cool because no php is touched for static content.
# include the "?$args" part so non-default permalinks doesn't break when using query string
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass php;
#The following parameter can be also included in fastcgi_params file
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Caching of media: images, icons, video, audio
location ~* \.(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff|woff2)$ {
expires max;
log_not_found off;
}
# CSS and JavaScript
location ~* \.(css|js)$ {
expires max;
log_not_found off;
}
}
Next reopen the docker-compose.yml file and add:
nginx:
image: nginx:alpine
restart: always
depends_on:
- wordpress
expose:
- 80
- 443
volumes:
- ./nginx/conf:/etc/nginx/conf.d
- ./nginx/logs:/var/log/nginx
- ./wordpress:/var/www/html
labels:
- traefik.enable=true
- traefik.http.routers.wordpress.rule=Host(`${WP_URL}`, `${WP_WWW_URL}`)
- traefik.http.routers.wordpress.entrypoints=web
#- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
#- traefik.http.routers.wordpress.middlewares=redirect-to-https@docker
#- traefik.http.routers.wordpress-secure.rule=Host(`${WP_URL}`, `${WP_WWW_URL}`)
#- traefik.http.routers.wordpress-secure.entrypoints=web-secure
#- traefik.http.routers.wordpress-secure.tls.certresolver=letsencrypt
Now lets configure WordPress, because we are setting WordPress up to use Nginx, we must specify the version of the WordPress image tag for docker to use, rather than simply putting latest. On the WordPress Docker Hub page, the images that support Nginx would be denoted with fpm in the name.
In the existing docker-compose.yml file add:
wordpress:
image: wordpress:php8.0-fpm-alpine
restart: always
depends_on:
- mariadb
- redis
expose:
- 9000
environment:
WORDPRESS_DB_HOST: mariadb
WORDPRESS_DB_NAME: ${WP_DB_NAME}
WORDPRESS_DB_USER: ${WP_DB_USER}
WORDPRESS_DB_PASSWORD: ${WP_DB_PASSWORD}
WORDPRESS_TABLE_PREFIX: ${WP_DB_PREFIX}
WORDPRESS_CONFIG_EXTRA:
define( 'WP_REDIS_HOST', 'redis' );
define( 'WP_REDIS_PORT', 6379 );
define( 'COMPRESS_CSS', true );
define( 'COMPRESS_SCRIPTS', true );
define( 'CONCATENATE_SCRIPTS', true );
define( 'ENFORCE_GZIP', true );
define( 'AUTOSAVE_INTERVAL', 120 );
define( 'WP_POST_REVISIONS', 10);
define( 'MEDIA_TRASH', true );
define( 'EMPTY_TRASH_DAYS', 30 );
define( 'IMAGE_EDIT_OVERWRITE', true );
define( 'DISALLOW_FILE_EDIT', true );
volumes:
- ./wordpress:/var/www/html
- ./wordpress.ini:/usr/local/etc/php/conf.d/wordpress.ini
The biggest change is the default port on which WordPress responds, which defaults to port 9000
Next create a file wordpress.ini next to the docker-compose.yml file and add:
file_uploads = On
upload_max_filesize = 128M
post_max_size = 128M
memory_limit = 256M
max_execution_time = 60
Next up MariaDB and Adminer
mariadb:
image: mariadb:latest
restart: always
expose:
- 3306
environment:
MYSQL_DATABASE: ${WP_DB_NAME}
MYSQL_USER: ${WP_DB_USER}
MYSQL_PASSWORD: ${WP_DB_PASSWORD}
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- mariadb:/var/lib/mysql
adminer:
image: adminer:latest
restart: always
depends_on:
- mariadb
expose:
- 8080
labels:
- traefik.enable=true
- traefik.http.routers.adminer.rule=Host(`${ADMINER_URL}`)
- traefik.http.routers.adminer.entrypoints=web
#- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
#- traefik.http.routers.adminer.middlewares=redirect-to-https@docker
#- traefik.http.routers.adminer-secure.rule=Host(`${ADMINER_URL}`)
#- traefik.http.routers.adminer-secure.entrypoints=web-secure
#- traefik.http.routers.adminer-secure.tls.certresolver=letsencrypt
Then we set up Redis to cache database queries, so add the following to your docker-compose.yml file
redis:
image: redis:latest
restart: always
expose:
- 6379
command:
- redis-server
- --save 60 1
- --loglevel warning
- --maxmemory 128mb
- --maxmemory-policy allkeys-lru
volumes:
- redis:/var/lib/redis
- redis:/data
#- ./redis.conf:/usr/local/etc/redis/redis.conf
I covered how to get WordPress setup with Redis in my previous post
Finally we create a .env file to store any variables set in the docker-compose.yml file
# WordPress
WP_DB_NAME=wp-dev-db
WP_DB_PREFIX=wp_
WP_DB_USER=wp-dev-user
WP_DB_PASSWORD=wp-dev-pass
# Traefik Domains
WP_URL=wpdev.test
WP_WWW_URL=www.wpdev.test
TRAEFIK_URL=traefik.wpdev.test
ADMINER_URL=adminer.wpdev.test
At the end your docker-compose.yml file should look similar to this:
version: '3.8'
services:
traefik:
image: traefik:latest
restart: always
ports:
- 80:80
- 443:443
command:
- --accesslog
- --log.level=INFO
- --api.dashboard=true
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.web-secure.address=:443
#- --certificatesresolvers.letsencrypt.acme.tlschallenge=true
#- --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
#- [email protected]
#- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- traefik:/letsencrypt
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`${TRAEFIK_URL}`)
- traefik.http.routers.api.entrypoints=web
- traefik.http.routers.api.service=api@internal
#- traefik.http.services.traefik.loadbalancer.server.port=8080
#- traefik.http.routers.api.entrypoints=web-secure
#- traefik.http.routers.api.tls=true
#- traefik.http.routers.api.tls.certresolver=letsencrypt
nginx:
image: nginx:alpine
restart: always
depends_on:
- wordpress
expose:
- 80
- 443
volumes:
- ./nginx/conf:/etc/nginx/conf.d
- ./nginx/logs:/var/log/nginx
- ./wordpress:/var/www/html
labels:
- traefik.enable=true
- traefik.http.routers.wordpress.rule=Host(`${WP_URL}`, `${WP_WWW_URL}`)
- traefik.http.routers.wordpress.entrypoints=web
#- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
#- traefik.http.routers.wordpress.middlewares=redirect-to-https@docker
#- traefik.http.routers.wordpress-secure.rule=Host(`${WP_URL}`, `${WP_WWW_URL}`)
#- traefik.http.routers.wordpress-secure.entrypoints=web-secure
#- traefik.http.routers.wordpress-secure.tls.certresolver=letsencrypt
wordpress:
image: wordpress:php8.0-fpm-alpine
restart: always
depends_on:
- mariadb
- redis
expose:
- 9000
environment:
WORDPRESS_DB_HOST: mariadb
WORDPRESS_DB_NAME: ${WP_DB_NAME}
WORDPRESS_DB_USER: ${WP_DB_USER}
WORDPRESS_DB_PASSWORD: ${WP_DB_PASSWORD}
WORDPRESS_TABLE_PREFIX: ${WP_DB_PREFIX}
WORDPRESS_CONFIG_EXTRA:
define( 'WP_REDIS_HOST', 'redis' );
define( 'WP_REDIS_PORT', 6379 );
define( 'COMPRESS_CSS', true );
define( 'COMPRESS_SCRIPTS', true );
define( 'CONCATENATE_SCRIPTS', true );
define( 'ENFORCE_GZIP', true );
define( 'AUTOSAVE_INTERVAL', 120 );
define( 'WP_POST_REVISIONS', 10);
define( 'MEDIA_TRASH', true );
define( 'EMPTY_TRASH_DAYS', 30 );
define( 'IMAGE_EDIT_OVERWRITE', true );
define( 'DISALLOW_FILE_EDIT', true );
volumes:
- ./wordpress:/var/www/html
- ./wordpress.ini:/usr/local/etc/php/conf.d/wordpress.ini
mariadb:
image: mariadb:latest
restart: always
expose:
- 3306
environment:
MYSQL_DATABASE: ${WP_DB_NAME}
MYSQL_USER: ${WP_DB_USER}
MYSQL_PASSWORD: ${WP_DB_PASSWORD}
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- mariadb:/var/lib/mysql
adminer:
image: adminer:latest
restart: always
depends_on:
- mariadb
expose:
- 8080
labels:
- traefik.enable=true
- traefik.http.routers.adminer.rule=Host(`${ADMINER_URL}`)
- traefik.http.routers.adminer.entrypoints=web
#- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
#- traefik.http.routers.adminer.middlewares=redirect-to-https@docker
#- traefik.http.routers.adminer-secure.rule=Host(`${ADMINER_URL}`)
#- traefik.http.routers.adminer-secure.entrypoints=web-secure
#- traefik.http.routers.adminer-secure.tls.certresolver=letsencrypt
redis:
image: redis:alpine
restart: always
expose:
- 6379
command:
- redis-server
- --save 60 1
- --loglevel warning
- --maxmemory 128mb
- --maxmemory-policy allkeys-lru
volumes:
- redis:/var/lib/redis
- redis:/data
#- ./redis.conf:/usr/local/etc/redis/redis.conf
volumes:
traefik:
mariadb:
redis:
Once finished you can Setup WordPress using the URL set in the .env file and everything should load up as usual.