Einführung
WordPress ist ein kostenloses Open-Source-Content-Management-System (CMS), das auf einer MySQL-Datenbank mit PHP-Verarbeitung basiert. Dank seiner Plugin-Architektur und des erweiterbaren Template-Systems lässt sich der Großteil der Verwaltung über eine Weboberfläche durchführen. Daher ist WordPress eine beliebte Wahl für die Erstellung von Websites aller Art, von Blogs über Produktseiten bis hin zu Online-Shops.
Die Installation eines LAMP- (Linux, Apache, MySQL und PHP) oder LEMP-Stacks (Linux, Nginx, MySQL und PHP) ist für den Betrieb von WordPress üblicherweise zeitaufwändig. Mit Tools wie Docker und Docker Compose lässt sich die Einrichtung eines eigenen Stacks und die Installation von WordPress jedoch deutlich vereinfachen. Anstatt einzelne Komponenten manuell zu installieren, können Images verwendet werden, die Bibliotheken, Konfigurationsdateien und Umgebungsvariablen standardisieren. Diese Images werden dann in Containern ausgeführt – isolierten Prozessen, die auf einem gemeinsamen Betriebssystem laufen. Mit Compose lassen sich zudem mehrere Container – beispielsweise eine Anwendung und eine Datenbank – so koordinieren, dass sie miteinander kommunizieren.
In diesem Tutorial erstellen Sie eine WordPress-Installation mit mehreren Containern. Ihre Container enthalten die MySQL-Datenbank, den Nginx-Webserver und WordPress selbst. Sie sichern Ihre Installation außerdem, indem Sie TLS/SSL-Zertifikate von Let's Encrypt für die Domain erwerben, die Sie mit Ihrer Website verknüpfen möchten. Abschließend richten Sie einen Cronjob ein, um Ihre Zertifikate automatisch zu erneuern und so die Sicherheit Ihrer Domain zu gewährleisten.
Voraussetzungen
- Ein Server, auf dem Ubuntu läuft, mit einem Nicht-Root-Benutzer mit entsprechenden Berechtigungen.
sudoUnd eine aktive Firewall. - Docker ist auf Ihrem Server installiert.
- Docker Compose muss auf Ihrem Server installiert sein.
- Ein registrierter Domainname. In diesem Tutorial wird Ihre Domain vollständig verwendet.
- Die folgenden beiden DNS-Einträge sind für Ihren Server eingerichtet.
Ein Eintrag mit Ihrer_Domain, der auf die öffentliche IP-Adresse Ihres Servers verweist.
Ein Eintrag mit www.your_domain, der auf die öffentliche IP-Adresse Ihres Servers verweist.
Schritt 1 – Webserverkonfiguration definieren
Bevor Sie Container starten, müssen Sie zunächst die Konfiguration Ihres Nginx-Webservers festlegen. Ihre Konfigurationsdatei enthält einige WordPress-spezifische Location-Blöcke sowie einen Location-Block, der Let's Encrypt-Verifizierungsanfragen an den Certbot-Client zur automatischen Zertifikatserneuerung weiterleitet.
Erstellen Sie zunächst ein Projektverzeichnis für Ihre WordPress-Installation. In diesem Beispiel heißt es „WordPress“. Sie können dieses Verzeichnis aber auch anders benennen:
mkdir wordpressWechseln Sie anschließend in das Verzeichnis:
cd wordpressAls Nächstes erstellen Sie ein Verzeichnis für die Konfigurationsdatei:
mkdir nginx-confDatei mit Nano Oder öffnen Sie Ihren bevorzugten Editor:
nano nginx-conf/nginx.confFügen Sie in dieser Datei einen Serverblock mit Anweisungen für den Servernamen und das Dokumentenverzeichnis sowie Standortblöcke hinzu, um Certbot-Clientanfragen für Zertifikate, PHP-Verarbeitung und Anfragen zu festen Anlagen zu steuern.
Fügen Sie den folgenden Code in die Datei ein. Ersetzen Sie dabei „your_domain“ durch Ihren Domainnamen:
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
index index.php index.html index.htm;
root /var/www/html;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
} Unser Serverblock enthält folgende Informationen:
Anweisungen:
HörenDies weist Nginx an, auf Port 80 zu lauschen, wodurch Sie das Webroot Certbot-Plugin für Ihre Zertifikatsanforderungen verwenden können. Beachten Sie, dass Sie Port 443 noch nicht angegeben haben – Sie werden Ihre Konfiguration aktualisieren, um SSL einzubinden, sobald Sie Ihre Zertifikate erfolgreich erhalten haben.ServernameHier wird Ihr Servername und der Serverblock angegeben, der für Anfragen an Ihren Server verwendet werden soll. Ersetzen Sie in dieser Zeile „your_domain“ durch Ihren Domainnamen.IndexDiese Direktive definiert die Dateien, die bei der Verarbeitung von Anfragen an Ihren Server als Indexdateien verwendet werden. Sie haben hier die Standardprioritätsreihenfolge geändert und index.php vor index.html verschoben, sodass Nginx Dateien mit dem Namen index.php nach Möglichkeit priorisiert.WurzelDiese Direktive legt das Stammverzeichnis für Ihre Serveranfragen fest. Dieses Verzeichnis, `/var/www/html`, wird während des Build-Prozesses durch die Direktiven in Ihrer WordPress-Dockerfile als Mountpunkt erstellt. Diese Dockerfile-Direktiven stellen außerdem sicher, dass die WordPress-Versionsdateien auf diesem Volume installiert werden.
Standortblöcke:
Standort ~ /.well-known/acme-challengeDieser Block verarbeitet Anfragen an das Verzeichnis „.well-known“. Dort platziert Certbot eine temporäre Datei, um zu überprüfen, ob die DNS-Auflösung Ihrer Domain zu Ihrem Server führt. Mit dieser Konfiguration können Sie das Webroot-Certbot-Plugin verwenden, um ein Zertifikat für Ihre Domain zu erhalten.Standort/: In diesem Location-Block wird die try_files-Direktive verwendet, um nach Dateien zu suchen, die der angeforderten URI entsprechen. Anstatt jedoch wie standardmäßig den Statuscode 404 (Nicht gefunden) zurückzugeben, übergeben Sie die Kontrolle mit den Anfrageargumenten an die WordPress-Datei index.php.location ~ \.php$: Dieser Location-Block verarbeitet PHP-Anfragen und leitet sie an Ihren WordPress-Container weiter. Da Ihr WordPress-Docker-Image auf dem php:fpm-Image basiert, müssen Sie in diesem Block auch die FastCGI-spezifischen Konfigurationsoptionen einfügen. Nginx benötigt einen separaten PHP-Prozessor für PHP-Anfragen. In diesem Fall werden die Anfragen vom php-fpm-Prozessor verarbeitet, der im php:fpm-Image enthalten ist. Zusätzlich enthält dieser Location-Block FastCGI-spezifische Direktiven, Variablen und Optionen, die die Weiterleitung der Anfragen an die im WordPress-Container laufende WordPress-Anwendung konfigurieren, eine Präferenzliste für die geparste Anfrage-URI festlegen und die Anfrage-URI parsen.location ~ /\.htDieser Block verarbeitet .htaccess-Dateien, da Nginx diese nicht ausliefert. Die Direktive „deny_all“ stellt sicher, dass .htaccess-Dateien niemals an Benutzer ausgeliefert werden.location = /favicon.ico, location = /robots.txtDiese Blöcke stellen sicher, dass Anfragen nach /favicon.ico und /robots.txt nicht protokolliert werden.location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: Dieser Block deaktiviert die Protokollierung von Anfragen zu Anlagevermögen und stellt sicher, dass diese Anlagen gut zwischengespeichert werden können, da ihre Wartung in der Regel teuer ist.
Speichern und schließen Sie die Datei nach der Bearbeitung. Wenn Sie nano verwenden, drücken Sie dazu Strg+X, Y und anschließend die Eingabetaste. Nachdem Nginx konfiguriert ist, können Sie Umgebungsvariablen erstellen, die zur Laufzeit an Ihre Anwendungs- und Datenbankcontainer übergeben werden.
Schritt 2 – Umgebungsvariablen definieren
Ihre WordPress-Anwendungsdatenbank und -Container benötigen zur Laufzeit Zugriff auf bestimmte Umgebungsvariablen, um Ihre Anwendungsdaten verfügbar zu halten. Diese Variablen enthalten sowohl sensible als auch unkritische Informationen: sensible Werte für das MySQL-Root-Passwort sowie Benutzername und Passwort der Anwendungsdatenbank und unkritische Informationen für Datenbankname und Host. Anstatt all diese Werte in der Docker-Compose-Datei – der Hauptdatei mit den Informationen zum Betrieb Ihrer Container – festzulegen, sollten Sie die sensiblen Werte in einer separaten Umgebungsvariablendatei (.env.) definieren und deren Zugriff einschränken. Dadurch wird verhindert, dass diese Werte in Ihre Projekt-Repositories kopiert und öffentlich sichtbar werden.
Öffnen Sie im Stammverzeichnis Ihres Projekts, ~/wordpress, eine Datei namens .env:
nano .envDie in dieser Datei festgelegten geheimen Werte umfassen ein Passwort für den MySQL-Root-Benutzer sowie einen Benutzernamen und ein Passwort, die WordPress für den Datenbankzugriff verwendet. Fügen Sie der Datei die folgenden Variablennamen und -werte hinzu. Denken Sie daran, hier für jede Variable Ihre eigenen Werte anzugeben:
MYSQL_ROOT_PASSWORD=your_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=your_wordpress_database_password
Geben Sie ein Passwort für das Root-Administratorkonto sowie den gewünschten Benutzernamen und das Passwort für Ihre Anwendungsdatenbank an. Speichern und schließen Sie die Datei nach der Bearbeitung.
Da Ihre env-Datei sensible Informationen enthält, sollten Sie sicherstellen, dass sie in den .gitignore- und .dockerignore-Dateien Ihres Projekts enthalten ist. Dadurch wird Git und Docker mitgeteilt, welche Dateien nicht in Ihre Git-Repositories bzw. Docker-Images kopiert werden sollen.
Mit git init:
git initErstellen und öffnen Sie anschließend eine .gitignore-Datei:
nano .gitignoreFüge der Datei die Umgebungsvariable hinzu:
.envSpeichern und schließen Sie die Datei, wenn Sie mit der Bearbeitung fertig sind.
Ebenso ist das Hinzufügen von .env zur .dockerignore-Datei eine gute Vorsichtsmaßnahme, damit es nicht in Ihre Container aufgenommen wird, wenn Sie dieses Verzeichnis als Build-Kontext verwenden.
Öffnen Sie die Datei:
nano .dockerignoreFüge der Datei die Umgebungsvariable hinzu:
.env
Darunter können Sie optional Dateien und Verzeichnisse hinzufügen, die mit Ihrer Anwendungsentwicklung zusammenhängen:
.env
.git
docker-compose.yml
.dockerignoreSpeichern und schließen Sie die Datei, wenn Sie fertig sind.
Nachdem Sie Ihre sensiblen Informationen hinterlegt haben, können Sie nun Ihre Dienste in einer docker-compose.yml-Datei definieren.
Schritt 3 – Dienste mit Docker Compose definieren
Ihre docker-compose.yml-Datei enthält die Servicedefinitionen für Ihre Konfiguration. Ein Service in Compose ist ein laufender Container, und die Servicedefinitionen legen fest, wie jeder Container ausgeführt werden soll.
Mit Compose können Sie verschiedene Dienste definieren, um Anwendungen mit mehreren Containern auszuführen. Compose ermöglicht es Ihnen, diese Dienste über gemeinsam genutzte Netzwerke und Volumes zu verknüpfen. Dies ist für Ihre aktuelle Konfiguration nützlich, da Sie separate Container für Ihre Datenbank, Ihre WordPress-Anwendung und Ihren Webserver erstellen. Zusätzlich erstellen Sie einen Container, um den Certbot-Client auszuführen und Zertifikate für Ihren Webserver zu beziehen.
Erstellen und öffnen Sie zunächst die Datei docker-compose.yml:
nano docker-compose.ymlFügen Sie den folgenden Code hinzu, um die Version Ihrer Compose-Datei und des Datenbankdienstes zu definieren:
version: '3' services: db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network
Die Datenbankdienstdefinition umfasst die folgenden Optionen:
BildDies teilt Compose mit, welches Image zum Erstellen des Containers verwendet werden soll. Hier wird das Image mysql:8.0 festgelegt, um zukünftige Konflikte zu vermeiden, da das Image mysql:latest fortlaufend aktualisiert wird. Weitere Informationen zum Festlegen von Versionen und zum Vermeiden von Abhängigkeitskonflikten finden Sie in der Docker-Dokumentation zu Best Practices für Dockerfiles.Containername: Gibt einen Namen für den Container an.NeustartDiese Richtlinie legt fest, ob der Container neu gestartet wird. Standardmäßig ist dies nicht der Fall, Sie haben den Container jedoch so konfiguriert, dass er neu gestartet wird, sofern er nicht manuell gestoppt wird.env_fileDiese Option weist Compose an, Umgebungsvariablen aus einer Datei namens .env im Build-Kontext hinzuzufügen. In diesem Fall ist der Build-Kontext das aktuelle Verzeichnis.UmfeldDiese Option ermöglicht es Ihnen, zusätzliche Umgebungsvariablen über die in der .env-Datei definierten hinaus hinzuzufügen. Sie setzen die Variable MYSQL_DATABASE auf wordpress, um Ihrer Anwendungsdatenbank einen Namen zu geben. Da diese Information nicht sensibel ist, können Sie sie direkt in die docker-compose.yml-Datei einfügen.BändeHier binden Sie ein Volume namens dbdata im Ordner /var/lib/mysql des Containers ein. Dies ist das Standard-Datenverzeichnis für MySQL auf den meisten Distributionen.BefehlDiese Option gibt einen Befehl an, der den Standard-CMD-Befehl für das Image überschreibt. In diesem Fall fügen Sie dem Standardbefehl `mysqld` des Docker-Images, der den MySQL-Server im Container startet, eine Option hinzu. Diese Option, `--default-authentication-plugin=mysql_native_password`, setzt die Systemvariable `--default-authentication-plugin` auf `mysql_native_password` und legt fest, welcher Authentifizierungsmechanismus für neue Authentifizierungsanfragen an den Server verwendet werden soll. Da PHP und somit auch Ihr WordPress-Image die neue MySQL-Standardauthentifizierung nicht unterstützen, müssen Sie diese Option konfigurieren, um Ihren Anwendungsdatenbankbenutzer zu authentifizieren.- Netzwerke: Hiermit wird festgelegt, dass sich Ihr Anwendungsdienst dem Anwendungsnetzwerk anschließt, das Sie am Ende der Datei definieren.
Fügen Sie anschließend unterhalb Ihrer Datenbankdienstdefinition Ihre WordPress-Anwendungsdienstdefinition hinzu:
... wordpress: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: wordpress restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - wordpress:/var/www/html networks: - app-network
In dieser Dienstdefinition benennen Sie Ihren Container und definieren eine Neustartrichtlinie, genau wie beim Datenbankdienst. Außerdem fügen Sie diesem Container einige spezifische Optionen hinzu:
abhängig vonDiese Option stellt sicher, dass Ihre Container in der Reihenfolge ihrer Abhängigkeiten gestartet werden, wobei der WordPress-Container nach dem Datenbank-Container startet. Ihre WordPress-Anwendung benötigt die Datenbank und den Anwendungsbenutzer. Durch die Angabe dieser Abhängigkeitsreihenfolge wird ein ordnungsgemäßer Start Ihrer Anwendung gewährleistet.BildFür diese Konfiguration verwenden Sie das WordPress-Image 5.1.1-fpm-alpine. Wie in Schritt 1 erläutert, stellt dieses Image sicher, dass Ihre Anwendung über den php-fpm-Prozessor verfügt, den Nginx für die PHP-Verarbeitung benötigt. Es handelt sich dabei um ein Alpine-Image, das vom Alpine-Linux-Projekt abgeleitet ist und so die Gesamtgröße Ihres Images reduziert. Weitere Informationen zu den Vor- und Nachteilen von Alpine-Images und ob diese für Ihre Anwendung sinnvoll sind, finden Sie in der ausführlichen Beschreibung im Abschnitt „Image-Varianten“ auf der WordPress-Docker-Hub-Image-Seite.env_fileSie geben also erneut an, dass Sie Werte aus Ihrer .env-Datei extrahieren möchten, da Sie dort Ihren Anwendungsdatenbankbenutzer und Ihr Passwort definiert haben.UmfeldHier verwenden Sie die Werte aus Ihrer .env-Datei und weisen sie den Variablennamen zu, die das WordPress-Image erwartet: WORDPRESS_DB_USER und WORDPRESS_DB_PASSWORD. Außerdem definieren Sie einen WORDPRESS_DB_HOST, der auf den MySQL-Server verweist, der im Datenbankcontainer über den Standard-MySQL-Port 3306 erreichbar ist. Ihr WORDPRESS_DB_NAME entspricht dem Wert, den Sie in Ihrer MySQL-Dienstdefinition für MYSQL_DATABASE angegeben haben: wordpress.BändeSie binden ein Volume namens „wordpress“ auf dem Mountpunkt „/var/www/html“ ein, der vom WordPress-Image erstellt wurde. Durch die Verwendung eines benannten Volumes auf diese Weise können Sie Ihren Anwendungscode mit anderen Containern teilen.NetzwerkSie fügen außerdem den WordPress-Container dem Anwendungsnetzwerk hinzu.
Fügen Sie anschließend unter der WordPress-Anwendungsdienstdefinition die folgende Definition für Ihren Nginx-Webserverdienst hinzu:
... webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network
Hier benennen Sie Ihren Container und machen ihn vom WordPress-Container in der Hauptreihenfolge abhängig. Außerdem verwenden Sie ein Alpine-Image – das Nginx-Image 1.15.12-alpine.
Diese Servicedefinition umfasst auch die folgenden Optionen:
HäfenDadurch wird Port 80 freigegeben, um die Konfigurationsoptionen zu aktivieren, die Sie in Schritt 1 in Ihrer nginx.conf-Datei definiert haben.BändeHier definieren Sie eine Kombination aus benannten Volumes und Mountpunkten:- wordpress:/var/www/html: Dieser Code platziert Ihre WordPress-Anwendung im Ordner /var/www/html, dem Verzeichnis, das Sie in Ihrem Nginx-Serverblock als Stammverzeichnis festgelegt haben.
./nginx-conf:/etc/nginx/conf.dDadurch wird der Nginx-Konfigurationsordner auf dem Host mit dem entsprechenden Verzeichnis im Container verbunden, sodass sichergestellt wird, dass alle Änderungen, die Sie an den Dateien auf dem Host vornehmen, auch auf dem Host widergespiegelt werden.certbot-etc:/etc/letsencryptDadurch werden die Let's Encrypt-Zertifikate und -Schlüssel für Ihre Domain im entsprechenden Verzeichnis auf dem Container installiert.
Sie haben diesen Container auch dem Anwendungsnetzwerk hinzugefügt.
Fügen Sie abschließend unter Ihrer Webserver-Definition Ihre endgültige Dienstdefinition für den Certbot-Dienst hinzu. Ersetzen Sie dabei unbedingt die hier aufgeführte E-Mail-Adresse und den Domainnamen durch Ihre eigenen Daten:
certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - wordpress:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
Diese Definition weist Compose an, das Image `certbot/certbot` von Docker Hub abzurufen. Außerdem werden benannte Volumes verwendet, um Ressourcen mit dem Nginx-Container zu teilen, darunter Domänenzertifikate und -schlüssel in `certbot-etc` sowie Anwendungscode in WordPress. Sie haben `dependent_on` verwendet, um festzulegen, dass der certbot-Container nach dem Start des Webservers gestartet werden soll. Zusätzlich haben Sie die Option `command` hinzugefügt, die einen Unterbefehl angibt, der mit dem Standardbefehl `certbot` des Containers ausgeführt wird. Der Unterbefehl `certonly` ruft das Zertifikat mit den folgenden Optionen ab:
--webrootDies weist Certbot an, das Webroot-Plugin zu verwenden, um Dateien zur Authentifizierung im Webroot-Ordner abzulegen. Das Plugin nutzt die HTTP-01-Authentifizierungsmethode, die mittels einer HTTP-Anfrage beweist, dass Certbot auf Ressourcen eines Servers zugreifen kann, der auf einen bestimmten Domainnamen antwortet.--webroot-pathDies gibt den Pfad zum Webroot-Verzeichnis an.--E-MailIhre gewünschte E-Mail-Adresse für Registrierung und Wiederherstellung.--agree-tos: Dies bedeutet, dass Sie der ACME-Gemeinschaftsvereinbarung zustimmen.--no-eff-emailDies teilt Certbot mit, dass Sie Ihre E-Mail-Adresse nicht mit der Electronic Frontier Foundation (EFF) teilen möchten. Sie können dies entfernen, wenn Sie dies wünschen.--stagingDiese Option teilt Certbot mit, dass Sie die Let's Encrypt-Testumgebung verwenden möchten, um Testzertifikate zu erhalten. So können Sie Ihre Konfigurationseinstellungen testen und mögliche Beschränkungen der Domain-Anfrage umgehen. Weitere Informationen zu diesen Beschränkungen finden Sie in der Dokumentation zu den Let's Encrypt-Ratenbegrenzungen.-DHiermit können Sie die Domainnamen angeben, die Sie für Ihre Anfrage verwenden möchten. In diesem Fall haben Sie „your_domain“ und „www.your_domain“ eingegeben. Ersetzen Sie diese bitte durch Ihre eigene Domain.
Fügen Sie unterhalb der certbot-Dienstdefinition Ihre Netzwerk- und Volumendefinitionen hinzu:
... volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Der Volume-Schlüssel der obersten Ebene definiert die Volumes certbot-etc, wordpress und dbdata. Beim Erstellen der Volumes durch Docker werden deren Inhalte in einem Verzeichnis auf dem Host-Dateisystem unter /var/lib/docker/volumes/ gespeichert, das von Docker verwaltet wird. Die Inhalte jedes Volumes werden dann von diesem Verzeichnis in jeden Container eingebunden, der das Volume verwendet. Dadurch können Code und Daten zwischen Containern ausgetauscht werden.
Das benutzerdefinierte Bridge-Netzwerk ermöglicht die Kommunikation zwischen Ihren Containern, da diese sich auf demselben Host wie der Docker-Daemon befinden. Dies vereinfacht den Datenverkehr und die Kommunikation innerhalb der Anwendung, da alle Ports zwischen Containern im selben Bridge-Netzwerk geöffnet werden, ohne dass Ports nach außen freigegeben werden. So können Ihre Datenbank-, WordPress- und Webserver-Container miteinander kommunizieren, und Sie müssen lediglich Port 80 für den Frontend-Zugriff auf die Anwendung freigeben.
Die vollständige docker-compose.yml-Datei wird unten angezeigt:
version: '3' services: db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network wordpress: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: wordpress restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - wordpress:/var/www/html networks: - app-network webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - wordpress:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Speichern und schließen Sie die Datei, wenn Sie die Bearbeitung abgeschlossen haben. Nachdem Ihre Dienstdefinitionen eingerichtet sind, können Sie Container starten und Ihre Zertifikatsanforderungen testen.
Schritt 4 – SSL-Zertifikate und Zugangsdaten beschaffen
Starten Sie Ihre Container mit dem Befehl `docker-compose up`. Dieser erstellt und startet Ihre Container in der von Ihnen angegebenen Reihenfolge. Durch Hinzufügen des Flags `-d` werden die Container für Datenbank, WordPress und Webserver im Hintergrund ausgeführt.
docker-compose up -dDie folgende Ausgabe bestätigt, dass Ihr Dienst erstellt wurde:
Output
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... doneÜberprüfen Sie den Status Ihrer Dienste mit docker-compose ps:
docker-compose psNach Abschluss des Vorgangs sind Ihre Datenbank-, WordPress- und Webserver-Dienste wieder verfügbar und der Certbot-Container beendet sich mit der Statusmeldung 0:
Output
Name Command State Ports
-------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcpAlles andere als die oben genannten Werte in der Spalte „Status“ für die Dienste „db“, „wordpress“ oder „webserver“ oder ein Exit-Status ungleich 0 für den „certbot“-Container bedeutet, dass Sie möglicherweise die Dienstprotokolle mit dem Befehl „docker-compose logs“ überprüfen müssen:
docker-compose logs service_nameSie können nun mit docker-compose exec überprüfen, ob Ihre Zertifikate im Webserver-Container installiert wurden:
docker-compose exec webserver ls -la /etc/letsencrypt/liveWenn Ihre Zertifikatsanforderungen erfolgreich waren, sieht die Ausgabe des Codes wie folgt aus:
Output
total 16
drwx------ 3 root root 4096 May 10 15:45 .
drwxr-xr-x 9 root root 4096 May 10 15:45 ..
-rw-r--r-- 1 root root 740 May 10 15:45 README
drwxr-xr-x 2 root root 4096 May 10 15:45 your_domainNachdem Sie nun wissen, dass Ihre Anfrage erfolgreich war, können Sie die certbot-Dienstdefinition bearbeiten und die Option --staging entfernen.
Öffnen Sie docker-compose.yml:
nano docker-compose.ymlSuchen Sie den Teil der Datei mit der Certbot-Dienstdefinition und ersetzen Sie die Option `--staging` in der Befehlszeile durch `--force-renewal`. Dadurch wird Certbot angewiesen, ein neues Zertifikat für dieselben Domains anzufordern. Das Zertifikat wird unterhalb der Certbot-Dienstdefinition mit der entsprechenden Variable aktualisiert.
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
...Jetzt können Sie docker-compose ausführen, um den certbot-Container neu zu erstellen. Fügen Sie außerdem die Option `--no-deps` hinzu, um Compose mitzuteilen, dass der Webserver-Dienst übersprungen werden kann, da er bereits läuft.
docker-compose up --force-recreate --no-deps certbotDie folgende Ausgabe zeigt an, dass Ihre Zertifikatsanforderung erfolgreich war:
Output Recreating certbot ... done Attaching to certbot certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | Plugins selected: Authenticator webroot, Installer None certbot | Renewing an existing certificate certbot | Performing the following challenges: certbot | http-01 challenge for your_domain certbot | http-01 challenge for www.your_domain certbot | Using the webroot path /var/www/html for all unmatched domains. certbot | Waiting for verification... certbot | Cleaning up challenges certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/your_domain/privkey.pem certbot | Your cert will expire on 2019-08-08. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0
Mit Ihren Zertifikaten können Sie Ihre Nginx-Konfiguration so anpassen, dass SSL enthalten ist.
Schritt 5 – Ändern Sie die Webserver-Konfiguration und die Dienstdefinition
Die Aktivierung von SSL in der Nginx-Konfiguration erfordert das Hinzufügen einer HTTP-zu-HTTPS-Weiterleitung, die Angabe der Speicherorte für SSL-Zertifikat und -Schlüssel sowie das Hinzufügen von Sicherheitsparametern und -headern. Da Sie den Webserver neu kompilieren möchten, um diese Ergänzungen zu integrieren, können Sie ihn jetzt stoppen.
docker-compose stop webserverBevor Sie die Konfigurationsdatei ändern, rufen Sie die empfohlenen Nginx-Sicherheitsparameter von Certbot mit curl ab:
curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.confDieser Befehl speichert diese Parameter in einer Datei namens options-ssl-nginx.conf, die sich im Verzeichnis nginx-conf befindet.
Löschen Sie anschließend die zuvor erstellte Nginx-Konfigurationsdatei:
rm nginx-conf/nginx.confErstellen und öffnen Sie eine weitere Version der Datei:
nano nginx-conf/nginx.confFügen Sie den folgenden Code in die Datei ein, um HTTP auf HTTPS umzuleiten und die Anmeldeinformationen, Protokolle und SSL-Sicherheitsheader hinzuzufügen. Vergessen Sie nicht, „your_domain“ durch Ihre Domain zu ersetzen:
server { listen 80; listen [::]:80; server_name your_domain www.your_domain; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { rewrite ^ https://$host$request_uri? permanent; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name your_domain www.your_domain; index index.php index.html index.htm; root /var/www/html; server_tokens off; ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem; include /etc/nginx/conf.d/options-ssl-nginx.conf; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # enable strict transport security only if you understand the implications location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass wordpress:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } }
Der HTTP-Server-Block legt das Webroot für Certbot-Erneuerungsanfragen im Verzeichnis .well-known/acme-challenge fest. Er enthält außerdem eine Rewrite-Anweisung, die HTTP-Anfragen über HTTPS an das Stammverzeichnis weiterleitet.
Der HTTPS-Serverblock aktiviert SSL und HTTP/2. Weitere Informationen darüber, wie HTTP/2 in HTTP-Protokollen implementiert wird und welche Vorteile dies für die Website-Performance bietet, finden Sie in der Einführung zu „So richten Sie Nginx mit HTTP/2-Unterstützung unter Ubuntu 18.04 ein“.
Dieser Block enthält außerdem die Speicherorte Ihres SSL-Zertifikats und -Schlüssels sowie die empfohlenen Certbot-Sicherheitsparameter, die Sie in nginx-conf/options-ssl-nginx.conf gespeichert haben.
Zusätzlich sind einige Sicherheitsheader enthalten, die Ihnen ermöglichen, bei Tests wie SSL Labs und Security Headers Servertestseiten eine A-Bewertung zu erhalten. Zu diesen Headern gehören X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy und X-XSS-Protection. Der HTTP Strict Transport Security (HSTS)-Header wird erläutert – aktivieren Sie ihn nur, wenn Sie die Konzepte verstehen und seine “Preload”-Funktionalität getestet haben.
In diesem Block befinden sich auch Ihre Root- und Verzeichnisanweisungen sowie die übrigen WordPress-spezifischen Standortblöcke, die in Schritt 1 besprochen wurden. Speichern und schließen Sie die Datei, sobald Sie mit der Bearbeitung fertig sind.
Bevor Sie den Webserverdienst neu erstellen, müssen Sie Ihrer Webserverdienstdefinition eine Portzuordnung für Port 443 hinzufügen.
Öffnen Sie Ihre docker-compose.yml-Datei:
nano docker-compose.ymlFügen Sie in der Webserver-Dienstdefinition die folgende Portzuordnung hinzu:
...
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-networkHier ist die vollständige docker-compose.yml-Datei nach der Bearbeitung:
version: '3' services: db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network wordpress: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: wordpress restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - wordpress:/var/www/html networks: - app-network webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - wordpress:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Speichern und schließen Sie die Datei, wenn Sie mit der Bearbeitung fertig sind.
Webserverdienst neu erstellen:
docker-compose up -d --force-recreate --no-deps webserverÜberprüfen Sie Ihre Dienste mit docker-compose ps:
docker-compose psDie Ausgabe sollte zeigen, dass Ihre Datenbank-, WordPress- und Webserverdienste laufen:
Output
Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcpSobald die Container laufen, können Sie Ihre WordPress-Installation über die Weboberfläche abschließen.
Schritt 6 – Schließen Sie die Installation über die Weboberfläche ab
Während Ihre Container laufen, schließen Sie die Installation über die WordPress-Weboberfläche ab.
Öffnen Sie in Ihrem Webbrowser die Adresse Ihrer Serverdomain. Vergessen Sie nicht, „your_domain“ durch Ihren Domainnamen zu ersetzen:
https://your_domainWählen Sie die gewünschte Sprache aus:
Nach dem Klick auf “Weiter” gelangen Sie zur Haupteinrichtungsseite. Dort wählen Sie einen Namen für Ihre Website und einen Benutzernamen. Es empfiehlt sich, einen einprägsamen Benutzernamen (z. B. nicht „admin“) und ein sicheres Passwort zu wählen. Sie können das von WordPress automatisch generierte Passwort verwenden oder ein eigenes erstellen. Abschließend geben Sie Ihre E-Mail-Adresse ein und entscheiden, ob Suchmaschinen Ihre Website nicht indexieren sollen.
Wenn Sie unten auf der Seite auf „WordPress installieren“ klicken, werden Sie zu einer Anmeldemaske weitergeleitet:
Sobald Sie sich angemeldet haben, haben Sie Zugriff auf das WordPress-Admin-Dashboard:
Sobald Sie die Installation von WordPress abgeschlossen haben, können Sie Maßnahmen ergreifen, um sicherzustellen, dass Ihre SSL-Zertifikate automatisch erneuert werden.
Schritt 7 – Erneuerung der Zertifikate
Let's Encrypt-Zertifikate sind 90 Tage gültig. Sie können eine automatische Verlängerung einrichten, um deren Ablauf zu verhindern. Eine Möglichkeit hierfür ist die Erstellung eines Cronjobs. Im folgenden Beispiel erstellen Sie einen Cronjob, der regelmäßig ein Skript ausführt, das Ihre Zertifikate erneuert und Ihre Nginx-Konfiguration neu lädt.
Öffnen Sie zunächst ein Skript namens ssl_renew.sh:
nano ssl_renew.shFügen Sie den folgenden Code zum Skript hinzu, um Ihre Zertifikate zu erneuern und Ihre Webserver-Konfiguration neu zu laden. Ersetzen Sie dabei den Beispielbenutzernamen durch Ihren Benutzernamen (kein Root-Benutzername):
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/wordpress/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Dieses Skript weist zunächst die docker-compose-Binärdatei einer Variablen namens COMPOSE zu und gibt die Option `--no-ansi` an, wodurch die docker-compose-Befehle ohne ANSI-Steuerzeichen ausgeführt werden. Anschließend wird dasselbe mit der docker-Binärdatei durchgeführt. Abschließend wechselt es in das Projektverzeichnis `~/wordpress` und führt die folgenden docker-compose-Befehle aus:
-
docker-composeDieser Befehl startet einen Certbot-Container und überschreibt den in Ihrer Certbot-Dienstdefinition angegebenen Befehl. Anstelle des Unterbefehls `certonly` wird der Unterbefehl `renew` verwendet, der Zertifikate erneuert, deren Gültigkeit bald abläuft. Die Option `--dry-run` zum Testen Ihres Skripts ist ebenfalls enthalten. docker-compose killDies sendet ein SIGHUP-Signal an den Webserver-Container, um die Nginx-Konfiguration neu zu laden.
Anschließend führt das System den Befehl docker prune aus, um alle nicht verwendeten Container und Images zu entfernen.
Nachdem Sie die Bearbeitung der Datei abgeschlossen haben, schließen Sie sie. Machen Sie sie mit folgendem Befehl ausführbar:
chmod +x ssl_renew.shÖffnen Sie anschließend Ihre Crontab-Datei im Stammverzeichnis, um das Erneuerungsskript in einem festgelegten Zeitintervall auszuführen:
sudo crontab -eWenn Sie diese Datei zum ersten Mal bearbeiten, werden Sie aufgefordert, einen Bearbeiter auszuwählen:
Outputno crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano <---- easiest 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...
Fügen Sie am Ende dieser Datei die folgende Zeile hinzu:
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1Dadurch wird das Jobintervall auf fünf Minuten festgelegt, sodass Sie überprüfen können, ob Ihre Verlängerungsanfrage wie gewünscht funktioniert hat. Eine Protokolldatei, cron.log, wird erstellt, um die relevanten Ausgaben des Jobs aufzuzeichnen.
Überprüfen Sie nach fünf Minuten die Datei cron.log, um zu bestätigen, ob die Erweiterungsanfrage erfolgreich war:
tail -f /var/log/cron.logDie folgende Ausgabe bestätigt eine erfolgreiche Erweiterung:
Output- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Beenden Sie das Programm mit der Tastenkombination STRG+C im Terminal.
Sie können die Crontab-Datei bearbeiten, um ein tägliches Intervall festzulegen. Um das Skript beispielsweise jeden Tag um 12 Uhr mittags auszuführen, ändern Sie die letzte Zeile der Datei wie folgt:
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1Sie sollten außerdem die Option --dry-run aus Ihrem Skript ssl_renew.sh entfernen:
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/wordpress/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Ihr Cronjob sorgt dafür, dass Ihre Let's Encrypt-Zertifikate nicht ablaufen, indem er sie rechtzeitig erneuert. Sie können außerdem mit dem Tool Logrotate in Ubuntu 22.04/20.04 die Protokollrotation einrichten, um Ihre Protokolldateien zu rotieren und zu komprimieren.
Ergebnis
In diesem Tutorial haben Sie mithilfe von Docker Compose eine WordPress-Installation mit dem Nginx-Webserver erstellt. Im Rahmen dieses Workflows haben Sie TLS/SSL-Zertifikate für die Domain erhalten, die Sie mit Ihrer WordPress-Website verknüpfen möchten. Außerdem haben Sie einen Cronjob eingerichtet, um diese Zertifikate bei Bedarf zu erneuern.













