Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung E-Mail / Mailserver 27.10.2026 · 10 min Lesezeit

Stalwart 1.0 mit Docker Compose: neu installieren und von 0.16 umsteigen

Stalwart 1.0 ist das erste stabile Release des Mail- und Collaboration-Servers und öffnet keine 0.16-Datenbanken mehr. Die Anleitung zeigt die getestete Neuinstallation mit Docker Compose, Setup-Assistent, Domain, Postfach, Testmail über SMTP und IMAP, Backup und Restore der Volumes sowie den Umstieg von 0.16 mit stalwart-migrate.

Geprüft am 27.10.2026 · für Stalwart 1.0.0

Mit KI erstellt – redaktionelle Prüfung ausstehend

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Titelbild: Mailserver 1.0 mit Docker Compose, Karten für Neuinstallation, Sicherung und Umstieg von 0.16

Stalwart vereint SMTP, IMAP, POP3, JMAP, CalDAV, CardDAV und WebDAV in einem einzigen Rust-Prozess. Am 26. Oktober 2026 erschien mit Version 1.0.0 das erste stabile Release. Das Datenbankschema ist damit festgeschrieben, künftige Updates sollen ohne Migration auskommen. Der Preis ist ein einmaliger Bruch: Laut Release-Notes lassen sich 0.16-Installationen wegen des neuen Datenbanklayouts nicht direkt aktualisieren. Neu sind unter anderem Volltextsuche in PDF- und Office-Anhängen, DKIM2 mit Post-Quanten-Signaturen und OAuth-Scopes.

Diese Anleitung zeigt die im Labor getestete Neuinstallation mit Docker Compose und erklärt den Umstieg von 0.16. Für 0.16 gilt weiter die Vorgänger-Anleitung Stalwart Mailserver mit Docker Compose installieren. Unterschiede: 1.0 öffnet standardmäßig keine Ports 587 und 143, der Assistent legt den Administrator selbst an, und 0.16-Daten kopiert das neue Werkzeug stalwart-migrate.

Voraussetzungen

Ein Mailserver stellt höhere Anforderungen an Netz und DNS als andere Dienste:

  • Linux-Server mit mindestens 2 CPU-Kernen, 4 GB RAM und 20 GB SSD-Speicher, x86_64 oder ARM64 (das Image gibt es für amd64, arm64, ARMv7 und ARMv6).
  • Feste öffentliche IPv4-Adresse mit passendem Reverse-DNS-Eintrag auf den Server-Hostnamen, etwa mail.example.com. Wie das geht, zeigt Reverse-DNS für Mailserver einrichten.
  • Port 25 in beide Richtungen frei. Viele Anbieter sperren ihn.
  • Eine eigene Domain mit Zugriff auf die DNS-Zone und einen A-Eintrag für den Hostnamen.
  • Docker Engine mit Docker Compose Plugin. Die Grundinstallation auf Debian 12 oder Ubuntu 24.04 beschreibt Docker Compose unter Linux als Selfhosting-Grundlage.
  • Ausgehendes HTTPS für WebUI- und Spamregel-Downloads von GitHub.

Schritt 1: Projektordner und Compose-Datei anlegen

Die Compose-Datei folgt der offiziellen Docker-Anleitung. Wir pinnen den getesteten Tag v1.0.0; die Entwickler empfehlen v1, der automatisch allen 1.x-Releases folgt. Port 8080 bleibt an 127.0.0.1 gebunden, weil der Setup-Listener nicht gegen Passwortraten geschützt ist.

EckdatenWert
Imagestalwartlabs/stalwart:v1.0.0 (Docker Hub, auch ghcr.io)
Ports25 SMTP, 465 Submission mit TLS, 993 IMAPS, 995 POP3S, 4190 ManageSieve, 443 HTTPS und JMAP, 127.0.0.1:8080 Einrichtung
Volumes/etc/stalwart (config.json), /var/lib/stalwart (RocksDB mit Mails und Einstellungen)
Umgebungkeine Pflichtvariablen; optional STALWART_RECOVERY_ADMIN für einen festen Notfallzugang
sudo mkdir -p /opt/stalwart && cd /opt/stalwart
sudo nano compose.yaml
services:
  stalwart:
    image: stalwartlabs/stalwart:v1.0.0
    init: true
    restart: unless-stopped
    ports:
      - "25:25"
      - "465:465"
      - "993:993"
      - "995:995"
      - "4190:4190"
      - "443:443"
      - "127.0.0.1:8080:8080"
    volumes:
      - stalwart-etc:/etc/stalwart
      - stalwart-data:/var/lib/stalwart

volumes:
  stalwart-etc:
  stalwart-data:

Das Image bringt einen Healthcheck auf /healthz/live mit. Weitere Härtung erklärt Docker Compose absichern mit Secrets, Healthchecks und Non-Root.

Verifizieren: sudo docker compose config --quiet gibt nichts aus, die Datei ist also gültig.

Schritt 2: Container starten und Einmal-Passwort lesen

Ohne config.json startet Stalwart im Bootstrap-Modus: nur Setup-Assistent auf Port 8080 und ein temporärer Administrator admin, dessen Zufallspasswort einmal im Log steht.

sudo docker compose up -d --pull always
sudo docker compose ps
sudo docker compose logs stalwart 2>&1 | grep -A8 'bootstrap mode'
Stalwart bootstrap mode - temporary administrator account
   username: admin
   password: ****************
WARN Server started in bootstrap mode (server.bootstrap-mode) hostname = "5e0bd476a0f3",
  details = "No configuration file was found. Port 8080 is open for initial setup.", version = "1.0.0"

Jeder Neustart erzeugt ein neues Passwort.

Verifizieren: docker compose ps zeigt nach etwa 20 Sekunden Up (healthy), und die Logzeile nennt version = "1.0.0".

Schritt 3: Setup-Assistent abschließen und neu starten

Öffnen Sie per SSH-Tunnel http://127.0.0.1:8080/admin und melden Sie sich als admin an.

ssh -L 8080:127.0.0.1:8080 admin@mail.example.com

Wichtig sind diese Felder der fünf Seiten:

  • Server Hostname und Default Email Domain: Im Container mit der Container-ID vorbelegt. Tragen Sie mail.example.com und example.com ein. Den Kurznamen mail lehnte Stalwart im Test erst beim Abschicken mit Invalid server hostname ab.
  • Automatically Obtain TLS Certificate und Generate Email Signing Keys bleiben aktiv. Ohne DNS-Anbieter prüft Let’s Encrypt über Port 443; CNAMEs für mta-sts, autoconfig, autodiscover und ua-auto-config müssen vorher auf den Hostnamen zeigen.
  • Storage: RocksDB unter /var/lib/stalwart/ beibehalten.
  • Logging: unter Docker Console wählen, sonst schreibt der Container kein Log.
  • DNS: Bei unterstützten Anbietern wie Cloudflare pflegt Stalwart die Einträge selbst.

Die letzte Seite zeigt einmalig das Passwort des Administrators admin@example.com. Speichern Sie es sofort, dann neu starten:

sudo docker compose restart stalwart
sudo docker compose exec stalwart cat /etc/stalwart/config.json
{"@type":"RocksDb","path":"/var/lib/stalwart/","blobSize":4096,"bufferSize":134217728,...}
INFO Network listener started (network.listen-start) listenerId = "submissions", localPort = 465, tls = true
INFO DKIM signature created (dkim.signature-created) name = "v1-ed25519-20261027", domain = "example.com"

config.json enthält nur den Datenspeicher, alles andere liegt in der Datenbank.

Verifizieren: sudo docker compose logs stalwart | grep listen-start listet sieben Listener, und es erscheint kein Bootstrap-Block mehr.

Schritt 4: In der WebUI Domain, Postfach und DNS einrichten

Nach dem Neustart akzeptiert die WebUI Anmeldungen nur noch per HTTPS unter dem Server-Hostnamen: https://mail.example.com/admin. Über IP-Adresse oder abweichenden Namen bricht die Anmeldung im Test so ab:

Stalwart-Anmeldeseite mit der Meldung Client metadata documents are disabled
Anmeldung über eine Adresse, die nicht dem Server-Hostnamen entspricht: Stalwart bricht mit dieser Meldung ab.

Legen Sie unter Management, Directory, Accounts ein eigenes Postfach an; das Passwort kommt unter Authentication, Credentials hinzu. Unter acht Zeichen meldet Stalwart Password must be at least 8 characters long.

Stalwart-WebUI mit der Kontenliste, darin admin@example.com und lisa@example.com
Management, Directory, Accounts: das Administratorkonto aus dem Assistenten und das neue Postfach.

Unter Domains zeigt View Zone File alle berechneten Einträge: MX, SPF, DMARC, DKIM (Ed25519 und RSA), SRV, MTA-STS und TLS-Reporting.

Stalwart-WebUI mit der Domainliste example.com und beispiel-firma.de, jeweils manuelles DNS- und Zertifikatsmanagement
Domains-Ansicht mit zwei Domains; das Menü am Zeilenende öffnet die Zonendatei.
Stalwart-WebUI zeigt die DNS-Zonendatei mit DKIM-, SPF-, MX-, DMARC- und SRV-Einträgen für example.com
View Zone File: alle DNS-Einträge, die Stalwart für die Domain berechnet hat, im BIND-Format.

Ohne DNS-Automatik übertragen Sie die Einträge selbst; den MX setzen Sie immer selbst. Gibt es schon einen SPF-Eintrag, führen Sie beide zu einem zusammen, denn zwei v=spf1-Einträge lassen SPF scheitern. Prüfen hilft das SPF- und DMARC-Werkzeug.

dig +short @1.1.1.1 MX example.com
dig +short @1.1.1.1 TXT example.com
dig +short @1.1.1.1 TXT _dmarc.example.com
dig +short @1.1.1.1 TXT v1-ed25519-20261027._domainkey.example.com

Verifizieren: Jede Abfrage liefert denselben Wert wie die Zonendatei, und der Browser zeigt nach kurzer Zeit ein Let’s-Encrypt-Zertifikat statt einer Warnung.

Schritt 5: Testmail senden und per IMAP abrufen

Mailprogramme nutzen IMAP 993 und SMTP 465 mit SSL/TLS und der vollen Adresse als Benutzername. Schnelltest mit curl (fragt das Passwort ab):

printf 'From: lisa@example.com\r\nTo: lisa@example.com\r\nSubject: Test 1.0\r\n\r\nHallo\r\n' > test.eml
curl --url smtps://mail.example.com:465 --user lisa@example.com \
  --mail-from lisa@example.com --mail-rcpt lisa@example.com --upload-file test.eml -v
curl --url "imaps://mail.example.com:993/INBOX" --user lisa@example.com -X "SEARCH SUBJECT Test"
< 250 2.0.0 Message queued with id 4adef6de8800000.
* SEARCH 1

Die Mail trug zwei DKIM-Signaturen (a=ed25519-sha256 und a=rsa-sha256). Den Weg nach außen prüfen Sie mit einer Mail an einen anderen Anbieter und einer Antwort; SPF, DKIM und DMARC sollten pass melden.

Verifizieren: Der SMTP-Dialog endet mit 250 2.0.0 Message queued, und die IMAP-Suche liefert mindestens eine Nachrichtennummer.

Schritt 6: Sichern und wiederherstellen

Mit RocksDB liegen Daten und Mailinhalte in einer Datenbank, eine Online-Sicherung gibt es nicht. Nutzen Sie einen atomaren Snapshot (LVM, ZFS, btrfs) oder stoppen Sie den Container; rsync im laufenden Betrieb ergibt eine inkonsistente Kopie.

cd /opt/stalwart && sudo mkdir -p backup
sudo docker compose stop stalwart
sudo docker run --rm -v stalwart_stalwart-etc:/etc/stalwart:ro -v stalwart_stalwart-data:/var/lib/stalwart:ro \
  -v "$PWD/backup":/backup alpine:3.22 tar czf /backup/stalwart-$(date +%F).tar.gz -C / etc/stalwart var/lib/stalwart
sudo docker compose start stalwart

Volume-Namen zeigt docker volume ls. Im Test haben wir Marker-Mail und Marker-Konto angelegt, gesichert und mit docker compose down -v alles gelöscht; der leere Server startete im Bootstrap-Modus. Restore:

sudo docker compose down -v
sudo docker compose create
sudo docker run --rm -v stalwart_stalwart-etc:/etc/stalwart -v stalwart_stalwart-data:/var/lib/stalwart \
  -v "$PWD/backup":/backup:ro alpine:3.22 tar xzf /backup/stalwart-2026-10-27.tar.gz -C /
sudo docker compose start stalwart

docker compose create legt die Volumes mit Compose-Labels an; mit docker volume create warnt Compose volume ... already exists but was not created by Docker Compose. Besitzer 2000:2000 bleibt erhalten. Marker-Mail und Marker-Konto waren danach wieder da.

Verifizieren: Nach dem Restore erscheint im Log Starting Stalwart Server statt des Bootstrap-Blocks, und Ihr Postfach enthält die Mails vom Sicherungszeitpunkt.

Schritt 7: Innerhalb von 1.x aktualisieren

Patch-Releases wie 1.0.1 enthalten nur Fehlerbehebungen, Minor-Releases können Vorgaben ändern, Major-Releases das Datenformat. Vor Minor- und Major-Updates sichern Sie wie in Schritt 6, dann Tag ändern oder bei v1 einfach:

sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs stalwart | grep 'Starting Stalwart'

Im Test zeigte v1 am 27. Oktober auf denselben Image-Digest wie v1.0.0; nach dem Wechsel waren alle Mails und Konten vorhanden. Meiden Sie latest, er folgt auch Major-Versionen. Watchtower oder Diun sollten nur melden, siehe Container-Updates mit Diun und WUD.

Verifizieren: Die Logzeile Starting Stalwart Server nennt die neue Versionsnummer, und docker compose ps zeigt healthy.

Schritt 8: Von 0.16 auf 1.0 umsteigen

Ein Tag-Wechsel reicht nicht. Mit einer 0.16.27-Instanz beendete sich der 1.0-Container im Test sofort mit Exited (1):

Server startup error (server.startup-error): details = The data store was created by a Stalwart version
prior to 1.0 and cannot be opened by this version.

Die 0.16-Daten bleiben unverändert. Für den Umzug gibt es stalwart-migrate (Image stalwartlabs/stalwart-migrate). Es liest den 0.16-Speicher nur und kopiert alles in einen neuen, leeren 1.0-Speicher; IMAP-UIDs und UIDVALIDITY bleiben erhalten. Laut Dokumentation:

  1. Die Quelle auf 0.16.27 aktualisieren und Platz für eine zweite Kopie des Datenspeichers schaffen.
  2. Einen migrate-Dienst mit alten und zwei neuen Volumes in die Compose-Datei aufnehmen (unten).
  3. prepare ausführen, Fragen zur Umsetzung beantworten und prepare-report.txt lesen.
  4. run im laufenden Betrieb, Wiederholungen kopieren nur Änderungen.
  5. Im Wartungsfenster 0.16 stoppen und run --final ausführen, danach report --severity error prüfen.
  6. 1.0 mit der neuen config.json und dem neuen Daten-Volume starten.
  migrate:
    image: stalwartlabs/stalwart-migrate:1.0.0
    profiles: [migrate]
    volumes:
      - stalwart-etc:/etc/stalwart:ro
      - stalwart-data:/var/lib/stalwart
      - stalwart-v1-etc:/etc/stalwart-v1
      - stalwart-v1-data:/var/lib/stalwart-v1
      - migrate-state:/var/lib/stalwart-migrate
sudo docker compose run --rm migrate prepare --source /etc/stalwart/config.json --state /var/lib/stalwart-migrate
sudo docker compose run --rm migrate run --source /etc/stalwart/config.json \
  --target /etc/stalwart-v1/config.json --state /var/lib/stalwart-migrate
sudo docker compose run --rm migrate run --final --source /etc/stalwart/config.json \
  --target /etc/stalwart-v1/config.json --state /var/lib/stalwart-migrate

Danach melden sich Nutzer in OAuth-Clients neu an, CalDAV-Clients laden einmal neu, der Suchindex wird neu aufgebaut. Behalten Sie den 0.16-Speicher, bis 1.0 sich bewährt hat; rollback kopiert notfalls zurück. Skripte gegen die Bootstrap-API: Das Hostnamen-Feld heißt in 0.16.27 serverHostname, in 1.0 defaultHostname.

Verifizieren: run --final endet ohne Fehler, der 1.0-Container startet mit Starting Stalwart Server, und ein Test-Postfach zeigt seine bisherigen Mails.

Troubleshooting

MeldungUrsache und Lösung
Invalid server hostnameKurzname oder Container-ID im Assistenten. Vollständigen Hostnamen eintragen.
Client metadata documents are disabledWebUI über IP, Proxy oder fremden Namen geöffnet. https://HOSTNAME/admin verwenden oder die öffentliche URL laut Reverse-Proxy-Doku setzen.
503 5.5.1 You must authenticate first.Mailprogramm sendet über 465 ohne Anmeldung. Authentifizierung für den Postausgang aktivieren.
501 5.5.4 You are not allowed to send from this address.Absender gehört nicht zum Konto. Adresse oder Alias anpassen.
The data store was created by a Stalwart version prior to 1.01.0-Image auf 0.16-Volume. Zurück auf den alten Tag und mit stalwart-migrate umziehen.
Wieder Setup-Assistent nach NeuerstellungVolume für /etc/stalwart fehlt oder ist leer. config.json zurückspielen.
WARN No TLS certificates availableZertifikat noch nicht ausgestellt. DNS-Einträge und Erreichbarkeit von Port 443 prüfen.

Port 8080 sollte nach dem Setup nicht aus dem Internet erreichbar sein. Dazu hilft eine Host-Firewall, siehe Linux-Server mit UFW und Fail2ban absichern beschrieben.

Häufige Fragen

Brauche ich Port 587 und 143?

Stalwart 1.0 legt diese Listener standardmäßig nicht mehr an und empfiehlt implizites TLS auf 465 und 993. Für STARTTLS-Geräte legen Sie die Listener in der WebUI an und veröffentlichen die Ports.

Kann ich das Bootstrap-Passwort festlegen?

Ja, mit STALWART_RECOVERY_ADMIN=admin:PASSWORT in der Umgebung. Sie gilt auch im Normalbetrieb als Vollzugriff, entfernen Sie sie nach dem Setup.

Bleiben meine 0.16-Daten beim Umstieg erhalten?

Ja, stalwart-migrate liest sie nur. Bis 1.0 produktiv läuft, kommen Sie mit dem alten Tag zurück.

Fazit

Die Neuinstallation von Stalwart 1.0 ist schlank: ein Container, zwei Volumes, ein Assistent. Stolpersteine sind der Hostname und die Log-Einstellung Console. Backup und Restore liefen ohne Nacharbeit. Von 0.16 aus planen Sie eine Kopie mit stalwart-migrate samt Wartungsfenster, danach reicht innerhalb von 1.x ein docker compose pull.

Weiterführende Anleitungen und Quellen

StalwartMailserverDocker ComposeSMTPIMAPJMAPMigrationSelfhosting