Mein Stalwart-Upgrade von Version 0.15.5 auf Version 0.16.2

ACHTUNG: Die nachfolgende Beschreibung setzt voraus, dass diese beiden Schritte

  • Account-Namen müssen E-Mail-Adressen sein und
  • Installations-Layout ist an den FHS angepasst

vorab durchgeführt wurden. Der Blog-Beitrag „Stalwart-Verzeichnisse anpassen – Upgrade-v0.16 Vorbereitung“ erläutert die Erledigung dieser beiden Schritte.

Darüber hinaus bitte meine Installations-Variante als Grundlage beachten:

  1. Direkte Installation ins System. Kein Docker!!!
  2. Die typischen Mailports sind direkt erreichbar.
  3. Port 443 wird von HAProxy „abgefangen“ und je nach Server-Name weitergereicht:
    • Stalwart, oder
    • Apache

Software für Migration herunterladen, ggf. patchen …

Dieser vorbereitende Schritt erfolgte mit folgender Kommando-Sequenz:

# Software-Verzeichnis für Upgrade anlegen
mkdir -p ~/software/stalwart/backups
mkdir -p ~/software/stalwart/upgrade-v0.15-to-v0.16
cd ~/software/stalwart/upgrade-v0.15-to-v0.16

# Alte Stalwart-Binaries sichern
cp /usr/local/bin/stalwart ./stalwart.v015
cp /usr/local/bin/stalwart-cli ./stalwart-cli.v015

# Neue Stalwart-Binaries downloaden (Versionsnummern ggf. anpassen)
(cd /tmp && curl https://github.com/stalwartlabs/stalwart/releases/download/v0.16.2/stalwart-x86_64-unknown-linux-gnu.tar.gz -O -L && tar zxf stalwart-x86_64-unknown-linux-gnu.tar.gz )
cp /tmp/stalwart ./stalwart.v0.16.2
(cd /tmp && curl https://github.com/stalwartlabs/cli/releases/download/v1.0.4/stalwart-cli-x86_64-unknown-linux-gnu.tar.xz -O -L && tar Jxf stalwart-cli-x86_64-unknown-linux-gnu.tar.xz )
cp /tmp/stalwart-cli-x86_64-unknown-linux-gnu/stalwart-cli ./stalwart-cli.v1.0.4

# Helper-Skript für Migration herunterladen
curl -fLO https://raw.githubusercontent.com/stalwartlabs/stalwart/refs/heads/main/resources/scripts/migrate_v016.py

Sofern in der bisherigen Installation als „In-Memory Store“ ein Redis-Server verwendet wurde (ist bei mir der Fall) das Migrations-Skript migrate_v016.py mit diesem Redis-relevanten Patch anpassen. Beachten: Die Zeilennummern weichen vom aktuellen Skript ab – man findet aber manuell die passende Stelle an der Zeilen ergänzt werden müssen.

Einstellungen mit dem (gepatchten) Migrations-Skript extrahieren

cd ~/software/stalwart/upgrade-v0.15-to-v0.16
apt install python3-venv
python3 -m venv .venv
source .venv/bin/activate
pip install requests urllib3

# Mit Server verbinden und v0.15.x Einstellungen, sowie 
# Principals (Berechtigungsinhaber) in zwei Dateien
# auf Platte speichern
python migrate_v016.py dump \
    --url https://mx01.grupp-web.de \
    --username admin \
    --password <altes, bisheriges Admin-Passwort> \
    --settings settings.json \
    --principals principals.json
	
# Die gerade extrahierten Daten in neues Format konvertieren
python migrate_v016.py convert \
    --settings settings.json \
    --principals principals.json \
    --config config.json \
    --output export.json

Mail-Services in Firewall sperrren

Auf Firewall die Mail-Ports sperren. Damit können weder von Außen neue Mails eingeliefert werden, noch können meine User Mails versenden oder auf ihr Konto zugreifen. Damit soll eine saubere Sicherung der Mail-Datenbank, ohne Verlust zwischenzeitlicher Veränderungen am Mail-Bestand ermöglicht werden.

firewall-cmd --list-services
firewall-cmd --permanent --remove-service=imaps
firewall-cmd --permanent --remove-service=smtps
firewall-cmd --permanent --remove-service=smtp
firewall-cmd --reload
# Kontrolle / Vergleich zum vorigen Zustand
firewall-cmd --list-services

Stalwart stoppen und Mail-Datenbank sichern

systemctl stop stalwart.service
tar czf ~/software/stalwart/backups/Stalwart-v0.15-Mail-Backup.tgz \
        /var/lib/stalwart

Offline-Snapshot des Servers erstellen

ACHTUNG: Nun, falls möglich, einen Offline-Snapshot des Servers erstellen und erst dann fortfahren. Bei Cloud-Servern ist das eine typische Möglichkeit die in der Verwaltungsoberfläche des Providers angeboten wird.

Ist einfach sicherer da bei Problemen mit dem Upgrade eine Rückkehr zum vorigen Zustand total einfach und schnell möglich ist.

Und nun das Kern-Upgrade

# Da wegen Offline-Snapshot der Server evtl. neu gestartet wurde
systemctl stop stalwart.service

# Neues Stalwart-Binary installieren
cd ~/software/stalwart/upgrade-v0.15-to-v0.16
mv /usr/local/bin/stalwart /usr/local/bin/stalwart.v015
mv /usr/local/bin/stalwart-cli /usr/local/bin/stalwart-cli.v015
cp stalwart.v0.16.2 /usr/local/bin/stalwart
cp stalwart-cli.v1.0.4 /usr/local/bin/stalwart-cli
chmod 0755 /usr/local/bin/stalwart*
chown root:root /usr/local/bin/stalwart*

# config.json platzieren
cd ~/software/stalwart/upgrade-v0.15-to-v0.16
cp config.json /etc/stalwart/config.json
chown stalwart:stalwart /etc/stalwart/config.json
chmod 0640 /etc/stalwart/config.json

# Neuen Stalwart im Recovery-Mode starten
sudo -u stalwart env \
    STALWART_RECOVERY_MODE=1 \
    STALWART_RECOVERY_ADMIN=admin:Super.Geheim2026 \
    /usr/local/bin/stalwart --config=/etc/stalwart/config.json

Stalwart ist nun in dieser Shell im Recovery-Mode. Der Prozess läuft im Vordergrund und die Shell ist damit erst mal für weitere Tätigkeiten blockiert.

Deshalb zweite Shell starten. Dort werden nun die Daten aus export.json verarbeitet.

cd ~/software/stalwart/upgrade-v0.15-to-v0.16
export STALWART_URL=http://127.0.0.1:8080
export STALWART_USER=admin
export STALWART_PASSWORD=Super.Geheim2026
stalwart-cli apply --file ./export.json

In erster Shell den Stalwart („hängt“ als Vordergrund-Prozess in der ersten Shell) nun per „Strg“ + „C“ stoppen.

Bei Upgrade auf Version 0.16.2 (für 0.16.3 ignorieren und nächsten Absatz beachten) die Datei /etc/stalwart/stalwart.env mit folgendem Inhalt neu anlegen.

# Environment variables for the Stalwart service.
# Uncomment and edit an entry to override its default.

# Override the hostname used in HTTP responses
#STALWART_HOSTNAME=mail.example.com

# Override the HTTPS port used in HTTPS responses
#STALWART_HTTPS_PORT=8080

# Enable bootstrap / recovery mode on startup. Accepted: 1, true. Default: false.
#STALWART_RECOVERY_MODE=true

# Log level while in recovery mode. Default: info.
#STALWART_RECOVERY_MODE_LOG_LEVEL=debug

# HTTP port used in recovery mode. Default: 8080.
#STALWART_RECOVERY_MODE_PORT=9090

# Fixed administrator credentials — format: username:password
# Default: a temporary random password is generated and printed to the logs.
#STALWART_RECOVERY_ADMIN=admin:changeme

# Cluster role assigned to this node. Must match a role name defined in the
# cluster registry. Leave unset for a standalone (non-clustered) deployment.
#STALWART_ROLE=primary

# Push-notification shard this node is responsible for, when running in a
# cluster.
#STALWART_PUSH_SHARD=1

Bei Version 0.16.3 wird STALWART_HTTPS_PORT durch STALWART_PUBLIC_URL ersetzt. Die neue /etc/stalwart/stalwart.env sieht im Original dann so aus:

# Environment variables for the Stalwart service.
# Uncomment and edit an entry to override its default.

# Override the hostname used in HTTP responses
#STALWART_HOSTNAME=mail.example.com

# Override the public base URL published in OAuth, OIDC, and JMAP discovery
# documents. Accepts scheme, host, optional port, and optional path prefix.
#STALWART_PUBLIC_URL=https://mail.example.com

# Enable bootstrap / recovery mode on startup. Accepted: 1, true. Default: false.
#STALWART_RECOVERY_MODE=true

# Log level while in recovery mode. Default: info.
#STALWART_RECOVERY_MODE_LOG_LEVEL=debug

# HTTP port used in recovery mode. Default: 8080.
#STALWART_RECOVERY_MODE_PORT=9090

# Fixed administrator credentials — format: username:password
# Default: a temporary random password is generated and printed to the logs.
#STALWART_RECOVERY_ADMIN=admin:changeme

# Cluster role assigned to this node. Must match a role name defined in the
# cluster registry. Leave unset for a standalone (non-clustered) deployment.
#STALWART_ROLE=primary

# Push-notification shard this node is responsible for, when running in a
# cluster.
#STALWART_PUSH_SHARD=1

Anschließend Rechte anpassen:

chown stalwart:stalwart /etc/stalwart/stalwart.env
chmod o-rwx /etc/stalwart/stalwart.env

In dieser env-Datei die Zeile STALWART_RECOVERY_ADMIN aktivieren und passend zu oben anpassen. Bei mir also:

STALWART_RECOVERY_ADMIN=admin:Super.Geheim2026

In der bereits weiter oben für den FHS-Standard angepassten /etc/systemd/system/stalwart.service:

  • Vor der ExecStart-Zeile diese Zeile einfügen: EnvironmentFile=-/etc/stalwart/stalwart.env
  • Die beiden Vorkommen von config.toml durch config.json ersetzen.

Anschließend systemd reloaden und Stalwart starten:

systemctl daemon-reload
systemctl start stalwart

In einer Shell SSH-Sitzung mit Port-Forwarding aufbauen …

┌── andreas@pfaender: [ ~ ]  
└─$ ssh -L 8080:localhost:8080 root@s3.grupp-web.de 

und nun wieder über http://localhost:8080/admin auf die Web-Oberfläche zugreifen. Login mit den Daten von STALWART_RECOVERY_ADMIN, siehe oben.

Konfiguration über WebGUI auf Port 8080

  • Settings > TLS > Certificates > Create Certificate … nachfolgende Schritte durchführen und auf „Create“ klicken
    • Certificate > „Text value read from file“
    • File Path > /etc/ssl/certs/grupp-web-de-cert.pem
    • Private Key > „Text value read from file“
    • File Path > /etc/ssl/private/grupp-web-de-key.pem
  • Settings > Network > Listeners > https-Zeile anklicken
    • Bind addresses > [::]:8443 > auf + klicken
    • Bind addresses > [::]:443 > entfernen
    • Proxy networks > ::1 und 127.0.0.0/8 hinzufügen
  • Am Seitenende auf „Save“ klicken und
  • Stalwart mit systemctl restart stalwart neu starten. Änderungen an Listenern scheinen nur so aktiv zu werden
  • Settings > Network > Listeners > pop3s-Listener auf Port 995 entfernen
  • Settings > Storage > In Memory Store > Kontrollieren ob …
    • Store type > Redis/Valkey
    • URL > redis://127.0.0.1

Danach sollte der Zugriff auch wieder regulär über https://mx01.grupp-web.de/admin funktionieren.

  • Settings > Telemetry > Metrics > Prometheus
    • Collector > Enabled
    • Username > zabbix
    • Secret > „Secret value“ und das Passwort das beim Zabbix-Agent hinterlegt ist
  • Settings > Network > WebDAV
    • Assisted Discovery > aktivieren
  • Management > Tasks > …

Firewall wieder öffnen

Ok, das war’s dann. Mailserver wieder für Zugriffe auf allen relevanten Mail-Ports freigeben.

firewall-cmd --list-services
firewall-cmd --permanent --add-service=imaps
firewall-cmd --permanent --add-service=smtps
firewall-cmd --permanent --add-service=smtp
firewall-cmd --reload
# Kontrolle / Vergleich zum vorigen Zustand
firewall-cmd --list-services

ua-auto-config in DNS und HAproxy ergänzen

Stalwart stellt nun auch einen virtuellen Webserver für „Automatic Configuration of Email, Calendar, and Contact Server Settings“ bereit. Siehe z.B. hier bei der IETF.

Dazu gehören zwei beim DNS-Provider nachzupflegende DNS-Records, die Stalwart unter „Management > Domains > Domains > bei der jeweiligen Doman ‚View Zone File‘ “ bereitstellt. In meinem Fall aktuell …

ua-auto-config.grupp-web.de. IN CNAME mx01.grupp-web.de.
_ua-auto-config.grupp-web.de. IN TXT "v=UAAC1; a=sha256; d=pcFpmF5uuCmxQC ..."

Beachte: Die Angaben im _ua-auto-config-TXT-Record validieren die über den nachfolgend gezeigten Webserver bereitgestellten Auto-Config-Daten! In d ist bei obigem Fall ein SHA256-Hash über diese Daten.

Damit der virtuelle Webserver auch erreichbar ist muss der Hostname bei Reverse Proxy Settings (wie es ja auch ich anwende) im Reverse Proxy ebenfalls nachgepflegt werden – use_backend bk_stalwart if { req.ssl_sni -i ua-auto-config.grupp-web.de } und der HAproxy neu geladen werden.

Test durch Aufruf des well-known URIs für diese Konfigurationsdaten.

Weitere DNS-Änderung – MTA-STS

Beim DNS TXT-Record _mta-sts hat(te) sich die ID geändert. Die ist lt. zugehörigem RFC ein Wert der anderen Servern eine Änderung der Daten, die unter dem well-known-URI abrufbar sind, mitteilt. Habe ich also auch mal übernommen.

Schreibe einen Kommentar