Mailserver mit Postfix und Dovecot – Vorwort

Der Mailserver für die Domains customieze.de und customieze.com läuft jetzt seit ein paar Wochen, und ich will das Prozedere natürlich auch hier nochmal dokumentieren.

Das sollte der Mailserver alles können:

  • E-Mails für Empfänger in den Domains customieze.de und customieze.com per SMTP von anonymen Clients (z.B. von anderen Mailservern) annehmen
  • E-Mails für beliebige Empfänger von authentifizierten Clients per SMTP annehmen und ebenfalls per SMTP an den Mailserver des Empfängers weitergeben
  • Abruf der empfangenen E-Mails per IMAP
  • TLS mit Zertifikaten von Let’s Encrypt
  • Tags für E-Mail-Adressen, damit man mit Adressen wie ich+dubioseseite@customieze.de einfacher herausfinden kann, wer die E-Mail-Adresse verkauft hat

Das ganze Konstrukt soll auf Postfix und Dovecot basieren und natürlich – wie der ganze Rest auch – in Docker-Containern laufen. Einen Spamfilter gibt es erstmal nicht, der sollte sich aber bei Bedarf nachrüsten lassen.

Rückblickend kann ich nur sagen: E-Mail ist kein Ponyhof!

Den Weg zum aktuellen Zustand werde ich in den nächsten Blog-Beiträgen detaillierter beschreiben.

Gigantische Uploads

Die aktuelle Standard-Konfiguration von WordPress lässt nur eine Upload-Größe von 2 MiB zu. Das ist natürlich (!) zu wenig, wenn Dana mit ihren riesigen Fotos ankommt.

Die richtige Einstellung dafür ist gar nicht so leicht zu finden. Im Quellcode von WordPress finde ich schließlich, dass das Minimum der PHP-Einstellungen upload_max_filesize und post_max_size entscheidend ist. Das dort aufgerufene apply_filters wird dazu verwendet, den Wert in Multisite-Installationen von WordPress zu modifizieren, bei einem einfachen WordPress tut es gar nichts.

Ein Aufruf von docker-compose exec blog-wordpress php --ini verrät, dass der Docker-Container alle PHP-Konfigurationsdateien lädt, die auf das Muster /usr/local/etc/php/conf.d/*.ini passen.

Mit diesen Erkenntnissen lege ich – per COPY im Dockerfile – im WordPress-Container eine Datei /usr/local/etc/php/conf.d/large-upload.ini mit folgendem Inhalt an:

upload_max_filesize = 20M
post_max_size = 24M

Hinweis am Rande: In der Standardkonfiguration ist upload_max_filesize = 2M und post_max_size = 8M.

Damit die Änderung greift, aktualisiere ich den WordPress-Container, wobei das Docker-Image wegen der Änderungen am Dockerfile mit --build neu gebaut werden muss:

docker-compose up -d --build blog-wordpress
--> Restarting hex_blog-wordpress_1 ... done

Ein kurzer Blick in den Upload-Dialog verrät: Jetzt sind Uploads bis zu 20 MiB möglich!

MariaDB: MySQL, aber besser™!

Damit mir die Arbeit nicht ausgeht, stelle ich heute von MySQL auf die freie Variante namens MariaDB um. Hintergrund der Aktion: Ich wollte MariaDB schon immer mal ausprobieren, hatte aber noch keine Gelegenheit. Die wäre eigentlich schon vor ein paar Tagen da gewesen, aber… Vergessen. Dann halt jetzt!

Damit bei der Umstellung kein neu hinzugefügter Content verloren geht, stoppe ich erstmal den WordPress-Container:

Weiterlesen „MariaDB: MySQL, aber besser™!“

Verbessertes Backup

Das Backup-Skript sichert momentan zwar schon die Docker-Volumes, allerdings muss dort bei einer MySQL-Datenbank wie der von WordPress nicht unbedingt der aktuelle Stand stehen. Deshalb baue ich vor dem Aufruf des eigentlichen Backups noch den folgenden Aufruf ein:

/bin/docker exec hex_blog-wordpress-mysql_1 /bin/bash -c 'MYSQL_PWD=${MYSQL_ROOT_PASSWORD} /usr/bin/mysqldump -B wordpress --add-drop-database --single-transaction > /var/lib/mysql/wordpress-dump.sql' 2>/dev/null || true

Der Befehl lässt sich in zwei Teile zerlegen. Der äußere Teil wird direkt auf dem Server ausgeführt:

Weiterlesen „Verbessertes Backup“

Wir sind Borg!

Da sich in den letzten Tagen schon einiges an Content angesammelt hat und die Storagebox noch fast leer vor sich hin dümpelt, muss ein Backup-Mechanismus her!

Auf der Suche nach Backup-Tools stolpere ich über BorgBackup – oder kurz Borg. Schon alleine des Namens wegen bekommt es eine Chance!

Borg kann ein paar ganz nette Sachen: Deduplizierung, Komprimierung, Verschlüsselung. Außerdem ist es quelloffen, sehr gut dokumentiert, komplett auf der Kommandozeile bedienbar, und – last but not least – wird von der Storagebox von Hetzner direkt unterstützt.

Den Borg-Client werde ich NICHT in einem Docker-Container ausführen, weil er möglichst unabhängig von der restlichen Infrastruktur sein soll. Ein klassischer Cron-Job passt perfekt.

Zuerst lege ich mit borg init ein Borg-Repository auf der Storagebox an, in die anschließend per Cron-Job alle fünf Minuten die wichtigsten System-Verzeichnisse und die Docker-Volumes gesichert werden.

Als Name für die Backup-Archive verwende ich backup-{uuid4}. Der Platzhalter wird von Borg durch eine UUID ersetzt. Der Zeitpunkt des Backups ist in der Ausgabe von borg list enthalten, muss also nicht nochmal in den Archiv-Namen rein.

Im Anschluss an die Sicherung wird noch mit borg prune aufgeräumt, damit ich nicht in einem Jahr mit hunderttausend Archiven hantieren muss.

Mal sehen, wann ich das erste Backup brauche…

IP-Adressen vs. SSL

Ruft man eine der IP-Adressen des Servers direkt im Browser auf, sieht man Dinge, die man nicht sehen will: Beim Zugriff mit HTTP ist das eine hässliche Fehlerseite, mit HTTPS ist es ein Zertifikatsfehler.

Für HTTP lässt sich das relativ einfach beheben, indem im Reverse Proxy ein – nach außen nicht sichtbarer – Default-Host mit dem gemäß RFC2606 ungültigen Namen „invalid.invalid“ konfiguriert wird, der einfach nur einen Redirect liefert. Damit leiten http://176.9.147.173 und http://[2a01:4f8:160:30a8::2] schon mal richtig weiter.

Für HTTPS funktioniert das prinzipiell auch, allerdings macht mir dort SSL einen Strich durch die Rechnung: Da die IP-Adressen des Servers laut RIPE Hetzner gehören, wird mir keine vertrauenswürdige CA ein Zertifikat dafür ausstellen. Es muss also eine Alternative her, die ohne „richtiges“ Zertifikat auskommt. Um die Warnung im Browser kommt man dann aber leider nicht herum.

Als halbwegs brauchbare Lösung erscheint mir ein selbstsigniertes Zertifikat mit Text im „Common Name“. Das ist im eben angelegten Default-Host am Reverse Proxy auch schnell konfiguriert. Beim Zugriff auf https://176.9.147.173 und https://[2a01:4f8:160:30a8::2] bekommt man dann zwar den unvermeidlichen Zertifikatsfehler zu sehen, aber zumindest hat der eine hübsche Meldung:

Zertifikatsfehler mit netter Meldung
Zertifikatsfehler im Browser

Customieze sucht Platz

Jetzt wo so langsam echte Daten auf dem Server anfallen, ist auch eine entsprechende Datensicherung notwendig. Die braucht natürlich Platz außerhalb des Servers.

Hetzner bietet dafür externen Speicherplatz in zwei Formen an: Backup-Speicher und Storagebox. Preislich nehmen sie sich nichts, der Backup-Speicher ist allerdings nur aus dem Hetzner-Netz direkt erreichbar. Ich entscheide mich für die Storagebox mit 100 GB, weil ich gerne auch ohne irgendwelche Tunnel von „außen“ darauf zugreifen möchte.

Auch für den Zugriff auf die Storagebox ist eine schlüsselbasierte Authentifizierung möglich. Also schnell den öffentlichen Schlüssel auf der Storagebox abgelegt und… Nichts! Warum das nicht geht, verrät das Hetzner-Wiki: Für den Zugriff mit SCP/SFTP muss der öffentliche Schlüssel im RFC4716-Format auf der Storagebox abgelegt werden. WTF?! Na wenn’s sein muss… Konvertiert. Abgelegt. Läuft.