Record that this migrated a production server, and what it took
On 2026-08-25 the tool migrated a live mail server - nine domains, six accounts, a 2.4 GB RocksDB store - from 0.15.5 to 0.16.19 with 8 seconds of downtime and every phase green, validation included. The practice worth copying is the dress rehearsal on a clone that preceded it. `rehearse` is read-only and stops before applying, which is where a real migration fails; a clone closes that gap for about six seconds of production downtime. It caught four faults that would each have reached production, and three of them only appear against a real instance. The README now describes how to build one, including the parts that are easy to get wrong: a consistent copy of a single-writer store, and a guest with no route out so a copy of a live mail server cannot renew real certificates or deliver real queued mail. It also documents what Stalwart's own converter drops without saying so. migrate_v016.py consumes every acme.* setting, emits nothing, and does not report them as unmigrated - so a migration reports success while removing certificate renewal, and nothing looks wrong until the certificate expires about ninety days later. The AcmeProvider that had to be rebuilt by hand is recorded in ARCHITECTURE.md, shape confirmed against a live 0.16.19, as the specification for generating it in the supplemental plan.
This commit is contained in:
@@ -323,6 +323,22 @@ schema-migration flag is set for the target version, and the plan skips
|
||||
is intentionally the same engine with a shorter plan, not a separate
|
||||
code path, so it doesn't rot independently.
|
||||
|
||||
### 4.6a What the converter drops without saying so
|
||||
|
||||
`migrate_v016.py` consumes every `acme.*` setting and emits nothing for it,
|
||||
and does not list those keys as unmigrated either. The effect is a migration
|
||||
that reports complete success while quietly removing certificate renewal: the
|
||||
certificate itself carries over, so nothing looks wrong until it expires
|
||||
about ninety days later. Observed on a production migration, 2026-08-25.
|
||||
|
||||
The supplemental plan already generates what the converter leaves behind for
|
||||
listeners (§4.6). An `AcmeProvider` generator belongs alongside it. The
|
||||
object shape is known-good, having been applied to a live 0.16.19 server:
|
||||
`challengeType` and `renewBefore` are enums (`TlsAlpn01`, `R23`), `contact`
|
||||
is a value-keyed set rather than a list, and `accountKey`/`accountUri` are
|
||||
server-set and must be omitted — the server registers a fresh ACME account,
|
||||
since the v0.15 account key cannot be carried across.
|
||||
|
||||
### 4.7 Post-migration validation
|
||||
|
||||
**What this suite can assert depends on the boundary being crossed, and on
|
||||
|
||||
Reference in New Issue
Block a user