One place for hosting & domains

      So installieren Sie Drupal mit Docker Compose


      Der Autor hat die United Nations Foundation dazu ausgewählt, im Rahmen des Programms Write for DOnations eine Spende zu erhalten.

      Die ursprüngliche WordPress-Version dieses Tutorials wurde von Kathleen Juell verfasst.

      Einführung

      Drupal ist ein Content-Management-System (CMS), das in PHP geschrieben und unter der Open-Source-Lizenz GNU General Public License vergeben wird. Menschen und Organisationen in der ganzen Welt verwenden Drupal, um öffentliche Websites, persönliche Blogs, Unternehmen und mehr zu betreiben. Was Drupal von anderen CMS-Frameworks abhebt, ist seine wachsende Community und eine Reihe von Funktionen, die sichere Prozesse, zuverlässige Leistung, Modularität und Flexibilität zur Anpassung umfassen.

      Drupal erfordert die Installation des LAMP-Stacks (Linux, Apache, MySQL und PHP) oder des LEMP-Stacks (Linux, Nginx, MySQL und PHP), aber das Installieren einzelner Komponenten ist eine zeitaufwendige Aufgabe. Wir können Tools wie Docker und Docker Compose verwenden, um den Prozess der Installation von Drupal zu vereinfachen. Dieses Tutorial verwendet Docker-Images zur Installation einzelner Komponenten in den Docker-Containern. Mit der Verwendung von Docker Compose können wir mehrere Container für die Datenbank, die Anwendung und für die Vernetzung/Kommunikation zwischen ihnen definieren und verwalten.

      In diesem Tutorial installieren wir Drupal mit Docker Compose, damit wir die Containerisierung nutzen und unsere Drupal-Website auf Servern bereitstellen können. Wir führen Container für eine MySQL-Datenbank, einen Nginx-Webserver und Drupal aus. Außerdem sichern wir unsere Installation, indem wir TLS/SSL Zertifikate mit Let’s Encrypt für die Domäne erlangen, die wir mit unserer Website verknüpfen möchten. Schließlich richten wir einen cron-Job ein, um unsere Zertifikate zu erneuern, damit unsere Domäne sicher bleibt.

      Voraussetzungen

      Um diesem Tutorial zu folgen, benötigen Sie:

      • Einen Server, auf dem Ubuntu 18.04 ausgeführt wird, zusammen mit einem non-root user mit sudo-Privilegien und einer aktiven Firewall. Eine Anleitung für das Setup finden Sie im Leitfaden für die Ersteinrichtung des Servers.
      • Docker, gemäß Schritt 1 und 2 unter So installieren und verwenden Sie Docker unter Ubuntu 18.04 auf Ihrem Server installiert. Dieses Tutorial wurde unter der Version 19.03.8 getestet.
      • Docker Compose, gemäß Schritt 1 unter So installieren Sie Compose unter Ubuntu 18.04 auf Ihrem Server installiert. Dieses Tutorial wurde unter der Version 1.21.2 getestet.
      • Einen registrierten Domänennamen. Dieses Tutorial verwendet in allen Bereichen your_domain. Einen Domänennamen können Sie kostenlos bei Freenom erhalten oder Sie nutzen eine Domänenregistrierungsstelle Ihrer Wahl.
      • Die beiden folgenden DNS-Einträge für Ihren Server eingerichtet. Falls Sie ein DigitalOcean-Konto nutzen, können Sie in der Einführung in DigitalOcean-DNS im Einzelnen nachlesen, wie Sie diese hinzufügen:
        • Einen A-Eintrag mit your_domain, der auf die öffentliche IP-Adresse Ihres Servers verweist.
        • Einen A-Eintrag mit www.your_domain, der auf die öffentliche IP-Adresse Ihres Servers verweist.

      Schritt 1 — Definieren der Webserver-Konfiguration

      Bevor wir Container ausführen, müssen wir die Konfiguration für unseren Nginx-Webserver definieren. Unsere Konfigurationsdatei enthält einige Drupal-spezifische Location-Blocks, zusammen mit einem Location-Block zur Weiterleitung von Verifizierungsanforderungen von Let’s Encrypt an den Certbot-Client für automatisierte Zertifikatserneuerungen.

      Zuerst erstellen wir ein Projektverzeichnis für unser Drupal-Setup namens drupal:

      Rufen Sie das neu erstellte Verzeichnis auf:

      Nun können wir ein Verzeichnis für unsere Konfigurationsdatei erstellen:

      Öffnen Sie die Datei mit nano oder Ihrem bevorzugten Texteditor:

      • nano nginx-conf/nginx.conf

      In dieser Datei fügen wir einen Serverblock mit Anweisungen für unseren Servernamen und die Dokumenten-root hinzu sowie Location-Blocks, um die Anforderung des Certbot-Clients nach Zertifikaten, PHP-Verarbeitung und statischen Asset-Anforderungen zu leiten.

      Fügen Sie den folgenden Code in die Datei ein. Achten Sie darauf, your_domain durch Ihren eigenen Domänennamen zu ersetzen:

      ~/drupal/nginx-conf/nginx.conf

      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;
          }
      
          rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
      
          location ~ .php$ {
              try_files $uri =404;
              fastcgi_split_path_info ^(.+.php)(/.+)$;
              fastcgi_pass drupal: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:

      • listen: Diese weist Nginx an, an Port 80 zu lauschen, sodass wir das Webroot-Plugin von Certbot für unsere Zertifikatsanforderungen nutzen können. Beachten Sie, dass wir noch nicht Port 443 einschließen – wir aktualisieren unsere Konfiguration, um SSL einzuschließen, sobald wir erfolgreich unsere Zertifikate erlangt haben.

      • server_name: Damit definieren Sie den Servernamen und den Serverblock, der für Anfragen an den Server verwendet werden sollte. Achten Sie darauf, your_domain in dieser Zeile durch Ihren eigenen Domänennamen zu ersetzen.

      • index: Die Anweisung index definiert die Dateien, die als Indizes bei der Verarbeitung von Anfragen an unseren Server dienen. Wir haben hier die Standardreihenfolge der Priorität geändert und index.php vor index.html geschoben, damit Nginx Dateien namens index.php wenn möglich priorisiert.

      • root: Unsere root-Anweisung benennt das root-Verzeichnis für Anfragen an unseren Server. Dieses Verzeichnis, /var/www/html, wird als Bereitstellungspunkt in der Erstellungszeit durch Anweisungen in unserer Drupal Dockerfile erstellt. Diese Dockerfile-Anweisungen stellen auch sicher, dass die Dateien aus der Drupal-Version auf diesem Volume bereitgestellt werden.

      • rewrite: Wenn die angegebene reguläre Expression (^/core/authorize.php/core/authorize.php(.*)$) mit einer URI-Anfrage übereinstimmt, wird die URI wie in der Ersatzzeichenfolge (/core/authorize.php$1) angegeben geändert.

      Location-Blocks:

      • location ~ /.well-known/acme-challenge: Dieser Location-Block verwaltet Anfragen an das Verzeichnis .well-known, in dem Certbot eine temporäre Datei ablegt, um zu validieren, dass das DNS für unsere Domäne auf unserem Server aufgelöst wird. Mit dieser Konfiguration können wir das Webroot-Plugin von Certbot verwenden, um Zertifikate für unsere Domäne zu erlangen.

      • location /: In diesem Location-Block verwenden wir eine try_files-Anweisung, um nach Dateien zu suchen, die individuellen URI-Anfragen entsprechen. Anstatt jedoch einen 404 Not Found-Status auszugeben, übergeben wir die Steuerung an die Datei index.php von Drupal mit den Anforderungsargumenten.

      • location ~ .php$: Dieser Location-Block verwaltet die PHP-Verarbeitung und überträgt diese Anfragen an unseren drupal-Container. Da unser Drupal-Docker-Image auf dem php:fpm-Image basiert, schließen wir auch Konfigurationsoptionen ein, die in diesem Block für das FastCGI-Protokoll spezifisch sind. Nginx erfordert einen unabhängigen PHP-Prozessor für PHP-Anfragen: In unserem Fall werden diese Anfragen vom php-fpm-Prozessor verwaltet, der im php:fpm-Image enthalten ist. Außerdem enthält dieser Location-Block FastCGI-spezifische Anweisungen, Variablen und Optionen, die Anfragen an die in unserem Drupal-Container ausgeführte Drupal-Anwendung überträgt, den bevorzugten Index für die analysierte Anfrage-URI festlegt und URI-Anfragen analysiert.

      • location ~ /.ht: Dieser Block verwaltet .htaccess-Dateien, da Nginx diese nicht bedient. Die Anweisung deny_all stellt sicher, dass .htaccess-Dateien nie für Benutzer bereitgestellt werden.

      • location = /favicon.ico, location = /robots.txt: Diese Blocks stellen sicher, dass Anfragen an /favicon.ico und /robots.txt nicht protokolliert werden.

      • location ~* . (css|gif|ico|jpeg|jpg|js|png)$: Dieser Block schaltet die Protokollierung für statische Asset-Anfragen ab und stellt sicher, dass diese Assets in hohem Maße zwischenspeicherbar sind, da ihre Bereitstellung in der Regel aufwendig ist.

      Weitere Informationen zu FastCGI-Proxying finden Sie in Verstehen und Implementieren von FastCGI-Proxying in Nginx. Informationen zu Server- und Location-Blocks finden Sie in Verstehen von Nginx-Server- und Location-Block-Auswahlalgorithmen.

      Wenn die Bearbeitung abgeschlossen wurde, speichern und schließen Sie die Datei.

      Nach Einrichtung der Nginx-Konfiguration können Sie Umgebungsvariablen erstellen, die zur Laufzeit an Ihre Anwendungs- und Datenbankcontainer übergeben werden.

      Schritt 2 — Definieren der Umgebungsvariablen

      Unsere Drupal-Anwendung benötigt eine Datenbank (MySQL, PostgresSQL, etc.) zum Speichern von Informationen im Zusammenhang mit der Website. Der Drupal-Container benötigt Zugriff auf bestimmte Umgebungsvariablen zur Laufzeit, um Zugriff auf den Datenbank-Container (MySQL) zu ermöglichen. Diese Variablen enthalten sensible Informationen wie die Zugangsdaten der Datenbank, sodass wir sie nicht direkt in der Docker-Compose-Datei offenlegen können – der Hauptdatei, die Informationen darüber enthält, wie unsere Container ausgeführt werden.

      Es wird immer empfohlen, die sensiblen Werte in der .env-Datei festzulegen und ihre Zirkulation zu beschränken. Dadurch werden diese Werte nicht in unsere Projekt-Repositorys kopiert und öffentlich verfügbar gemacht.

      Erstellen und öffnen Sie im Haupt-Projektverzeichnis ~/drupal eine Datei namens .env:

      Fügen Sie die folgenden Variablen in die .env-Datei ein und ersetzen Sie dabei die hervorgehobenen Abschnitte mit den Zugangsdaten, die Sie verwenden möchten:

      ~/drupal/.env

      MYSQL_ROOT_PASSWORD=root_password
      MYSQL_DATABASE=drupal
      MYSQL_USER=drupal_database_user
      MYSQL_PASSWORD=drupal_database_password
      

      Wir haben nun das Passwort für das MySQL-root-Administratorkonto sowie unseren bevorzugten Benutzernamen und das Passwort für unsere Anwendungsdatenbank hinzugefügt.

      Unsere .env-Datei enthält sensible Informationen. Es wird daher immer empfohlen, sie in die .gitignore– und .dockerignore-Dateien des Projekts einzufügen, damit sie nicht in unseren Git-Repositorys und Docker-Images hinzugefügt werden.

      Wenn Sie mit Git zur Versionskontrolle arbeiten möchten, initialisieren Sie Ihr aktuelles Arbeitsverzeichnis als ein Repository mit git init:

      Öffnen Sie die .gitignore-Datei:

      Fügen Sie Folgendes hinzu:

      ~/drupal/.gitignore

      .env
      

      Speichern und schließen Sie die Datei.

      Öffnen Sie in ähnlicher Weise die .dockerignore-Datei:

      Fügen Sie Folgendes hinzu:

      ~/drupal/.dockerignore

      .env
      .git
      

      Speichern und schließen Sie die Datei.

      Wir haben nun die Maßnahmen zur Sicherung unserer Zugangsdaten als Umgebungsvariablen ergriffen. Im nächsten Schritt definieren wir unsere Dienste in einer docker-compose.yml-Datei.

      Schritt 3 — Definieren der Dienste mit Docker Compose

      Docker Compose ist ein Tool zum Definieren und Ausführen von Docker-Anwendungen mit mehreren Containern. Wir definieren eine YAML-Datei, um die Dienste unserer Anwendung zu konfigurieren. Ein Dienst oder service in Docker Compose ist ein Container, der ausgeführt wird. Compose ermöglicht uns, diese Dienste zusammen mit geteilten Volumes und Netzwerken zu verknüpfen.

      Wir erstellen verschiedene Container für die Drupal-Anwendung, die Datenbank und den Webserver. Außerdem erstellen wir einen Container, der Certbot ausführt, um Zertifikate für unseren Webserver zu erlangen.

      Erstellen Sie eine docker-compose.yml-Datei:

      Fügen Sie den folgenden Code hinzu, um die Compose-Dateiversion und den mysql-Datenbankdienst zu definieren:

      ~/drupal/docker-compose.yml

      version: "3"
      
      services:
        mysql:
          image: mysql:8.0
          container_name: mysql
          command: --default-authentication-plugin=mysql_native_password
          restart: unless-stopped
          env_file: .env
          volumes:
            - db-data:/var/lib/mysql
          networks:
            - internal
      

      Wir behandeln diese nacheinander mit allen Konfigurationsoptionen des mysql-Dienstes:

      • image: Hiermit wird das Image festgelegt, das wir zum Erstellen des Containers verwenden/pullen. Es wird immer empfohlen, das Image mit dem richtigen Versions-Tag unter Ausschluss des latest-Tags zu verwenden, um zukünftige Konflikte zu vermeiden. Lesen Sie dazu mehr in Best Practices für Dockerfiles in der Docker-Dokumentation.

      • container_name: Hiermit wird der Name des Containers definiert.

      • command: Diese Option wird verwendet, um den Standardbefehl (CMD-Instruktion) im Image zu überschreiben. MySQL hat verschiedene Authentifizierungs-Plugins unterstützt, aber mysql_native_password ist die traditionelle Methode zur Authentifizierung. Da PHP und damit Drupal nicht die neuere MySQL-Authentifizierung unterstützen, müssen wir das --default-authentication-plugin=mysql_native_password als standardmäßigen Authentifizierungsmechanismus festlegen.

      • restart: Diese Option wird verwendet, um die Neustartregel des Containers festzulegen. Die Regel unless-stopped startet einen Container neu, bis er manuell gestoppt wird.

      • env_file: Hiermit werden die Umgebungsvariablen aus einer Datei hinzugefügt. In unserem Fall werden die Umgebungsvariablen aus der im vorherigen Schritt definierten .env-Datei gelesen.

      • volumes: Hiermit werden Host-Pfade oder benannte Volumes, die als Suboptionen eines Dienstes angegeben sind, bereitgestellt. Wir stellen ein benanntes Volume namens db-data im Verzeichnis /var/lib/mysql des Containers bereit, in der MySQL standardmäßig seine Datendateien schreibt.

      • networks: Hiermit wird das internal-Netzwerk, an das sich unser Anwendungsdienst anschließt, definiert. Wir definieren die Netzwerke am Ende der Datei.

      Wir haben unsere mysql-Dienstdefiniton definiert. Nun fügen wir die Definition des drupal-Anwendungsdienstes am Ende der Datei hinzu:

      ~/drupal/docker-compose.yml

      ...
        drupal:
          image: drupal:8.7.8-fpm-alpine
          container_name: drupal
          depends_on:
            - mysql
          restart: unless-stopped
          networks:
            - internal
            - external
          volumes:
            - drupal-data:/var/www/html
      

      In dieser Dienstdefinition benennen wir unseren Container und definieren eine Neustartregel, wie wir es beim mysql-Dienst getan haben. Außerdem fügen wir einige Optionen hinzu, die für diesen Container spezifisch sind:

      • image: Hier verwenden wir Drupal-Image 8.7.8-fpm-alpine. Dieses Image verfügt über den php-fpm-Prozessor, den unser Nginx-Webserver zur Verwaltung der PHP-Verarbeitung benötigt. Darüber hinaus verwenden wir das aus dem Alpine-Linux-Projekt erlangte alpine-Image, das die Größe des Gesamtimages reduziert und in den Best Practices für Dockerfiles empfohlen wird. Drupal verfügt über weitere Versionen von Images, die Sie auf Dockerhub finden können.

      • depends_on: Diese Option wird verwendet, um Abhängigkeit zwischen Diensten auszudrücken. Das Definieren des mysql-Dienstes als Abhängigkeit unseres drupal-Containers stellt sicher, dass unser drupal-Container nach dem mysql-Container erstellt wird und ermöglicht einen reibungslosen Start unserer Anwendung.

      • networks: Hier haben wir diesen Container zusammen mit dem internal-Netzwerk dem external-Netzwerk hinzugefügt. Dadurch wird sichergestellt, dass unser mysql-Dienst nur über das internal-Netzwerk aus dem drupal-Container zugänglich ist, während dieser Container über das external-Netzwerk für andere Container weiterhin zugänglich bleibt.

      • volumes: Wir stellen ein benanntes Volume namens drupal-data im Bereitstellungspunkt /var/www/html bereit, der vom Drupal-Image erstellt wurde. Wenn wir ein benanntes Volume auf diese Weise verwenden, können wir unseren Anwendungscode mit anderen Containern teilen.

      Als Nächstes fügen wir die Nginx-Dienstdefinition nach der drupal-Dienstdefinition hinzu:

      ~/drupal/docker-compose.yml

      ...
        webserver:
          image: nginx:1.17.4-alpine
          container_name: webserver
          depends_on:
            - drupal
          restart: unless-stopped
          ports:
            - 80:80
          volumes:
            - drupal-data:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - external
      

      Auch hier benennen wir unseren Container und machen ihn in der Reihenfolge des Starts vom Drupal-Container abhängig. Außerdem verwenden wir ein alpine-Image – das Nginx-Image 1.17.4-alpine.

      Diese Dienstdefinition enthält auch die folgenden Optionen:

      • ports: Hiermit wird Port 80 zur Verfügung gestellt, um die Konfigurationsoptionen zu aktivieren, die wir in unserer Datei nginx.conf in Schritt 1 definiert haben.

      • volumes: Hier definieren wir sowohl das benannte Volume als auch den Host-Pfad:

        • drupal-data:/var/www/html: Hiermit wird unser Drupal-Anwendungscode im Verzeichnis /var/www/html, das wir als die root in unserem Nginx-Serverblock festgelegt haben, bereitgestellt.
        • ./nginx-conf:/etc/nginx/conf.d: Hiermit wird das Nginx-Konfigurationsverzeichnis auf dem Host in dem entsprechenden Verzeichnis im Container bereitgestellt. Dadurch wird sichergestellt, dass alle Änderungen, die wir an Dateien auf dem Host vornehmen, im Container reflektiert werden.
        • certbot-etc:/etc/letsencrypt: Hiermit werden die relevanten Let’s-Encrypt-Zertifikate und die Schlüssel für unsere Domäne in dem entsprechenden Verzeichnis des Containers bereitgestellt.
        • networks: Wir haben das external-Netzwerk nur definiert, damit dieser Container mit dem drupal-Container, aber nicht mit dem mysql-Container kommunizieren kann.

      Schließlich fügen wir unsere letzte Dienstdefinition für den certbot-Dienst hinzu. Achten Sie darauf, sammy@your_domain und your_domain durch Ihre eigene E-Mail-Adresse und den Domänennamen zu ersetzen:

      ~/drupal/docker-compose.yml

      ...
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - drupal-data:/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 zu pullen. Außerdem werden benannte Volumes verwendet, um Ressourcen für den Nginx-Container freizugeben, einschließlich der Domänenzertifikate und des Schlüssels in certbot-etc und des Anwendungscodes in drupal-data.

      Wir haben auch depends_on verwendet, um sicherzustellen, dass der certbot-Container gestartet wird, nachdem der webserver-Dienst ausgeführt wird.

      Wir haben hier keine networks angegeben, da dieser Container mit keinem Dienst über das Netzwerk kommunizieren wird. Es werden nur die Domänenzertifikate und der Schlüssel hinzugefügt, die wir mit den benannten Volumes bereitgestellt haben.

      Außerdem haben wir die Option command eingeschlossen, die einen Unterbefehl angibt, der mit dem Standardbefehl certbot des Containers ausgeführt werden soll. Der Certbot-Client unterstützt Plugins zur Erstellung und Installation von Zertifikaten. Wir verwenden das webroot-Plugin, um ein Zertifikat zu erlangen, indem wir certonly und --webroot in die Befehlszeile einfügen. Lesen Sie mehr über das Plugin und zusätzliche Befehle in der offiziellen Certbot-Dokumentation.

      Fügen Sie nach der certbot-Dienstdefinition die Netzwerk- und Volume-Definitionen hinzu:

      ~/drupal/docker-compose.yml

      ...
      networks:
        external:
          driver: bridge
        internal:
          driver: bridge
      
      volumes:
        drupal-data:
        db-data:
        certbot-etc:
      

      Mit dem networks-Schlüssel der obersten Ebene können wir die zu erstellenden Netzwerke angeben. networks ermöglicht die Kommunikation über die Dienste/Container auf allen Ports, da sie sich auf demselben Docker-Daemon-Host befinden. Wir haben zwei Netzwerke, internal und external, definiert, um die Kommunikation der Dienste webserver, drupal und mysql zu sichern.

      Der volumes-Schlüssel wird verwendet, um die benannten Volumes drupal-data, db-data und certbot-etc zu definieren. Wenn Docker Volumes erstellt, werden die Inhalte des Volumes in einem Verzeichnis des Host-Dateisystems, /var/lib/docker/volumes/, gespeichert, das von Docker verwaltet wird. Die Inhalte jedes Volumes werden dann von diesem Verzeichnis in jedem Container bereitgestellt, der das Volume verwendet. Auf diese Weise können Code und Daten zwischen Containern geteilt werden.

      Die fertige docker-compose.yml-Datei sieht so aus:

      ~/drupal/docker-compose.yml

      version: "3"
      
      services:
        mysql:
          image: mysql:8.0
          container_name: mysql
          command: --default-authentication-plugin=mysql_native_password
          restart: unless-stopped
          env_file: .env
          volumes:
            - db-data:/var/lib/mysql
          networks:
            - internal
      
        drupal:
          image: drupal:8.7.8-fpm-alpine
          container_name: drupal
          depends_on:
            - mysql
          restart: unless-stopped
          networks:
            - internal
            - external
          volumes:
            - drupal-data:/var/www/html
      
        webserver:
          image: nginx:1.17.4-alpine
          container_name: webserver
          depends_on:
            - drupal
          restart: unless-stopped
          ports:
            - 80:80
          volumes:
            - drupal-data:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - external
      
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - drupal-data:/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
      
      networks:
        external:
          driver: bridge
        internal:
          driver: bridge
      
      volumes:
        drupal-data:
        db-data:
        certbot-etc:
      

      Nun sind unsere Dienstdefinitionen fertig. Als Nächstes starten wir den Container und testen unsere Zertifikatsanforderungen.

      Schritt 4 — Erlangen der SSL-Zertifikate und Zugangsdaten

      Wir können unsere Container mit dem Befehl docker-compose up starten, der die Container in der von uns angegebenen Reihenfolge erstellt und ausführt. Wenn unsere Domain-Anfragen erfolgreich sind, sehen wir den richtigen Exit-Status in unserer Ausgabe und die richtigen Zertifikate, die im Ordner /etc/letsencrypt/live im Webservercontainer bereitgestellt werden.

      Um die Container im Hintergrund auszuführen, verwenden Sie den Befehl docker-compose up mit dem Flag -d:

      Sie sehen eine ähnliche Ausgabe, die bestätigt, dass Ihre Dienste erstellt wurden:

      Output

      ... Creating mysql ... done Creating drupal ... done Creating webserver ... done Creating certbot ... done

      Überprüfen Sie den Status der Dienste mit dem Befehl docker-compose ps:

      Wir sehen die Dienste mysql, drupal und webserver mit einem State von Up, während certbot mit einer Statusmeldung von 0 beendet wird:

      Output

      Name Command State Ports -------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 drupal docker-php-entrypoint php-fpm Up 9000/tcp mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp

      Wenn Sie in der Spalte State für die Dienste mysql, drupal oder webserver etwas anderes als Up sehen, oder für den certbot-Container einen anderen Exit-Status als 0, überprüfen Sie die Dienstprotokolle mit dem Befehl docker-compose logs:

      • docker-compose logs service_name

      Wir können nun mit dem Befehl docker-compose exec überprüfen, dass unsere Zertifikate auf dem webserver bereitgestellt wurden:

      • docker-compose exec webserver ls -la /etc/letsencrypt/live

      Dadurch erhalten Sie folgende Ausgabe:

      Output

      total 16 drwx------ 3 root root 4096 Oct 5 09:15 . drwxr-xr-x 9 root root 4096 Oct 5 09:15 .. -rw-r--r-- 1 root root 740 Oct 5 09:15 README drwxr-xr-x 2 root root 4096 Oct 5 09:15 your_domain

      Nachdem nun alles erfolgreich ausgeführt wird, können wir unsere certbot-Dienstdefinition bearbeiten, um das Flag --staging zu entfernen.

      Öffnen Sie die Datei docker-compose.yml, gehen Sie zur certbot-Dienstdefinition und ersetzen Sie das Flag --staging in der Befehlsoption mit dem Flag --force-renewal, das Certbot mitteilt, dass Sie ein neues Zertifikat mit denselben Domänen wie ein vorhandenes Zertifikat anfordern möchten. Die aktualisierte Definition von certbot sieht wie folgt aus:

      ~/drupal/docker-compose.yml

      ...
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - drupal-data:/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
      ...
      

      Wir müssen docker-compose erneut ausführen, um den certbot-Container neu zu erstellen. Wir schließen auch die Option --no-deps ein, um Compose mitzuteilen, dass das Starten des webserver-Dienstes übersprungen werden kann, da dieser bereits ausgeführt wird:

      • docker-compose up --force-recreate --no-deps certbot

      In der Ausgabe sehen wir, dass unsere 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 2020-01-03. 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

      Nachdem wir unsere Zertifikate erfolgreich generiert haben, können wir unsere Nginx-Konfiguration aktualisieren, um SSL einzuschließen.

      Schritt 5 — Ändern der Webserver-Konfiguration und Dienstdefinition

      Nach der Installation von SSL-Zertifikaten in Nginx müssen wir alle HTTP-Anfragen an HTTPS umleiten. Außerdem müssen wir unser SSL-Zertifikat und unsere Schlüsselpositionen angeben und Sicherheitsparameter sowie Header hinzufügen.

      Da Sie den webserver-Dienst neu erstellen, um diese Ergänzungen einzuschließen, können Sie diesen jetzt stoppen:

      • docker-compose stop webserver

      Dadurch erhalten Sie folgende Ausgabe:

      Output

      Stopping webserver ... done

      Als Nächstes entfernen wir die zuvor erstellte Nginx-Konfigurationsdatei:

      Öffnen Sie eine andere Version der Datei:

      • nano nginx-conf/nginx.conf

      Fügen Sie der Datei den folgenden Code hinzu, um HTTP an HTTPS umzuleiten und SSL-Zugangsdaten, Protokolle und Sicherheitsheader hinzuzufügen. Denken Sie daran, your_domain durch Ihre eigene Domäne zu ersetzen:

      ~/drupal/nginx-conf/nginx.conf

      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;
          listen [::]:443 ssl;
          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;
      
          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;
      
          location / {
              try_files $uri $uri/ /index.php$is_args$args;
          }
      
          rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
      
          location ~ .php$ {
              try_files $uri =404;
              fastcgi_split_path_info ^(.+.php)(/.+)$;
              fastcgi_pass drupal: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-Serverblock gibt das Webroot-Plugin für Certbot-Erneuerungsanfragen an das Verzeichnis .well-known/acme-challenge an. Er enthält auch eine rewrite-Anweisung, die HTTP-Anfragen an das root-Verzeichnis an HTTPS leitet.

      Der HTTPS-Serverblock aktiviert ssl und http2. Weitere Informationen dazu, wie HTTP/2 über HTTP-Protokolle iteriert und welche Vorteile es für die Website-Leistung haben kann, lesen Sie bitte in der Einführung Einrichten von Nginx mit HTTP/2-Support unter Ubuntu 18.04.

      Diese Blocks aktivieren SSL, da wir unser SSL-Zertifikat und die Schlüsselpositionen zusammen mit den empfohlenen Headern eingefügt haben. Diese Header ermöglichen uns eine A-Bewertung auf den Server-Testseiten SSL-Labs und Security Headers.

      Unsere Anweisungen root und index befinden sich ebenfalls in diesem Block, ebenso wie die restlichen Drupal-spezifischen Location-Blocks, die in Schritt 1 behandelt wurden.

      Speichern und schließen Sie die aktualisierte Nginx-Konfigurationsdatei.

      Bevor wir den webserver-Container neu erstellen, müssen wir unserem webserver-Dienst ein 443-Port-Mapping hinzufügen, da wir SSL-Zertifikate aktiviert haben.

      Öffnen Sie die Datei docker-compose.yml:

      Führen Sie die folgenden Änderungen in der webserver-Dienstdefinition aus:

      ~/drupal/docker-compose.yml

      ...
        webserver:
          image: nginx:1.17.4-alpine
          container_name: webserver
          depends_on:
            - drupal
          restart: unless-stopped
          ports:
            - 80:80
            - 443:443
          volumes:
            - drupal-data:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - external
      ...
      

      Nach dem Aktivieren der SSL-Zertifikate sieht unsere docker-compose.yml wie folgt aus:

      ~/drupal/docker-compose.yml

      version: "3"
      
      services:
        mysql:
          image: mysql:8.0
          container_name: mysql
          command: --default-authentication-plugin=mysql_native_password
          restart: unless-stopped
          env_file: .env
          volumes:
            - db-data:/var/lib/mysql
          networks:
            - internal
      
        drupal:
          image: drupal:8.7.8-fpm-alpine
          container_name: drupal
          depends_on:
            - mysql
          restart: unless-stopped
          networks:
            - internal
            - external
          volumes:
            - drupal-data:/var/www/html
      
        webserver:
          image: nginx:1.17.4-alpine
          container_name: webserver
          depends_on:
            - drupal
          restart: unless-stopped
          ports:
            - 80:80
            - 443:443
          volumes:
            - drupal-data:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - external
      
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - drupal-data:/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
      
      networks:
        external:
          driver: bridge
        internal:
          driver: bridge
      
      volumes:
        drupal-data:
        db-data:
        certbot-etc:
      

      Speichern und schließen Sie die Datei. Wir erstellen den webserver-Dienst mit unserer aktualisierten Konfiguration nun neu:

      • docker-compose up -d --force-recreate --no-deps webserver

      Dadurch erhalten Sie folgende Ausgabe:

      Output

      Recreating webserver ... done

      Überprüfen Sie die Dienste mit docker-compose ps:

      Wir sehen die Dienste mysql, drupal und webserver als Up, während certbot mit der Statusmeldung 0 beendet wird:

      Output

      Name Command State Ports -------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 drupal docker-php-entrypoint php-fpm Up 9000/tcp mysql 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

      Jetzt werden alle unsere Dienste ausgeführt und wir können mit der Installation von Drupal über die Web-Oberfläche fortfahren.

      Schritt 6 – Abschließen der Installation über die Weboberfläche

      Beenden wir die Installation über die Weboberfläche von Drupal.

      Navigieren Sie in einem Webbrowser zur Domäne des Servers. Denken Sie daran, your_domain hier mit Ihrem eigenen Domänennamen zu ersetzen:

      https://your_domain
      

      Wählen Sie die Sprache aus, die Sie verwenden möchten:

      Sprachauswahlseite auf der Drupal-Weboberfläche

      Klicken Sie auf Speichern und fortfahren. Wir werden zur Seite der Installationsprofile geleitet. Drupal bietet verschiedene Profile. Wählen Sie das Profil Standard und klicken Sie auf Speichern und fortfahren.

      Profilauswahlseite auf der Drupal-Weboberfläche

      Nach Auswahl des Profils gehen wir weiter zur Seite der Datenbankkonfiguration. Wählen Sie als Datenbanktyp MySQL, MariaDB, Percona Server oder äquivalent aus. Geben Sie die Werte für Datenbankname, Benutzername und Passwort entsprechend der Werte von MYSQL_DATABASE, MYSQL_USER und MYSQL_PASSWORD ein, die jeweils in der .env-Datei in Schritt 2 definiert wurden. Klicken Sie auf Erweiterte Optionen und setzen Sie den Wert für Host auf den Namen des mysql-Dienstcontainers. Klicken Sie auf Speichern und fortfahren.

      Datenbankeinrichtungsseite auf der Drupal-Weboberfläche

      Nach Konfiguration der Datenbank beginnt die Installation der Standardmodule und Themen von Drupal:

      Installationsseite der Website auf der Drupal-Weboberfläche

      Nachdem die Website installiert ist, werden wir auf die Einrichtungsseite der Drupal-Website geleitet, um den Namen der Website, die E-Mail-Adresse, den Benutzernamen, das Passwort und die Ländereinstellungen zu konfigurieren. Geben Sie die Informationen an und klicken Sie auf Speichern und fortfahren:

      Konfigurationsseite der Website auf der Drupal-Weboberfläche

      Nachdem wir auf Speichern und fortfahren geklickt haben, sehen wir die Seite Willkommen bei Drupal. Diese zeigt uns, dass unsere Drupal-Website eingerichtet ist und erfolgreich ausgeführt wird.

      Seite Willkommen bei Drupal auf der Drupal-Weboberfläche

      Nachdem die Installation von Drupal nun abgeschlossen ist, müssen wir sicherstellen, dass unsere SSL-Zertifikate automatisch erneuert werden.

      Schritt 7 — Erneuern der Zertifikate

      Let’s-Encrypt-Zertifikate sind 90 Tage gültig. Daher müssen wir einen automatisierten Erneuerungsprozess einrichten, um sicherzustellen, dass sie nicht ablaufen. Eine Möglichkeit hierzu ist das Erstellen eines Jobs mit dem Planungsprogramm cron. In diesem Fall erstellen wir einen cron-Job, der in regelmäßigen Abständen ein Skript ausführt, das unsere Zertifikate erneuert und die Nginx-Konfiguration neu lädt.

      Wir erstellen die Datei ssl_renew.sh, um unsere Zertifikate zu erneuern:

      Fügen Sie folgenden Code hinzu. Denken Sie daran, den Verzeichnisnamen durch Ihren eigenen non-root user zu ersetzen:

      ~/drupal/ssl_renew.sh

      
      #!/bin/bash
      
      cd /home/sammy/drupal/
      /usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run && 
      /usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver
      

      Das Skript wechselt zum ~/drupal-Projektverzeichnis und führt die folgenden docker-compose-Befehle aus.

      • docker-compose run: Hiermit wird ein certbot-Container gestartet und der in unserer certbot-Dienstdefinition verfügbare command überschrieben. Anstatt des Unterbefehls certonly verwenden wir hier den Unterbefehl renew, mit dem Zertifikate, die kurz vor Ablauf stehen, erneuert werden. Wir haben hier die Option --dry-run zum Testen unseres Skripts hinzugefügt.

      • docker-compose kill: Hiermit wird ein SIGHUP-Signal an den webserver-Container gesendet, um die Nginx-Konfiguration neu zu laden.

      Schließen Sie die Datei und machen Sie sie mit folgendem Befehl ausführbar:

      • sudo chmod +x ssl_renew.sh

      Öffnen Sie als Nächstes die Datei root crontab, um das Erneuerungsskript in einem angegebenen Intervall auszuführen:

      Wenn Sie die Datei zum ersten Mal bearbeiten, werden Sie dazu aufgefordert, einen Texteditor zum Öffnen der Datei zu wählen:

      Output

      no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...

      Fügen Sie am Ende der Datei die folgende Zeile hinzu und ersetzen Sie sammy mit Ihrem Benutzernamen:

      crontab

      ...
      */5 * * * * /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1
      

      Hiermit wird das Job-Intervall auf alle fünf Minuten festgelegt, sodass wir testen können, ob unsere Erneuerungsanfrage wie beabsichtigt funktioniert hat oder nicht. Außerdem haben wir eine Protokolldatei, cron.log, zum Aufzeichnen der relevanten Ausgabe erstellt.

      Verwenden Sie nach fünf Minuten den Befehl tail, um cron.log zu prüfen und zu sehen, ob die Erneuerungsanfrage erfolgreich war oder nicht:

      • tail -f /var/log/cron.log

      Sie sehen eine Ausgabe, die eine erfolgreiche Erneuerung bestätigt:

      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.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

      Drücken Sie STRG+C, um den tail-Prozess zu beenden.

      Wir können jetzt die Datei crontab ändern, um das Skript jeden zweiten Tag der Woche um 02:00 Uhr auszuführen. Ändern Sie die letzte Zeile der crontab wie folgt:

      crontab

      ...
      * 2 * * 2 /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1
      

      Speichern und schließen Sie die Datei.

      Nun entfernen wir die Option --dry-run aus dem Skript ssl_renew.sh. Öffnen Sie es zunächst:

      Ändern Sie dann den Inhalt wie folgt:

      ~/drupal/ssl_renew.sh

      #!/bin/bash
      
      cd /home/sammy/drupal/
      /usr/local/bin/docker-compose -f docker-compose.yml run certbot renew && 
      /usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver
      

      Unser cron-Job kümmert sich nun um den Ablauf unserer SSL-Zertifikate, indem er sie erneuert, wenn sie hierfür infrage kommen.

      Zusammenfassung

      In diesem Tutorial haben wir Docker Compose verwendet, um eine Drupal-Installation mit einem Nginx-Webserver zu erstellen. Als Teil des Workflows haben wir TLS/SSL-Zertifikate für die Domäne erlangt, mit der wir unsere Drupal-Website verknüpfen wollten, und einen cron-Job erstellt, um diese Zertifikate bei Bedarf zu erneuern.

      Wenn Sie mehr über Docker erfahren möchten, besuchen Sie unsere Docker-Themenseite.



      Source link