Native Commento-Server mit Docker Compose

Hinweis: Dies ist eine Übersetzung meines Beitrags (Englisch), die die Implementierung des Kommentarservers beschreibt, der auf derselben Site verwendet wird, auf der sich das Original befindet.


TL; DR-Version: Ich habe die Commento-Serverkonfiguration entwickelt, die einfach und einfach im halbautomatischen Modus bereitgestellt werden kann. Kopieren Sie dieses Repository von GitHub in sich selbst und folgen Sie den Anweisungen in README .

Vor einiger Zeit wollte ich Disqus - das vielleicht häufigste System zum Hinzufügen von Kommentaren zu Seiten - unwiderstehlich in ein freies und offenes Commento ändern.


Warum Commento?


Das Problem bei Disqus ist, wie bei vielen anderen "kostenlosen" Produkten, dass das Produkt in diesem Fall der Benutzer ist - das heißt Sie. Darüber hinaus „bereichert“ Disqus jede Seite, auf der es verwendet wird, mit Megabyte an Skripten und mehr als hundert zusätzlichen HTTP-Anforderungen.


Außerdem werden in der kostenlosen Version Anzeigen geschaltet, mit denen Sie "nur" 9 US-Dollar pro Monat auszahlen können (Plus-Plan). Dies allein reicht aus, um etwas Besseres finden zu wollen.


Irgendwann bin ich auf diesen Beitrag gestoßen und habe herausgefunden, dass es einen kostenlosen Kommentarserver namens Commento gibt . Durch einen glücklichen Zufall wurde Commento erst kürzlich vollständig geöffnet - bevor es in zwei Versionen erhältlich war: Free Community und Commercial Enterprise . Dank seines Entwicklers Adhityaa Chandrasekar.


Commento ist um Größenordnungen effizienter als Disqus, die typische Größe der zusätzlichen Last beträgt etwa 11 KB , plus die Kommentare selbst natürlich. Ungefähr die gleiche Situation mit den erforderlichen HTTP-Anforderungen.


Ein weiteres Plus des Commento-Servers ist, dass er sehr schnell ist, da er in Go geschrieben ist.


Nun, als Kirsche auf dem Kuchen hat er eine Menge Kommentare von Disqus, wovon könnte er sonst noch träumen?


Anwendungsfälle für Commento


Für nicht fortgeschrittene (technisch) Benutzer bietet Commento einen einsatzbereiten Cloud-Dienst auf commento.io . Der Autor bietet Ihnen an, die monatliche Gebühr selbst zu wählen, sie darf jedoch "aus technischen Gründen" nicht unter 3 US-Dollar liegen.


Herr Chandrasekar bietet auch großzügig ein kostenloses Konto auf Commento.io an, um „nicht triviale Patches“ für das Produkt zu erhalten.


Nun, ich habe die dritte Option gewählt: den Commento-Server selbst zu erhöhen. In diesem Fall sind Sie von niemandem abhängig (außer natürlich vom Hoster), und ich liebe die Unabhängigkeit.


Schwierigkeiten


Ich bin ein großer Fan von Docker-Containern und verwende häufig Docker Compose , ein Tool zum Verwalten von Gruppen mehrerer verwandter Container. Commento verfügt über ein gebrauchsfertiges Docker-Image in der GitLab-Containerregistrierung.


Daher reifte die Entscheidung, Container zu verwenden, von selbst - aber zunächst mussten einige Dinge entschieden werden.


Schwierigkeit Nr. 1: PostgreSQL


Für Commento ist eine relativ neue Version des PostgreSQL-Servers erforderlich. Leider werden keine anderen SQL-Server unterstützt.


Nun, wir lassen immer noch alles in Containern laufen, also ist es ziemlich einfach.


Schwierigkeit Nr. 2: Keine HTTPS-Unterstützung


Commento selbst ist ein Webserver, unterstützt jedoch nur das unsichere HTTP-Protokoll.


Es ist zu beachten, dass diese Vorgehensweise heutzutage weit verbreitet ist: In diesem Fall ist der Server hinter dem Reverse-Proxy versteckt, der auch das SSL-Offloading durchführt. Die Sache ist, dass SSL / HTTPS-Unterstützung in diesem Fall schließlich in der Werft 2019 absolut notwendig ist und es sehr schwierig sein wird, Versuche zu versuchen, einen Benutzer unter Verwendung eines ungesicherten Internetprotokolls zu autorisieren.


Ich habe mich für den Nginx- Server entschieden. Erstens hatte ich beträchtliche Erfahrung damit, und zweitens ist er sehr schnell, wirtschaftlich und stabil. Und veröffentlicht die offiziellen Builds von Docker-Images .


Die zweite Zutat im HTTPS-Rezept ist das SSL-Zertifikat für die Domain. Ich bin EFF und Mozilla auf ewig dankbar, dass sie die Let's Encrypt Certificate Authority erstellt haben , die jeden Monat Millionen kostenloser Zertifikate ausstellt.


Let's Encrypt bietet auch ein kostenloses Befehlszeilenprogramm namens certbot , das das Abrufen und Aktualisieren eines Zertifikats erheblich vereinfacht. Nun, und natürlich ein Docker-Image für ihn!


Schwierigkeit Nr. 3: Certbot-Hühnerei-Problem


Aber dieser Trick ist schwieriger.


Wir möchten in der Konfiguration unseres Reverse-Proxys auf Nginx auf das SSL-Zertifikat verweisen, was bedeutet, dass es ohne Zertifikat einfach nicht gestartet werden kann. Um ein SSL-Zertifikat für eine Domain zu erhalten, benötigen Sie gleichzeitig einen funktionierenden HTTP-Server, mit dem Let's Encrypt Ihren Besitz dieser Domain nachweist.


Ich habe es geschafft, dieses Problem zu lösen, und es scheint mir ziemlich elegant:


  1. Zunächst wird ein ungültiges Dummy-Zertifikat generiert, dessen einziger Zweck darin besteht, Nginx starten zu lassen.
  2. Nginx und certbot erhalten gemeinsam ein neues, jetzt gültiges Zertifikat.
  3. Sobald das Zertifikat empfangen wurde, wechselt certbot in den „Standby-Modus“ und wacht alle 12 Stunden auf, um zu überprüfen, ob es aktualisiert werden muss - gemäß den Empfehlungen von Let's Encrypt.
  4. Wenn der Moment gekommen ist und das Zertifikat erneuert wurde, signalisiert certbot Nginx, neu zu starten.

Schwierigkeit Nr. 4: Etwas muss erhalten bleiben


Ich vermute sehr, dass Sie möchten, dass Benutzerkommentare nach einem Neustart oder einem Systemupdate gespeichert werden.


Damit Let's Encrypt Sie nicht aufgrund zu häufiger Anfragen sperrt, sollten Sie die erhaltenen Zertifikate für das gesamte Ablaufdatum aufbewahren.


Beide Punkte wurden in der vorgeschlagenen Konfiguration unter Verwendung der Volumes des Dockers gelöst, die von systemd beim ersten Start von Commento automatisch erstellt wurden. Volumes werden als "extern" markiert, sodass Docker sie überspringt, wenn Container mit docker-compose down -v .


Bring alles zusammen


Jetzt können Sie sehen, wie alles zusammenarbeitet.


Die folgende Abbildung zeigt die Interaktion und den Verkehr zwischen den vier Containern:



Ich habe die depends_on Option Docker Compose depends_on um sicherzustellen, dass die Container in der richtigen Reihenfolge beginnen.


Wenn Sie nur Ihren eigenen Commento-Server starten möchten, können Sie den Rest des Artikels überspringen und direkt zum Code auf GitHub wechseln .


Nun, ich werde später ausführlicher auf diese Implementierung eingehen.


Wie funktioniert das alles?


Datei erstellen


Wie Sie im Bild oben sehen können, besteht meine „Komposition“ aus vier Diensten:


  1. certbot - Dienstprogramm certbot von EFF
  2. nginx - Reverse Proxy, der SSL-Offloading implementiert
  3. app - Commento Server
  4. postgres - PostgreSQL-Datenbank

Die docker-compose.yml enthält Deklarationen des eigenen Docker-Netzwerks mit dem Namen commento_network und drei Volumes, von denen zwei extern sind ( docker-compose.yml außerhalb von Compose erstellt werden müssen):


  • commento_postgres_volume speichert PostgreSQL-Serverdaten für Commento: Benutzer, Moderatoren, Kommentare usw.
  • certbot_etc_volume enthält Zertifikate, die von certbot empfangen wurden.

Nginx


Der Nginx-Container basiert auf einem einfachen offiziellen Image, das auf Alpine basiert, und verwendet das folgende Skript zum Ausführen:


 #!/bin/sh trap exit TERM # Wait for the certificate file to arrive wait_for_certs() { echo 'Waiting for config files from certbot...' i=0 while [[ ! -f /etc/letsencrypt/options-ssl-nginx.conf ]]; do sleep 0.5 [[ $((i++)) -gt 20 ]] && echo 'No files after 10 seconds, aborting' && exit 2 done } # Watches for a "reload flag" (planted by certbot container) file and reloads nginx config once it's there watch_restart_flag() { while :; do [[ -f /var/www/certbot/.nginx-reload ]] && rm -f /var/www/certbot/.nginx-reload && echo 'Reloading nginx' && nginx -s reload sleep 10 done } # Wait for certbot wait_for_certs # Start "reload flag" watcher watch_restart_flag & # Run nginx in the foreground echo 'Starting nginx' exec nginx -g 'daemon off;' 

  • Zeile 3 ( ARRGHHH, Habr unterstützt die Anzeige von Zeilennummern im Code nicht - ca. Transl. ) Ein Interrupt-Handler wird registriert, damit Nginx und der Hintergrundüberwachungsprozess die Arbeit erfolgreich abschließen, wenn der Container stoppt.
  • Zeile 27 ruft die certbot auf, die den Nginx-Startvorgang certbot , bis die vom certbot Container erstellten SSL-Konfigurationsdateien certbot . Ohne dies würde Nginx den Start verweigern.
  • Zeile 30 erstellt einen Hintergrundprozess, der regelmäßig alle zehn Sekunden das Vorhandensein einer Flag-Datei mit dem Namen .nginx-reload überprüft und Nginx anweist, die Konfiguration neu zu .nginx-reload , sobald sie .nginx-reload . Diese Datei erstellt auch certbot, wenn das Zertifikat aktualisiert wird.
  • Zeile 34 startet Nginx im normalen Modus. In diesem Fall bedeutet exec , dass der aktuelle Shell-Prozess durch den Nginx-Prozess ersetzt wird.

Eine weitere wichtige Datei in diesem Bild ist die Konfiguration des virtuellen Commento-Servers, die Nginx dazu zwingt, HTTPS-Anforderungen an den commento weiterzuleiten:


 server { listen [::]:443 ssl ipv6only=on; listen 443 ssl; server_tokens off; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name __DOMAIN__; location / { proxy_pass http://app:8080/; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } ssl_certificate /etc/letsencrypt/live/__DOMAIN__/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/__DOMAIN__/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } server { listen 80 default_server; listen [::]:80 default_server; server_tokens off; server_name __DOMAIN__; location /.well-known/acme-challenge/ { root /var/www/certbot; } # Redirect to HTTPS on port 80 location / { return 301 https://$host$request_uri; } } 

Der erste Serverblock (Zeilen 1-21 ) beschreibt die Arbeit mit HTTPS und der Weiterleitungsregel. Hier werden Let's Encrypt-Zertifikatdateien erwähnt (oder stattdessen verwendete Stubs).


Die vom Server bereitgestellte Domäne wird beim Erstellen des Images als Argument übergeben. Es ersetzt die Zeile __DOMAIN__ in der Serverkonfiguration.


Der zweite Block (Zeilen 23-38 ) ist die Konfiguration des HTTP-Servers, der vom Certbot zur Bestätigung des Domänenbesitzes verwendet wird (die sogenannte „ACME-Herausforderung“). Alle anderen Anfragen bewirken eine Umleitung über HTTPS an die entsprechende Adresse.


certbot


Unser Certbot-Image basiert auf dem offiziellen Build mit dem folgenden Skript:


 #!/bin/sh trap exit TERM # Wait until nginx is up and running, up to 10 seconds wait_for_nginx() { echo 'Waiting for nginx...' i=0 while ! nc -z nginx 80 &>/dev/null; do sleep 0.5 [[ $((i++)) -gt 20 ]] && echo "nginx isn't online after 10 seconds, aborting" && exit 4 done echo 'nginx is up and running' } # Check vars [[ -z "$DOMAIN" ]] && echo "Environment variable 'DOMAIN' isn't defined" && exit 2 [[ -z "$EMAIL" ]] && echo "Environment variable 'EMAIL' isn't defined" && exit 2 TEST="${TEST:-false}" # Check external mounts data_dir='/etc/letsencrypt' www_dir='/var/www/certbot' [[ ! -d "$data_dir" ]] && echo "Directory $data_dir must be externally mounted" [[ ! -d "$www_dir" ]] && echo "Directory $www_dir must be externally mounted" # If the config/certificates haven't been initialised yet if [[ ! -e "$data_dir/options-ssl-nginx.conf" ]]; then # Copy config over from the initial location echo 'Initialising nginx config' cp /conf/options-ssl-nginx.conf /conf/ssl-dhparams.pem "$data_dir/" # Copy dummy certificates mkdir -p "$data_dir/live/$DOMAIN" cp /conf/privkey.pem /conf/fullchain.pem "$data_dir/live/$DOMAIN/" # Wait for nginx wait_for_nginx # Remove dummy certificates rm -rf "$data_dir/live/$DOMAIN/" # Run certbot to validate/renew certificate test_arg= $TEST && test_arg='--test-cert' certbot certonly --webroot -w /var/www/certbot -n -d "$DOMAIN" $test_arg -m "$EMAIL" --rsa-key-size 4096 --agree-tos --force-renewal # Reload nginx config touch /var/www/certbot/.nginx-reload # nginx config has been already initialised - just give nginx time to come up else wait_for_nginx fi # Run certbot in a loop for renewals while :; do certbot renew # Reload nginx config touch /var/www/certbot/.nginx-reload sleep 12h done 

Ein kurzer Überblick über seine Linien:


  • Zeile 3 ist wie im vorherigen Skript für die regelmäßige Fertigstellung des Containers erforderlich.
  • Die Zeilen 17-19 überprüfen die erforderlichen Variablen.
  • Und in den Zeilen 22-25 - dass die Verzeichnisse, die für das Funktionieren von certbot erforderlich sind, korrekt bereitgestellt werden.
  • Die Gabel folgt:
    • Die Zeilen 30-50 werden nur beim ersten Start des Containers ausgeführt:
      • Ein Dummy-Zertifikat wird kopiert, sodass Nginx normal gestartet werden kann.
      • Nginx wartet unterdessen auf das Ende dieses Prozesses, wonach der Download fortgesetzt wird.
      • Nach dem Start von Nginx leitet certbot den Prozess zum Abrufen eines gültigen Zertifikats von Let's Encrypt ein.
      • Und schließlich wird, sobald das Zertifikat empfangen wurde, die .nginx-reload Datei erstellt, was Nginx darauf hinweist, dass es Zeit ist, die Konfiguration neu zu laden.
    • Zeile 54 wartet auf den Start von Nginx - falls bereits ein vollständiges Zertifikat verfügbar ist.
  • Nach all dem (Zeilen 58-63 ) fährt er alle 12 Stunden mit dem Zyklus fort, überprüft die Notwendigkeit, das Zertifikat zu erneuern, und signalisiert Nginx den Neustart.

Commento und PostgreSQL


Die postgres und postgres Container verwenden die von den Entwicklern bereitgestellten Originalbilder ohne Änderungen.


Systemd Service


Das letzte Teil dieses Puzzles ist die systemd commento.service Einheitendatei , für die Sie in /etc/systemd/system/commento.service einen Symlink /etc/systemd/system/commento.service damit sie zu einem guten Zeitpunkt beim Systemstart /etc/systemd/system/commento.service :


 [Unit] Description=Commento server [Service] TimeoutStopSec=30 WorkingDirectory=/opt/commento ExecStartPre=-/usr/bin/docker volume create commento_postgres_volume ExecStartPre=-/usr/bin/docker volume create certbot_etc_volume ExecStartPre=-/usr/local/bin/docker-compose -p commento down -v ExecStart=/usr/local/bin/docker-compose -p commento up --abort-on-container-exit ExecStop=/usr/local/bin/docker-compose -p commento down -v [Install] WantedBy=multi-user.target 

Zeilen:


  • Zeile 6 impliziert, dass der Projektcode in das Verzeichnis /opt/commento geklont wird - dies ist viel einfacher.
  • In den Zeilen 7 bis 8 werden externe Volumes erstellt, sofern dies noch nicht geschehen ist.
  • In Zeile 9 werden die möglichen Reste der vorherigen Container gelöscht. Externe Volumes bleiben erhalten.
  • Zeile 10 markiert den tatsächlichen Start von Docker Compose. Das --abort-on-container-exit gesamte Herde von Containern, wenn einer von ihnen --abort-on-container-exit . Dank dessen wird systemd zumindest bewusst sein, dass der Dienst gestoppt wird.
  • In Zeile 11 werden erneut Container, Netzwerke und Volumes bereinigt und gelöscht.

Quellcode


Eine voll funktionsfähige Implementierung, die nur die Konfiguration von Variablen in docker-compose.yml , ist auf GitHub verfügbar. Sie müssen nur die in README beschriebenen Schritte sorgfältig ausführen .


Der Code unterliegt der MIT-Lizenz .


Vielen Dank für das Lesen zu diesem Ort, Kommentare sind herzlich willkommen!

Source: https://habr.com/ru/post/de464105/


All Articles