[docker-compose] WordPress, nginx, SQL, redis et Traefik
Objectif de l’article : mise en place d’un socle fiable et performant pour WordPress, avec Traefik en frontend, Nginx en reverse pour WordPress, une base de données SQL grâce à MariaDB et un serveur de cache objets via Redis.
Mise à jour le 28/09/2020.
Comme les autres articles, j’utilise le dossier « /srv/docker » pour y placer le fichier docker-compose.yml. Un dossier « conf » sera exploité pour y stocker les fichiers de configuration.
Logiciels exploités :
- Ubuntu 18.04 LTS
- Docker CE = 19.03.8
- Docker-compose = 1.25.4
- Traefik = 2.3 « picodon »
- Nginx = 1.x « alpine » (stable)
- MariaDB = 10.15
- WordPress = 5.x
- PHP = 7.4-fpm « alpine »
- Redis = 6
Pré-requis : créer les dossiers et placer les droits nécessaires pour les configurations des différents services :
mkdir -p /srv/docker/conf/traefik/traefikdynamic
mkdir /srv/docker/conf/nginx-wp
mkdir /srv/docker/logs
touch /srv/docker/logs/traefik.log
touch /srv/docker/conf/acme.json
chmod 0600 /srv/docker/conf/acme.json
Ci-dessous le fichier « traefik.yml » (/srv/docker/conf/traefik.yml) :
global:
sendAnonymousUsage: false
checkNewVersion: false
api:
#insecure: true
dashboard: true
#debug: true
log:
filePath: "/etc/traefik/applog.log"
level: INFO
providers:
docker:
endpoint: unix:///var/run/docker.sock
exposedByDefault: false
watch: true
swarmMode: false
file:
directory: /traefikdynamic
watch: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory
caServer: https://acme-v02.api.letsencrypt.org/directory
storage: acme.json
keyType: EC256
httpChallenge:
entryPoint: web
Passons au fichier traefik_dynamic.yml
(/srv/docker/conf/traefikdynamic/traefik_dynamic.yml) :
tls:
options:
default:
minVersion: VersionTLS12
sniStrict: true
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
http:
middlewares:
compression:
compress:
excludedContentTypes:
- text/event-stream
security:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
#accessControlAllowOriginList = "*"
accessControlMaxAge: 100
addVaryHeader: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
sslRedirect: true
sslForceHost: true
stsPreload: true
#ContentSecurityPolicy = "default-src 'self' 'unsafe-inline'"
customFrameOptionsValue: SAMEORIGIN
referrerPolicy: same-origin
featurePolicy: vibrate 'self'
stsSeconds: 315360000
authentification:
basicAuth:
users: # admon / totolasticot
- admon:$2y$10$4IgUsvlCwENsF18B9t7AoegQ7eWZVfWxPFRhNfBWz7F00h1X2oZFe
Fichier docker-compose.yml comportant tous les services – quelques explications seront juste en dessous du code.
---
version: '3.6'
services:
traefik:
container_name: traefik
image: traefik:${TRAEFIKVERSION}
restart: unless-stopped
ports:
- 80:80
- 443:443
- 8080:8080 # used to have the traefik dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./conf/traefik.yml:/etc/traefik/traefik.yml:ro
- ./conf/traefikdynamic:/traefikdynamic:ro
- ./logs/traefik.log:/etc/traefik/applog.log
- ./conf/acme.json:/acme.json
sqlwp:
container_name: sqlwp
image: mariadb:${MARIADBVERSION}
restart: unless-stopped
volumes:
- datasqlwp:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: '1'
MYSQL_USER: ${MYSQLUSER}
MYSQL_PASSWORD: ${MYSQLPASSWORD}
MYSQL_DATABASE: ${MYSQLDB}
labels:
traefik.enable: false
nginxwp:
container_name: nginxforwp
image: nginx:${NGINXVERSION}
restart: unless-stopped
volumes:
- datawp:/var/www/html
- datanginxlogs:/var/log/nginx/
- ./conf/nginx-wp:/etc/nginx/
links:
- wp
labels:
traefik.enable: true
traefik.http.routers.nginxwp-https.entrypoints: websecure
traefik.http.routers.nginxwp-https.rule: Host(`wp.czs.local`)
traefik.http.routers.nginxwp-https.middlewares: [email protected], [email protected]
traefik.http.routers.nginxwp-https.tls: true
traefik.http.routers.nginxwp-https.tls.certresolver: letsencrypt
wp:
container_name: wpapp
image: wordpress:${WPVERSION}
restart: unless-stopped
volumes:
- ./conf/php.ini:/usr/local/etc/php/php.ini
- datawp:/var/www/html
depends_on:
- sqlwp
environment:
WORDPRESS_DB_HOST: sqlwp
WORDPRESS_DB_USER: ${MYSQLUSER}
WORDPRESS_DB_PASSWORD: ${MYSQLPASSWORD}
WORDPRESS_DB_NAME: ${MYSQLDB}
WORDPRESS_TABLE_PREFIX: ${MYSQLTABLEPREFIX}
labels:
traefik.enable: false
redis:
container_name: redis
image: redis:${REDISVERSION}
restart: unless-stopped
volumes:
- dataredis:/data
labels:
traefik.enable: false
volumes:
datasqlwp:
datanginxlogs:
datawp:
dataredis:
Traefik est le reverse-proxy frontal. Le serveur nginx est présent pour afficher les ressources de WordPress : en effet, le conteneur WordPress n’a pas de serveur web, uniquement le socket PHP-FPM et les fichiers statiques de l’application. Traefik n’est pas (encore) capable de servir de serveur web, il est donc nécessaire d’utiliser nginx pour se faire. La base de données et Redis sont plutôt orienté « backend » pour WordPress.
Fichier .env
(contient les variables avec les mots de passe pour le SQL et les numéros de version)
MYSQLUSER=wpsqluser
MYSQLPASSWORD=sqlpassword
MYSQLDB=wpdb
MYSQLTABLEPREFIX=lkEZKOl
TRAEFIKVERSION=picodon
MARIADBVERSION=focal
NGINXVERSION=stable-alpine
WPVERSION=5-php7.4-fpm-alpine
REDISVERSION=6
Fichier « wp.conf » (/srv/docker/conf/nginx-wp/wp.conf)
server {
listen 80;
server_name wp.czs.local;
root /var/www/html;
index index.php;
access_log /var/log/nginx/wp-access.log;
error_log /var/log/nginx/wp-error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ .php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass wp:9000;
include /etc/nginx/fastcgi.conf;
}
location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
}
Fichier « nginx.conf » (/srv/docker/conf/nginx-wp/nginx.conf)
worker_processes auto; # use " grep processor /proc/cpuinfo | wc -l " and type the number here, or stay with automatic configuration
events {
worker_connections 1024; # use " ulimit -n" and type the number here
}
http {
############# NGINX conf
include /etc/nginx/mime.types;
include /etc/nginx/fastcgi.conf;
sendfile on;
tcp_nopush on;
server_names_hash_bucket_size 128;
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 16M;
large_client_header_buffers 2 1k;
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;
gzip on;
gzip_comp_level 2;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/x-javascript text/xml text/css application/xml;
############# WP conf
include /etc/nginx/wp.conf;
}
Fichier « fastcgi.conf » (/srv/docker/conf/nginx-wp/fastcgi.conf)
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_index index.php;
fastcgi_param REDIRECT_STATUS 200;
Fichier « mime.types » (/srv/docker/conf/nginx-wp/mime.types)
types {
text/html html htm shtml;
text/css css;
text/xml xml rss;
image/gif gif;
image/jpeg jpeg jpg;
image/svg+xml svg svgz;
application/x-javascript js;
text/plain txt;
text/x-component htc;
text/mathml mml;
image/png png;
image/x-icon ico;
image/x-jng jng;
image/vnd.wap.wbmp wbmp;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/pdf pdf;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/zip zip;
application/octet-stream deb;
application/octet-stream bin exe dll;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/mpeg mp3;
audio/x-realaudio ra;
video/mpeg mpeg mpg;
video/quicktime mov;
video/x-flv flv;
video/x-msvideo avi;
video/x-ms-wmv wmv;
video/x-ms-asf asx asf;
video/x-mng mng;
}
Bien entendu, n’oubliez pas de changer le nom de domaine pour correspondre à vos besoins. Lancez une première fois le stack – Une fois votre WordPress en place, installez l’extension « Redis Object Cache » (auteur = Till KRÜSS) et activez-là.
Modifiez le fichier « wp-config.php » qui se trouve dans le volume de données WordPress « /var/lib/docker/volumes/docker_datawp/_data/ » et ajoutez ces 5 lignes juste en dessous du premier commentaire :
define('WP_CACHE', true);
define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', '6379');
define('WP_CACHE_KEY_SALT', 'B33?,;j3D$srtX-nJC[[email protected]!SjSRDL?S~lg{8>(pagVe|-QoX..1Ky3PkG.1|C');
define('WP_REDIS_DISABLE_BANNERS', 'true');
Vous pouvez enfin retourner dans l’interface d’administration de WordPress, notamment dans la page « Réglages » > « Redis » et cliquer sur le bouton « Enable Object Cache ».
Avec ce stack, vous avez un site web sous WordPress derrière Traefik et Nginx, en plus d’avoir du cache objet via REDIS.
Vous pouvez retrouver l’ensemble des fichiers sur GitHub à cette adresse.