[docker-compose] WordPress, nginx, SQL, redis et Traefik

Tut's Linux avr. 13, 2020

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 20/07/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.2 "chevrotin"
  • Nginx = 1.x "alpine" (stable)
  • MariaDB = 10.14.12
  • 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: contact@czs.local
#      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
        stsIncludeSubdomain: 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.8'
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
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone: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:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - 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: security@file, compression@file
      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:
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
      - ./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=v2.2.5
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[poPD@6!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.

Mettmett/docker-compose
Some examples used on ComputerZ Solutions... Contribute to Mettmett/docker-compose development by creating an account on GitHub.

Mots clés

Julien HOMMET

Bercé par l'informatique depuis mon plus jeune âge, je transforme ma passion en expertise.

Super ! Vous vous êtes inscrit avec succès.
Super ! Effectuez le paiement pour obtenir l'accès complet.
Bon retour parmi nous ! Vous vous êtes connecté avec succès.
Parfait ! Votre compte est entièrement activé, vous avez désormais accès à tout le contenu.