WordPress Container auf Docker

Dieser Blog-Eintrag beschreibt, wie man auf WordPress auf einem Docker-Host installieren und damit mehrere WordPress-Instanzen auf einem Host betreiben kann.
Ich betreibe die Docker-Container hinter einem Proxy-Server, der aber nicht als Container läuft. Der Proxy-Server leitet die HTTPS-Requests an die entsprechenden Docker-Container weiter.

Dieser Beitrag setzt ein vorinstalliertes Photon 3.0 inkl. Docker und Docker-Compose voraus. Siehe hier.

Die Docker-Container können über diverse Befehle gemanaged werden. Siehe dazu eine kleine Übersicht hier.

WordPress installieren

Wir installieren WordPress mit Hilfe von Docker Compose. Dazu erstellen wir ein template:

mkdir wordpress
cd wordpress
vi docker-compose.yml

Im yml-Script erstellen wir eine WordPress- inkl. DB-Instanz.

WordPress-Instanz

  • Die WordPress-Instanz hat eine Abhängigkeit zur DB.
  • Die WordPress-Files werden unter /var/www/html abgelegt
  • der Host-Port 80 wird zur wordpress-Instanz port 80 weitergeleitet (“80:80”)
  • Die DB ist über Port 3306 anzusprechen (WORDPRESS_DB_HOST: db:3306)
  • Der DB-User ist wordpress (WORDPRESS_DB_USER: wordpress)
  • Das DB-Passowort ist zu setzen: WORDPRESS_DB_PASSWORD: <wordpress_db_password>

DB-Instanz

  • Die DB-Files werden hier abgelegt: db_data:/var/lib/mysql
  • Passort setzen: MYSQL_ROOT_PASSWORD: <mysql root password>
  • Datenbank definieren: MYSQL_DATABASE: wordpress
  • User definieren: MYSQL_USER <wordpress>
  • DB-Passwort setzen: MYSQL_PASSWORD: (wordpress db password)
version: '3.3' services:

wordpress:
   depends_on:
     - db
   image: wordpress:latest
   volumes:
     - wordpress_files:/var/www/html
   ports:
     - "8080:80"
   restart: always
   environment:
     WORDPRESS_DB_HOST: db:3306
     WORDPRESS_DB_USER: wordpress
     WORDPRESS_DB_PASSWORD: (wordpress_db_password)

db:
   image: mysql:5.7
   command: '--default-authentication-plugin=mysql_native_password'
   volumes:
     - db_data:/var/lib/mysql
   restart: always
   environment:
     MYSQL_ROOT_PASSWORD: (mysql root password)
     MYSQL_DATABASE: wordpress
     MYSQL_USER: wordpress
     MYSQL_PASSWORD: (wordpress db password)
   volumes:
     wordpress_files:
     db_data:

 

Die letzten beiden Linien restellen lokale Verzeichnisse auf dem Photon-Host. Hier werden die WordPress- und SQL-Files abgespeichert. Diese Files überleben somit, wenn der container zerstört und neu generiert wird.

Die Volumes werden unter

cd /var/lib/docker/volumes

erstellt und bleiben bestehen. Dies solange bis die Volumes mittels

docker-compose down -v

zerstört werden.

WordPress Container starten

Nun kann der Container einfach gestartet werden. Dank Docker Compose braucht man nur noch einen Befehl. Docker Compose erkennt automatisch das YAML im aktuellen Verzeichnis, durchläuft die Konfiguration und startet die Container-Anwendung:

docker-compose up -d

Den Prozess kann man anzeigen lassen

docker ps

Nun ist über http://<ip>:8080 auf die WordPress-Instanz zugegriffen werden.

WordPress Container mit SSL erweitern

Das so bereitgestellte Container-Image bietet WordPress “out-of-the-Box” über Port 80 an. Port 443 ist nicht aktiviert. Man geht dabei davon aus, dass die Verschlüsselung (https) eine zusätzliche, neue Funktion darstellt und damit über einen weiteren Container abzubilden ist. Dazu kann ein Proxy-Container aufgebaut werden, für den es auch bereits fertige Docker-Images gibt. Architektonisch mag das Sinn machen.

Ich möchte das aber nicht so umsetzen. Ich betreibe bereits einen Proxy-Server und dieser soll auch so weiter beibehalten werden. Ich verzichte also auf einen Proxy-Container und erweitere das WordPress-Image durch die SSL-Funktionalität. Damit das geht, muss ich das docker-compose.yml bzw. die WordPress-Container Beschreibung erweitern.

Als erstes erstelle ich ein zusätzliches File

vi wordpress/wp-init.sh
!/usr/bin/env bash
apt-get update
apt-get install -y --no-install-recommends ssl-cert
rm -r /var/lib/apt/lists/*
a2enmod ssl
a2dissite 000-default.conf
a2ensite apache2-vhosts.conf
docker-entrypoint.sh apache2-foreground

Dieses Bash-Script soll bei jedem Starten des Containers ausgeführt werden. Mittels diesem Script wird
– SSL nachinstalliert
– Die Default Konfig “000-default.conf” auf dem Apachen entfernt und stattdessen
– eine neue Konfig “apache2-vhosts.conf” installiert.
– Anschliessend wird der Apache neu gestartet.

Damit das Script funktioniert braucht es noch eine Apache-Config. Diese Config wird in den WordPress-Container gemappt und beim Container-Start aktiviert. Damit kann ich von ausserhalb des Containers, die Apache-Config manipulieren:

vi wordpress/apache2-vhosts.conf
NameVirtualHost * 
<VirtualHost *:443> 
   ServerName domain.ch 
   DocumentRoot /var/www/html/ 
   DirectoryIndex index.php 
   Options -Indexes 
   SSLEngine On 
   SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem 
   SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key 
   SSLCACertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem 
</VirtualHost>

Nun ist das das docker-compose.yml zu erweitern (siehe die markierten Erweiterungen):

version: '3.3'
   services:
   wordpress:
     depends_on:
       - db_node
     image: wordpress:latest
     volumes:
       - wordpress_files:/var/www/html
       - ./wp-init.sh:/usr/local/bin/apache2-custom.sh
       - ./apache2-vhosts.conf:/etc/apache2/sites-available/apache2-vhosts.conf
     ports:
       - "8080:80"
       - "8443:443"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db_node:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: (wordpress db password)
     container_name: wordpress_web
     command: "bash -c apache2-custom.sh"

   db_node:
     image: mysql:5.7
     command: '--default-authentication-plugin=mysql_native_password'
     volumes:
       - db_data:/var/lib/mysql
     ports:
       - 6601:3306
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: (wordpress root password)
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: (wordpress db password)
     container_name: wordpress_db
     volumes:
       wordpress_files:
       db_data:

Wie man sieht wird
– das wp-init.sh Skript in den Container gemappt
– Die Apache-Config apache2-vhosts.conf in den Container gemappt.
– Der Container um den Port 8443 erweitert, der Container-Intern auf 443 routet und
– Das Commando “bash -c apache2-custom.sh” bei starten ausgeführt.

Damit startet der Container ab sofort mit aktiviertem SSL und der Apache-Container kann über das File apache2-vhosts.conf konfiguriert werden.

Reverse Proxy

Auf dem Reverse-Proxy wird nun einfach eine Reverse-Rule für den Container eingeführt. Der Reverse-Proxy leitet die HTTPS-Anfragen intern an den Container-Host mit Port 8443 weiter. Diese kann so aussehen:

<VirtualHost serverIp:80> 
ServerAdmin info@domain.ch 
ServerName www.domain.ch 
ServerAlias domain.ch 
RewriteEngine on 
ReWriteCond %{SERVER_PORT} !^443$ RewriteRule ^/(.*) https://www.domain.ch/$1 [NC,R,L] 
</VirtualHost>

<VirtualHost serverIp:443> 
ServerAdmin info@domain.ch 
ServerName www.domain.ch 

#aktiviert SSL Unterstuetzung 
SSLEngine On 
SSLProxyEngine on 
SSLProxyVerify none 
SSLProxyCheckPeerCN off 
SSLProxyCheckPeerName off 
SSLProxyCheckPeerExpire off 

SSLCertificateKeyFile /etc/letsencrypt/live/www.domain.ch/privkey.pem 
SSLCertificateFile /etc/letsencrypt/live/www.domain.ch/cert.pem 
SSLCertificateChainFile /etc/letsencrypt/live/www.domain.ch/chain.pem 

# Regeln zum umleiten auf den internen Server 
ProxyPreserveHost On 
ProxyRequests Off 
ProxyPass / https://www.domain.ch:8443/ 
ProxyPassReverse / https://www.domain.ch:8443/ 

RequestHeader unset Accept-Encoding 

ErrorLog /var/log/apache2/error.log 

# Possible values include: debug, info, notice, warn, error, crit, 
# alert, emerg. 
LogLevel warn 

CustomLog /var/log/apache2/access.log combined 
ServerSignature On 
</VirtualHost>

SMTP auf WordPress-Container

Ich betreibe einen eigenen Mailserver. Ich stellte rasch fest, dass WordPress keine Mails über diesen Server versenden kann. Dies, weil das WordPress-Image einerseits grundsätzlich keinen SMTP-Agent mit dabei hat und andererseits mein Mailserver auch nicht aus dem Container heraus erreichbar war:

Um das Problem zu lösen habe ich mir einfach das Plugin “WP Mail SMTP” installiert. Dieses erweitert WordPress um die Mailfunktion. Das Connectivity-Problem konnte ich mit einer einfach Erweiterung von /etc/hosts lösen:

192.168.xx.xx    mx.domain.ch

Man beachte, dass ich die interne IP des Mailservers verwende.

Damit diese Erweiterung auch bei einem neuen Create des Containers übernommen wird, muss wordpress/wp-init.sh noch modifiziert werden:

#!/usr/bin/env bash

# modify /etc/hosts with mx.intelli.ch
cat >> /etc/hosts <<-EOF

/* mx.intelli.ch */
192.168.xx.xx    mx.domain.ch
EOF

apt-get update
apt-get install -y  --no-install-recommends ssl-cert   # SSL
rm -r /var/lib/apt/lists/*

a2enmod ssl
a2dissite 000-default.conf
a2ensite apache2-vhosts.conf

# finally execute default command
docker-entrypoint.sh apache2-foreground

Links

Linux Datei-Rechte

GruppeUserGroupOthers
Rechtr w xr – xr – –
Wertung4 2 14 0 14 0 0
Mode (Octal)754
Recht Mode (Octal)
0
–x 1
-w- 2
-wx 3
r– 4
r-x 5
rw- 6
rwx 7

Debian sudo: Benutzer für sudo berechtigen

Erscheint die Fehlermeldung

username is not in the sudoers file. This incident will be reported.

hat der aktuelle Benutzer kein Recht, sudo zu nutzen. Das heißt, er ist nicht in einer Benutzergruppe, welche ihm die Nutzung dieser Funktion gestattet.

In der Standardkonfiguration haben der Benutzer “root” und die Benutzergruppe “sudo” Zugriff auf die gleichnamige Funktion sudo. Es gibt auch hinreichend viele Tutorials, welche sich mit der Thematik befassen, einem Benutzer das Recht zu geben, sudo zu nutzen. Diese sind jedoch meiner Meinung nach umständlicher.

Umständliche Variante

Diese nutzen das Programm visudo, welches von sudo ebenfalls mitgeliefert wird. Damit öffnet sich die Konfigurationsdatei von sudo und man kann mit der richtigen Syntax Benutzer oder Benutzergruppen hinzufügen, um ihnen das Nutzen von sudo zu erlauben.

Für den Benutzer “test” sähe das z.B. folgendermaßen aus:

test ALL=(ALL) ALL

Für die Benutzergruppe “test” sähe das dagegen folgendermaßen aus:

%test ALL=(ALL) ALL

Einfache Variante

Da jedoch bereits die Gruppe “sudo” das Recht hat, sudo zu nutzen, kann man auch einfach diese nutzen. Hierzu muss man den Benutzer lediglich dieser Gruppe hinzufügen:

usermod -a -G sudo test

Nach dem nächsten Login per SSH können dann der jeweilige Benutzer bzw. Benutzer der jeweiligen Benutzergruppe sudo problemlos nutzen und erhalten nicht mehr die Fehlermeldung “username is not in the sudoers file. This incident will be reported.”.

Benutzerverwaltung (User Administration)

User und Gruppen

Auflisten aller registrierten User

sudo cat /etc/passwd

Auflisten aller Gruppen

sudo cat /etc/group

Benutzerkonten hinzufügen (adduser)

Das Hinzufügen neuer Benutzerkonten (neuer User erstellen) ist Aufgabe des Systemadministrators und muss daher mit Administrator-Rechten durchgeführt werden. Neben dem klassischen Weg, dem Hinzufügen der erforderlichen Daten mittels eines Editors in den entsprechenden Dateien, steht unter Debian GNU das Programm

adduser

zur Verfügung.

adduser kennt eine Reihe von Optionen, die in der Manpage beschrieben sind oder, in verkürzter Form, mittels

adduser -h

angezeigt werden. Für den „Hausgebrauch“ ist es ausreichend, das Programm ohne weitere Optionen aufzurufen; adduser verfügt über einen interaktiven Modus, in dem alle notwendigen Angaben erfragt werden.

sushi:~# adduser
Enter a username to add: dd
Adding user dd...
Adding new group dd (1001).
Adding new user dd (1001) with group dd.
Creating home directory /home/dd.
Copying files from /etc/skel
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for dd
Enter the new value, or press return for the default
    Full Name []: Donald Duck
    Room Number []:
    Work Phone []:
    Home Phone []:
    Other []:
Is the information correct? (y/n) y

Benutzerkonten löschen (deluser)

Das Entfernen von Benutzerkonten (User löschen) aus dem System ist deutlich einfacher. Hierzu steht das Kommando

deluser

zur Verfügung. Auch dieses Programm kann interaktiv benutzt werden; hier aber ein Beispiel mit der Angabe des Login-Namens auf der Kommandozeile:

sushi:~# deluser dd
Removing user dd...
done.
{code}
Zu beachten ist, dass dabei nicht das Heimatverzeichnis des Benutzers gelöscht wird. Dies bleibt dem Systemadministrator überlassen.
1.1 Gruppe erstellen
{code:txt}
addgroup ~~gruppenname~~
{code}
Alle schon bestehenden Groupen findet man auch unter *cat /etc/group*
1.1 Existierender User einer Existierenden Gruppe hinzufügen
{code:txt}
adduser ~~username gruppe~~

User Passwort ändern unter Ubuntu

Folgendermassen kann man das Passwort eines bestimmten Users ändern:

sudo passwd <username>

z.B.

sudo passwd ralph

Das eigene Passwort ändern man mit einem simplen:

passwd

Passwort für User entfernen (erlaubt Login ohne Passworteingabe unter Ubuntu 18.04)

passwd -d <username>

 

Dualboot System mit Ubuntu und Windows – Zeit nicht korrekt

Auf meinen Dualboot-System ist Ubuntu und Windows installiert.

Die beiden Betriebssysteme interpretieren die Hardware-Clock nicht gleich. Linux interpretiert die Hardware-Clock als UTC. Windows aber als “Local-Time”. Daraus resultiert, dass in dem einen Betriebssystem die Zeit korrekt gesetzt wird und im anderen falsch angezeigt wird.

Ich korrigiere dies, indem ich Ubuntu beibringe die Local-Zime zu verwenden:

  1. Im Bios die HW-Clock auf die aktuelle Local-Zeit einstellen
  2. Dann im Linux die Local-Zeit konfigurieren
    sudo timedatectl set-local-rtc 1

Man könnte dies auch so korrigieren, indem man Windows beibringt, die UTC zu verwenden. Aber umständlicher als die Korrektur über Linux.

Links

https://askubuntu.com/questions/169376/clock-time-is-off-on-dual-boot

test

Ubuntu 18.4: Default Klang-Wiedergabegerät setzen

Mein Ubuntu setzt nach einem Reboot immer das falsche Klang-Wiedergabegerät. Das Default Wiedergabegerät kann folgendermassen gesetzt werden, so dass es auch nach einem Reboot noch gesetzt ist:

Als erstes die vorhandenen Wiedergabegeräte auflisten:

pacmd list-sinks

Dies listet die “Indexe” der Wiedergabegeräte auf. Der mit * markierte Index ist das aktuell als Default gesetzte Wiedergabegerät.

Nun den Index des gewünschten Default Wiedergabegerätes merken (bei mir ist es die “2”) und eintragen in

sudo vi /etc/pulse/default.pa
### Make some devices default
set-default-sink 2

Nach einem Reboot ist das Wiedergabegerät Nr. 2 automatisch gesetzt.

Links

https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/DefaultDevice/

docker / docker-compose Befehle

Container stoppen

docker-compose down

Container aktualisieren

docker-compose down
docker-compose pull
docker-compose up -d

Volumes anzeigen / löschen

Achtung! Dies entfernt einerseits die Container, aber inklusive die statischen Files bzw. Volumes (wordpress_files & db_data)

docker volume ls                # Listet alle Docker-Volumes auf
docker-compose down ––volumes   # löscht ein Container inkl. Volumes (!)

Bash eines Containers öffnen

Es ist möglich über den Docker-Host auf eine Container-Bash zuzugreifen.
Syntax:

docker exec -i -t <docker-id> /bin/bash

Docker Logs anzeigen

Wenn Docker-Containers im “detached-mode” (-d) laufen, werden keine Logs angezeigt. Die Logs können folgendermassen sichtbar gemacht werden:

# Zeigt das Log
docker logs <ContainerName/ContainerID>  
# Zeigt das laufende Log (tail -f)
docker logs --follow <ContainerName/ContainerID>
# Zeigt  die letzen 2500 Zeilen des Logs
docker logs --tail 2500 <ContainerName/ContainerID>
# Zeigt das Log seit dem 28.12.2018 10:00
docker logs --since 2018-12-28T10:00 ContainerName/ContainerID

Auch docker-compose bietet die Möglichkeit auf die Docker-Logs zuzugreifen:

docker-compose logs <service-name>

Entferne nicht benutzte Docker Images

Folgender Befehl entfernt alle aktuell nicht benutzen Images und Volumes

docker system prune

 

WordPress “Nativ-Installation” nach Docker Container umziehen

Nachdem ich nun meine WordPress Docker Container am laufen habe, ist es an der Zeit meine alten WordPress-Installationen umzuziehen. Der Use-Case ist simple:

  • Die WordPress-Installation, welche bisher “nativ” auf www.meinedomäne.ch lief soll nun neu vom neu erstellen Docker-Container beliefert werden.

Das Umziehen einer bestehenden WordPress-Installation war kniffliger als erwartet. Auf diesem Wege hat es dann für mich funktioniert:

  • Als Erstes einen Docker-Container erstellen. Siehe hier. Wichtig war, dass der Container erst ohne die SSL-Erweiterung (inkl. wpinit.sh und apache2vhosts.conf) gestartet wurde.
  • Das so erstellte Image ist nun über http://lokaleIp:port erreichbar.
  • Nun die Installations-Routine von WordPress durchlaufen.
  • Nun auf der WordPress-Installation, welche umgezogen werden soll, das Plugin “All-in-One WP Migration” installieren und damit die WordPress-Export (in ein File) erstellen.
  • Nun wieder auf die Docker-Wordpress Installation wechseln, auch hier das Plugin “All-in-One WP Migration” installieren und anschliessend einen WordPress-Import aus dem erstellten File durchführen.
  • Damit sollte der Umzug schon erledigt sein.
  • Ich habe dann noch das Plugin “SSL Insecure Content Fixer” installiert um sicherzustellen, dass die noch folgende SSL-Aktivierung sicher funktioniert => Das ist evtl. aber gar nicht nötig…
  • Nun Kann die Docker-Instanz gestoppt und wpinit.sh und apache2vhosts.conf im yml-File aktiviert werden. Anschliessend die Docker-Instanz wieder starten:
    docker-compose down
    --- Änderung an yml-File vornehmen (wp-init.sh und apache2-vhosts.conf) ----
    docker-compose up -d

    Damit ist nun auch SSL aktiviert, so dass der Docker-Container über SSL die Seite ausliefert.