stalwart-migrator

In-place upgrade tool for Stalwart Mail Server, 0.15.5 → 0.16: no data loss, a checkpoint at every step so an interrupted run resumes instead of restarting, and automated validation that the server still works afterwards. Go, standard library only.

A companion to ihasmail, a JMAP-first webmail client for Stalwart. That one is what you read your mail in; this one gets the server underneath it onto a version that speaks the protocol it needs.

Caution

A migration cannot be undone, and this tool does not undo one. Recovery from a failed migration is your own snapshot or backup, taken beforehand and checked. run will not start until you confirm you have one. See Recovery.

Full guide: docs.ihasmail.org/install/stalwart-migrator walks through the whole upgrade — what to fix first, rehearsing, running it, and what to check afterwards.

Requirements

  • Stalwart 0.15.5, as a systemd service or a single Docker container
  • root on the mail server
  • python3, for Stalwart's own migrate_v016.py
  • stalwart-cli 1.0.2 or later, a separate download from the server
  • an administrator account in Stalwart's directory — not the fallback-admin from config.toml, which does not survive the migration
  • Go 1.26 or newer, to build

Fix these on the server first

Both stop a migration, and preflight refuses on both:

  1. Tenants that share a domain. v0.16 requires an account in a tenant to use only that tenant's domains. stalwart-migrate tenants shows who owns what.
  2. A config-file admin. Migrate as a directory account with the admin role, whose local part is unique and whose rights don't come only from tenant-admin.

Details: Known Stalwart problems.

Build

git clone https://github.com/Coffey-Labs/stalwart-migrator.git
cd stalwart-migrator
go build -o stalwart-migrate ./cmd/stalwart-migrate

Use

Give the admin password with --admin-password or STALWART_MIGRATE_ADMIN_PASSWORD.

# 1. Read-only checks and a migration plan
sudo ./stalwart-migrate preflight --admin-url https://mail.example.com --admin-user [email protected]

# 2. Read-only: convert your settings and report what won't carry over
sudo ./stalwart-migrate rehearse --admin-url https://mail.example.com --admin-user [email protected]

# 3. Rehearse the real migration on a clone of the server (strongly recommended)

# 4. Migrate, once you have a snapshot you have checked you can restore
sudo ./stalwart-migrate run --admin-url https://mail.example.com --admin-user [email protected] \
    --recovery-point-confirmed --yes

# Afterwards
sudo ./stalwart-migrate status <run-id>     # which steps completed
sudo ./stalwart-migrate report <run-id>     # what validation found

A Docker container also needs --container-path-unproven and --target-image; see Docker deployments. After the migration, check the certificate on ports 993 and 465, and recreate your ACME provider — Stalwart's converter drops it without saying so.

Status

Every command works: preflight, rehearse, run, tenants, status and report. It has migrated a production server (0.15.5 → 0.16.19, 8 seconds of downtime) and, in another operator's hands, three more. Two things are still open: some store migrations need one more recovery-mode boot, which is a manual step, and the Docker path has never completed a migration against a real Stalwart image. Details and field reports: Status.

Documentation

Upgrade guide The whole upgrade, step by step, on docs.ihasmail.org
docs/rehearsal.md Running preflight safely, what rehearse reports, rehearsing on a clone
docs/docker.md Container deployments: flags, what cutover carries and refuses, where the config goes
docs/known-stalwart-problems.md Tenants, the admin account, dropped ACME, certificates on mail ports, the extra recovery boot
docs/recovery.md Why recovery is your snapshot, what the tool keeps, never booting recovery mode again
docs/status.md Command and package state, validation, field reports
ARCHITECTURE.md The design: phases, checkpoints, and the reasoning behind them
CONTRIBUTING.md Building, testing, and where the design is written down

License

Copyright (C) 2026 Coffey Labs. GPL-3.0-or-later: free software, with no warranty. The full text is in LICENSE.

No third-party code is vendored — the tool is standard library only, and the migrate_v016.py it downloads at runtime is Stalwart's own script, fetched rather than redistributed.

S
Description
Imported from github.com during the 2026-09-20 standup (local dir: stalwart-migrator)
Readme GPL-3.0
537 KiB
v2026.9.15
Latest
2026-09-21 05:10:39 +00:00
Languages
Go 99.8%
Shell 0.2%