From 275aea0b58d7cd7595115eed171798df7eb88fa3 Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:30:57 +0200 Subject: [PATCH] Bump dns-update --- CHANGELOG.md | 4 +++- Cargo.lock | 4 ++-- UPGRADING/v0_16.md | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e1055e9..4de1eaec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,9 @@ This version includes **multiple breaking changes**. If you are upgrading from v ## Fixed - Do not include port number when constructing HTTP base URLs. - OSS builds. -- Cloudflare `CAA` record updates. +- Cloudflare DNS updater: + - Fix `CAA` record updates. + - Check zone subdomains when finding zones ## [0.16.0] - 2026-04-20 diff --git a/Cargo.lock b/Cargo.lock index 4cf2b3f7..a2a78079 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1871,9 +1871,9 @@ dependencies = [ [[package]] name = "dns-update" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c66cca6c65ce66934ed66df2b49c6ce47aa419093c8e76af05495fa35c0ea9" +checksum = "e02da0fe33d1f2c0604bad883145ea2e9f72da8f32486f3a3faaf99fe7266271" dependencies = [ "aws-lc-rs", "base64 0.22.1", diff --git a/UPGRADING/v0_16.md b/UPGRADING/v0_16.md index ad2a050c..ed6c3581 100644 --- a/UPGRADING/v0_16.md +++ b/UPGRADING/v0_16.md @@ -368,6 +368,19 @@ $ docker run --rm \ alpine sh -c 'cp /src/config.json /dst/config.json && chown 2000:2000 /dst/config.json' ``` +> **Update embedded paths inside `config.json` and `export.json` for the new mount points.** The migration script writes the on-disk paths it found in the v0.15 deployment, which on the previous Docker image typically pointed at `/opt/stalwart/data` (and `/opt/stalwart/data/blobs` for the filesystem [BlobStore](https://stalw.art/docs/ref/object/blob-store)). The new image mounts persistent data at `/var/lib/stalwart` instead, so any path referencing the old location must be edited to point at the new one before the recovery container is started; otherwise the container exits with `Permission denied: /opt/stalwart/data` because UID `2000` cannot create that directory inside the container's filesystem. Two files need to be checked: +> +> - **`config.json`**: any embedded-store entry such as `RocksDb.path` or `SQLite.filePath` must be updated. For example, change `"path": "/opt/stalwart/data"` to `"path": "/var/lib/stalwart"`. +> - **`export.json`**: any filesystem `BlobStore` whose `basePath` references the old location must be edited the same way (`/opt/stalwart/data/blobs` → `/var/lib/stalwart/blobs`). Deployments that store blobs in S3, Azure Blob Storage, the database, or another non-filesystem backend can ignore this. +> +> A grep for `/opt/stalwart` against both files is the quickest way to confirm nothing was missed: +> +> ```bash +> $ grep -n /opt/stalwart /path/to/config.json /path/to/export.json +> ``` +> +> Skip this paragraph entirely on deployments that use external databases (PostgreSQL, MySQL, FoundationDB) and external blob backends; those deployments have no on-disk paths to rewrite. + **4. Start a temporary container in recovery mode.** This container exists only for the duration of the migration: ```bash @@ -444,6 +457,24 @@ https://mail.example.org/admin Replace `mail.example.org` with the server's hostname. Log in either with the recovery admin credential (if it is still active) or with the administrator account created via the test-deployment snapshot. +A few behavioural changes from `v0.15.x` are worth flagging before the first sign-in: + +- **The WebUI is reached over HTTPS on the configured hostname only.** The OAuth, OIDC, and JMAP discovery documents `v0.16` publishes use `https:///...` exclusively in normal mode. Loading the WebUI by IP address, by container name, or over plain HTTP (for example `http://192.168.1.10:8080/admin`) will appear to load the sign-in page but will fail at the OAuth callback. Use the same hostname that was entered in Step 1 of the wizard, or that already lives on `defaultHostname` from the migrated settings. +- **`http://...:8080` is no longer the right URL for day-to-day administration.** Port `8080` carries the recovery / bootstrap HTTP listener and is intended for the migration window; once the server is running normally it stops being a valid sign-in entry point. +- **When the public HTTPS port is not `443`** (for example a reverse proxy on `:8443`, or a Docker host port mapping that diverges from the container's `443`), set the [`STALWART_HTTPS_PORT`](https://stalw.art/docs/configuration/environment-variables#public-urls) environment variable to that port and restart the server. Without it, the discovery documents will publish `https:///...` (port `443` implied) and clients will be sent to a port the proxy is not listening on. +- **Plain-text mail listeners (port `587` submission, port `143` IMAP) are no longer added by default.** This is required for compliance with the PACC autoconfig draft, which only advertises implicit-TLS ports. Mail clients that were configured to connect over `587` STARTTLS will silently stop working until either the listener is recreated through the WebUI / CLI or the clients are pointed at the implicit-TLS ports (`465` for submission, `993` for IMAPS). + +#### Reverse-proxy deployments + +If the deployment sits behind a reverse proxy (NGINX, Traefik, Caddy, HAProxy, or similar), this is the part of the migration where proxy-related issues most often surface. The migrated `defaultHostname`, the proxy's public hostname, the proxy's listening port, and the proxy's TLS configuration all have to line up before the first sign-in completes; if any of them is off, the OAuth flow fails partway through with errors that are hard to relate back to the proxy. + +The most reliable way through this step is to **bypass the proxy temporarily** for the duration of the recovery-mode `apply`, the first sign-in, and the creation of a permanent administrator. Concretely: + +1. While running `stalwart-cli apply` and creating the permanent admin, point the CLI and the browser at Stalwart directly: `http://:8080` for the recovery-mode CLI session, then `https:///admin` (accepting any self-signed certificate warning) for the first WebUI sign-in. +2. Once a permanent administrator account exists and the WebUI is confirmed working, restore the reverse-proxy configuration. From this point forward, end users reach Stalwart through the proxy and the discovery documents already point at the public hostname over HTTPS. + +A full description of how `v0.16` composes the published URLs, how the proxy can talk to Stalwart on either HTTP or HTTPS, and where to set `STALWART_HTTPS_PORT` for non-standard public ports lives at https://stalw.art/docs/server/reverse-proxy/overview. + ### Recalculate disk quotas Disk quotas were reset to zero during the wipe and need to be rebuilt from the actual mailbox contents. Navigate to the **Tasks** section of the admin panel and trigger the **"Recalculate disk quotas"** task. This spawns one subtask per user account, each of which scans that user's storage and updates the counter. On large deployments this may take a while to complete: progress is visible in the Tasks panel. @@ -478,6 +509,12 @@ Most failures come from trying to create an object whose parent does not exist y This error means one node in a cluster was left running on `v0.15.x` while another was being migrated, and the old node wrote records in the obsolete format into the shared database. Stop every node in the cluster, ensure every binary is on `v0.16`, and restart. If corruption persists, the logs name the offending keys and they can be removed with the `stalwart-cli delete` command. +### `/admin` (or `/account`) returns `404 Not Found` + +The WebUI is delivered as a downloadable [Application](https://stalw.art/docs/applications/overview) bundle that the server fetches from `https://github.com/stalwartlabs/webui/releases/latest/` on first start, and then refreshes on a schedule. When the very first download fails, no bundle has been unpacked locally and every request to a WebUI mount path returns `404 Not Found`. This is the most common cause of "the server is running, port `8080` answers, but `/admin` returns 404" reports during the migration. + +The fix is to make sure outbound HTTPS from the Stalwart host can reach GitHub's release storage (`github.com` and `objects.githubusercontent.com`). On a host that genuinely cannot reach the public internet, stage the WebUI bundle on an internal HTTPS server and update the [`resourceUrl`](https://stalw.art/docs/ref/object/application#resourceurl) field on the WebUI's [Application](https://stalw.art/docs/ref/object/application) record to point at the internal location. After the first successful download, subsequent failures are non-fatal: the previously installed bundle stays in service and `/admin` keeps working until the next successful refresh. The full description, including the precise hosts involved, is at https://stalw.art/docs/management/webui/overview#outbound-network-requirement. + ### Rolling back If the migration cannot be completed within the available maintenance window, the database backup captured in Step 2 can be restored and the old binary (preserved as `/usr/local/bin/stalwart.v015` in the example) started again. The `v0.16` binary will refuse to start a second time against a database that has already been migrated, so restoring the pre-migration backup is the only path back to `v0.15.x`.