Datenschutzfreundliches Kommentarsystem mit Commento und Docker selbst hosten

Kommentarsystem selbst hosten, aber ein Blog mit statischen Seiten betreiben? Das geht, mit Commento. Mit Docker-Containern auf dem eigenen Server hat man alles unter Kontrolle und Datenschutz ist kein Thema mehr.

Lesezeit: 8 Min., von Titus Gast gepostet am Tue, 14.4.2020
Tags: dsgvo, datenschutz, intern, docker

Es gibt viele gute Gründe, Kommentare selbst zu hosten – Datenschutz ist nur einer davon. Was mir hingegen an Disqus gefiel, war die Tatsache, dass es ganz prima mit meinem statischen Blog klar kam, einfach zu integrieren war und ich mich außer um Anonymisierung und Moderation um nichts kümmern musste. Und dann kam die Datenschutzgrundverordnung und mit ihr eine Menge Unsicherheit. Für mich bedeutete das: Eine Alternative musste her.

Isso oder Commento?

Am Anfang liebäugelte ich mit Isso und unternahm damit auch einige Experimente, bekam es aber nicht richtig zum Laufen. Die Dokumentation – insbesondere für die Docker-Variante – ist dann doch ein bisschen einsilbig; möglicherweise probiere ich es aber auf Basis des unten beschriebenen Setups nochmal. Mit einem Versuch, Isso bei Uberspace zum Laufen zu bringen, hatte ich ebenfalls weniger Glück als andere.

Da lief mir Commento über den Weg. Commento ist ebenfalls ein Kommentarsystem, das man selbst hosten kann. Es gibt die gehostete Variante, die es ab 5 Dollar aufwärts gibt. Das habe ich auch zunächst mal probiert; die Firma hinter Commento (letztendlich scheint es mir eine 1-Mann-Firma zu sein) muss kein Geld mit Werbung und Tracking verdienen und verkauft Datenschutz explizit als Geschäftsmodell. Letztendlich waren für mich die Kosten ein (kleines) Argument fürs Selber-Hosten, ein größeres die Unsicherheit, dass der Dienst ebenfalls in den USA sitzt und ich meine User trotz allen Datenschutzversprechen nicht einem Drittanbieter ausliefern wollte. Vor allem ändert so ein Drittanbieter ja auch mal sein Geschäftsmodell oder verschwindet ganz – alles schon erlebt.

Hinweis: Für die folgenden Anleitungen gehe ich davon aus, dass du weißt, was Docker und Docker-Compose sind, beides auf deinem System installiert hast und damit ein bisschen umgehen kannst.

Commento selbst hosten

Commento ist recht gut dokumentiert und es gibt vor allem eine umfangreiche Anleitung für Docker. Damit bekommt man das System recht schnell zum Laufen und zunächst war ich begeistert – doch dann fiel mir etwas Entscheidendes auf: Es fehlt da ein -s in der URL. Der Docker-Container kommt nur mit HTTP, es fehlt nativer Support für verschlüsselte Verbindungen via HTTPS, die bei echten Webservern mittlerweile zum Standard geworden und bei einem Kommentarsystem, in dem sich Leute potenziell einloggen, natürlich Pflicht sind.

Also war schnell klar: Nur mit der Anleitung alleine geht’s nicht, da muss noch ein Proxy davor.

Erste Proxy-Versuche mit Nginx

Genauer gesagt: Einen Reverse Proxy. Kann ja nicht so schwer sein, dachte ich mir, der ansonsten von mir eingesetzte Webserver Nginx kann so was ja ganz gut und den gibt’s auch als Docker-Container.

Mein erster Versuch bestand darin, Docker mit Commento auf einem bestehenden und mit fest installiertem Nginx ausgestatteten System zu installieren. Die Idee: Nginx kümmert sich um die Letsencrypt-Zertifikate und fungiert als Proxy für Commento, das in einem Docker-Container läuft. Das funktionierte überhaupt nicht; ganz sicher gibt es Tricks, das zu erreichen – aber mir fiel hier das auf die Füße, was der große Vorteil von Docker-Containern ist: Sie sind abgeschottet gegenüber dem restlichen System. Ein Webserver auf dem Gastsystem kann nicht so einfach mit Containern sprechen und diese auch nicht so ohne weiteres miteinander.

Das zeigte sich dann in lustigen Fehlermeldungen wie

connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: ...

oder

nginx_proxy | nginx: [emerg] host not found in upstream "server:8080" in /etc/nginx/nginx.conf:21

Nicht schön, und verschiedene Versuche, die interne Docker-IP direkt anzusteuern, schlugen auch fehl.

Traefik als Reverse-Proxy für Commento

Bei der Suche nach Lösungen für dieses Problem stieß ich auf eine Anleitung, in der von einem anderen Proxy-Server die Rede war, nämlich Traefik. Traefik kann Proxy-Server sein, Loadbalancer und kümmert sich selbstständig um das Routing zu den ahinter liegenden Docker-Apps, außerdem kümmert er sich selbstständig um Letsencrypt-Zertifikate. Das schien mir genau die Lösung zu sein, die ich brauchte und bei Nginx mit viel Handarbeit umsetzen musste.

Um es kurz zu machen: Die oben verlinkte Anleitung für die Kombination von Traefik mit Commento hat natürlich nicht funktioniert.

ABER: Ich habe dann eine docker-compose.yml-Datei nach der offiziellen Traefik-Anleitung aufgebaut, noch keine weiteren Dienste hinzugefügt und das erst mal getestet. Das sah so aus (setzt voraus, dass man ein System mit Docker und Docker Compose am Start hat):

version: "3.3"

services:

  traefik:
    image: "traefik:v2.2"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      # Letsencrypt TLS 
      # https://docs.traefik.io/user-guides/docker-compose/acme-http/
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
      #- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.myresolver.acme.email=ADRESSE@EXAMPLE.ORG"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks: 
      - web

  whoami:
    image: "containous/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`SUBDOMAIN.EXAMPLE.ORG`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=myresolver"
    networks:
      - web

networks:
  web:
    external: true

Diese Datei sorgt dafür, dass die relevanten Docker-Container geladen werden, miteinander sprechen und der Service traefik dafür sorgt, dass die durch den Service whoami ermittelten Daten ausgegeben werden. Damit lässt sich testen, ob alles auf dem System funktioniert, dann kann man richtige Anwendungen hinter Traefik hängen.

Von da war es nicht mehr weit bis zum Einbinden von Commento. Das erforderte in meinem Fall einige Stunden des Experimentierens, weil meine YAML-Anweisungen dafür natürlich entweder von einem Betrieb ohne Proxy ausgingen oder aber auf das Setup mit Nginx ausgelegt waren. Das kann aus verschiedenen Gründen nicht funtionieren, ich bekam dauernd den Fehler 502 Bad Gateway, was dafür sprach, dass der Proxy-Server anstandslos funktionierte, aber die Anfragen nicht korrekt an den Commento-Server weiterleitete. Die HTTP-Version des Commento-Servers hingegen konnte ich via curl ohne Probleme erreichen (über den Browser ging es nicht, weil – wie ich nach einiger Recherche herausfand – gastauftritt.net in einer Liste geführt wird, die moderne Browser anweist, sich ausschließlich mit HTTPS zu verbinden (HSTS). Eigentlich eine feine Sache, sorgte nur bei mir dafür, dass ich erst mal auf die falsche Fährte geriet, weil ich meine Container nicht via HTTP erreichen konnte.

Zurück zu Commento: Letztendlich erfolgreich war ich mit folgenden Ergänzungen in der oben gezeigten docker-compose.yml (den Dienst whoami kann man entfernen):

  server:
    image: registry.gitlab.com/commento/commento
    environment:
      # For me, this only worked well WITHOUT specifying ports. Traefik will just find them ... ;)
      COMMENTO_ORIGIN: https://commento.example.org # PLEASE CHANGE TO YOUR URL!
      COMMENTO_POSTGRES: postgres://postgres:YOUR_OWN_PASSWORD@db:5432/commento?sslmode=disable # PLEASE CHANGE TO A SAVE DB PASSWORD!
      # SMTP settings, PLEASE CHANGE accordingly
      COMMENTO_SMTP_HOST: HOST
      COMMENTO_SMTP_PORT: 587
      COMMENTO_SMTP_USERNAME: USERNAME
      COMMENTO_SMTP_PASSWORD: PASSWORD
      COMMENTO_SMTP_FROM_ADDRESS: PROBABLY-SAME-AS-USERNAME
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`commento.example.org`)" # PLEASE CHANGE according to line 39
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=myresolver"
    depends_on:
      - db
    networks:
      - web

  db:
    image: postgres
    environment:
      POSTGRES_DB: commento
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: YOUR_OWN_PASSWORD # PLEASE CHANGE according to line 40!
    networks:
      - web
    volumes:
      - ./postgres/data:/var/lib/postgresql/data

volumes:
  postgres_data_volume:

Worauf man dabei achten muss: Im Unterschied zu anderen Proxy-Servern kümmert sich Traefik selbst um die Zuweisung der Ports und Kommunikation mit ihnen. Das heißt, der Commento-Server, der für Nginx z.B. die Anweisung bekäme

	ports:
	- 8080
  

um auf den Port 8080 zu hören, braucht und will diese Anweisung im Traefik-Setup nicht – sonst kommunizieren die Container aneinander vorbei. 8080 ist ohnehin eine schlechte Wahl im Zusammenhang mit Traefik, weil der Proxy-Server unter diesem Port ein übrigens sehr schickes Dashboard (mit Dark Mode!) zur Verfügung stellt.

traefik_750

Reboot-sicher machen

Natürlich funktioniert das alles, wenn man die Container mittels docker-compose up -d manuell startet. Aber was passiert, wenn man den Server neu starten muss oder – noch besser – er das (zum Beispiel nach einem Update) selbst tut?

Neulich hatte ich schon mal bei Jitsi gute Erfahrugen damit gemacht, das einfach per Cronjob zu regeln. Commento und Traefik haben darauf überhaupt nicht reagiert. Ein Blick in die Docker-Doku verriet mir: So macht man das auch nicht. Da steht auch relativ klar:

Do not try to combine Docker restart policies with host-level process managers, because this creates conflicts.

Richtig ist, den entsprechenden Containern in der docker-compose.yml zu sagen, dass sie sich neu starten sollen:

  restart: always

Ein weiterer wichtiger Baustein: Docker muss beim Systemstart natürlich auch gestartet werden. Das erreicht man, indem man im Terminal den Befehl

systemctl enable docker

eingibt. Und damit überlebt mein Kommentarsystem nun auch Reboots des Servers erfolgreich.

Eine (anonymisierte) Version meiner aktuellen docker-compose.yml habe ich übrigens bei Gitlab bereitgestellt. Dort habe ich die neuralgischen Stellen (auf Englisch) auch kommentiert. Sollten sich in der Zukunft Änderungen oder Verbesserungen ergeben, werde ich diese Datei natürlich aktualisieren.

Und was kann Commento?

Commento gefällt mir sehr gut. Das Backend ist spartanisch und beschränkt sich auf Einstellungen, moderiert wird per E-Mail oder nach Anmeldung direkt im Frontend. Wenn man das mal verstanden hat, ist es gut. Außerdem kann man in den Kommentaren Markdown verwenden, was nicht nur einige Optionen der Textgestaltung bietet, sondern auch prima zur Genese des gesamten Blogs passt (gut, das ist den Usern wurscht, aber mir gefällt’s).

Was mir bislang nicht so gut gefällt:

  • Man muss sich entweder anmelden (positiv: geht theoretisch auch u.a. über Twitter und Gitlab, de facto habe ich das noch nicht zum Laufen gebracht) oder kommentiert anonym unter dem Namen „Anonym“. In diesem Punkt gefällt mir Isso wesentlich besser, weil User da Name und E-Mail-Adresse sowie Website optional eingeben können.
  • Das Anpassen der Styles scheint nicht trivial zu sein – jedenfalls nicht trivial genug für mich; am Versuch, die Textgröße anzupassen, bin ich bisher grandios gescheitert.

Insgesamt nach einigen Tagen eine vorsichtig positive Bilanz – es kann aber durchaus sein, dass ich es mit Isso nochmal versuche.


Posts zu ähnlichen Themen:


Kommentare zu diesem Post