WordPress mit Nginx, PHP und MySQL(-Derivaten) in einem ressourceneffizienten Docker-Containerverbund aufsetzen, warten und betreiben

M. Schmidt

Wofür

  • WordPress
  • im Betrieb so granular wie möglich
  • so wartbar wie möglich
  • logische Trennung mehrerer Instanzen

Wie (1/3)

Wie (2/3)

Wie (3/3)

Granular

  • mehrere WP Instanzen in separaten Docker Compose Dateien, Docker Volumes und MySQL-Datenbanken

 

  • einzeln startbar
  • einzeln wartbar
    • (WordPress-Upgrade, PHP-Upgrade, PHP-Module)

Wartbar

PHP-Upgrade/Downgrade

PHP-Modul nachinstallieren

WordPress-Upgrade (inkl. Themes/Plugins)

➔ WordPress Dashboard

sed -i "s/wordpress:php8.0-fpm-alpine/php8.1-fpm-alpine/" && docker-compose up -d
sed -i "s/wordpress:php8.1-fpm-alpine/php8.0-fpm-alpine/" && docker-compose up -d
echo -e "FROM wordpress:php8.1-fpm-alpine\nRUN docker-php-ext-install gd" > Dockerfile && \
sed -i "s/image:\ wordpress:php8.1-fpm-alpine/build:\ \./" docker-compose.yml && \
docker-compose up -d

Praktische Umsetzung

Wir optimieren
(ein wenig)

Wenig RAM? - ZRAM

Wenig IOPS? - Caching, ggf. Cache auf Ramdisk

Wenig CPU? Caching, aktuelle PHP-Version

Wenig Netzwerkbrandbreite? Kompression, HTTP/2, HTTP/3 nutzen

10 Clients, 30 Sekunden

 

Ausgangszustand: 8.7 Req/s

+ WP Super Cache: 109 Req/s

+ HTTP/2: 230 Req/s *

 

Mit WP Super Cache (simple Konfiguration):

50% weniger Systemload

Mit HTTP/2 durch Kompression:
30% weniger Datenmenge

 

 

https://manage-it-for.me
info@manage-it-for.me

Fragen?

docker-compose.yml

version: '3'

services:
  nginx:
    image: nginx:1.23
    restart: always
    ports:
      - '127.0.0.1:8080:80'
    volumes:
      - "files:/var/www/html"
      - "./default.conf:/etc/nginx/conf.d/default.conf:ro"
      - "./nginx.conf:/etc/nginx/nginx.conf:ro"
  fpm:
    image: wordpress:php8.1-fpm-alpine
    restart: always
    environment:
      - "WORDPRESS_DB_HOST=db"
      - "WORDPRESS_DB_USER=username"
      - "WORDPRESS_DB_PASSWORD=passwort"
      - "WORDPRESS_DB_NAME=dbname"
    volumes:
      - "files:/var/www/html"
      - "./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro"
  db:
    image: mysql:8.0
    command: --skip-log-bin
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpw
    volumes:
      - "mysql:/var/lib/mysql"
    ports:
      - "3306:3306"

volumes:
  mysql:
  files:

Mailversand?

  • WP Mail SMTP (mit eigenem SMTP-Account, Gmail, etc.)

oder

  • msmtp im PHP-Container mit SMTP-Container zum Versand

oder

  • WP Mail SMTP mit SMTP-Container zum Versand

default.conf

server {
  listen 80;
  server_name localhost;
  root /var/www/html;

  index index.php;

  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  rewrite /wp-admin$ $scheme://$host$request_uri/ permanent;

  client_max_body_size 4096M;

  location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
      return 404;
    }

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

    fastcgi_pass   fpm:9000;
    fastcgi_index  index.php;
  }
}

nginx.conf

user  nginx;
worker_processes  4;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    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;
    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;

    fastcgi_read_timeout 120s;
    fastcgi_send_timeout 120s;

}

uploads.ini

file_uploads = On
memory_limit = 128M
upload_max_filesize = 128M
post_max_size = 128M
max_execution_time = 600

Nginx-Konfiguration des vorgeschalteten Nginx

upstream seite.de {
    server                        127.0.0.1:8080;
}

server {
    listen                        443 http2 ssl;
    listen                        [::]:443 http2 ssl;
    server_name                   seite.de;
    access_log                    /dev/null;
    error_log                     /dev/null;
    index                         index.php;

    client_max_body_size          16M;

    ssl_certificate               /etc/letsencrypt/live/seite.de/fullchain.pem;
    ssl_certificate_key           /etc/letsencrypt/live/seite.de/privkey.pem;
    ssl_protocols                 TLSv1.2 TLSv1.3;
    ssl_dhparam                   /etc/nginx/ssl/seite.de/dhparam.pem;
    add_header                    Strict-Transport-Security "max-age=31536000; includeSubDomains";
    ssl_ciphers                   EECDH+AESGCM:EDH+AESGCM:EECDH:EDH:!MD5:!RC4:!LOW:!MEDIUM:!CAMELLIA:!ECDSA:!DES:!DSS:!3DES:!NULL;
    ssl_prefer_server_ciphers     on;

    gzip                          on;
    gzip_min_length               1000;
    gzip_proxied                  expired no-cache no-store private auth;
    gzip_types                    text/plain application/javascript application/x-javascript text/javascript text/xml text/css;

    location / {
        proxy_pass                https://seite.de;
        include                   proxy_params;
        proxy_ssl_server_name     on;

        location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
            expires               6M;
            add_header            Cache-Control "public";
            proxy_pass            https://seite.de;
            proxy_set_header      X-Forwarded-Proto $scheme;
            proxy_ssl_server_name on;
        }

        location ~* \.(?:css|js|woff)$ {
            expires               1y;
            add_header            Cache-Control "public";
            proxy_pass            https://seite.de;
            proxy_set_header      X-Forwarded-Proto $scheme;
            proxy_ssl_server_name on;
        }
    }
}


server {
    listen                        80;
    listen                        [::]:80;
    listen                        443 ssl;
    listen                        [::]:443 ssl;
    server_name                   www.seite.de;

    ssl_certificate               /etc/letsencrypt/live/seite.de/fullchain.pem;
    ssl_certificate_key           /etc/letsencrypt/live/seite.de/privkey.pem;
    ssl_protocols                 TLSv1.2 TLSv1.3;
    ssl_dhparam                   /etc/nginx/ssl/seite.de/dhparam.pem;

    return                        301 https://seite.de$request_uri;
}

server {
    listen                        80;
    listen                        [::]:80;
    server_name                   seite.de;

    return                        301 https://seite.de$request_uri;
}