From d45fbf2c444640d2baebb104b69714c9a1e23d5d Mon Sep 17 00:00:00 2001 From: Lukas Remis Date: Sat, 10 Oct 2026 13:40:26 +0200 Subject: [PATCH] M6: network and DNS plan for hosted mail on the QNAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hosting decided (spec App. D §D.1 option A): Stalwart on the QNAP, receiving and sending directly; addresses @ultimo.email; mail apps allowed with app passwords; mail host mail.ultimo.email. docs/mail-server-network.md records the connection checks (clean IP, outbound 25 open, generic reverse DNS to change), the router / Synology / QNAP port layout, container ports, TLS certificate, the DNS records to set at home.pl, moving mail from home.pl, and checks after. Co-Authored-By: Claude Opus 5.5 --- docs/mail-server-network.md | 117 ++++++++++++++++++++++++++++++++++++ webmail-client-spec_v1.5.md | 2 + 2 files changed, 119 insertions(+) create mode 100644 docs/mail-server-network.md diff --git a/docs/mail-server-network.md b/docs/mail-server-network.md new file mode 100644 index 0000000..ed864ea --- /dev/null +++ b/docs/mail-server-network.md @@ -0,0 +1,117 @@ +# Hosted mail (M6): network and DNS plan + +Notes for switching `ultimo.email` mail from home.pl to Ultimo's own mail server +(Stalwart on the QNAP). Companion to the M6 plan in +`webmail-client-spec_v1.5.md` Appendix D. Gathered 2026-10-09/10. + +## Decisions + +| | Decision | +|---|---| +| Hosting | **Everything on the QNAP** — receive and send directly (spec §D.1 option A). A relay (home.pl SMTP, SMTP2GO, Brevo) is optional, as a fallback only. | +| Domain | Addresses `name@ultimo.email`; webmail stays at `https://ultimo.email`. | +| Mail apps | **Allowed**: Thunderbird and phone mail apps use the mailboxes over IMAP/SMTP, signing in with **app passwords** (required when 2FA is on). | +| Mail host name | **`mail.ultimo.email`** (recommended; `ultimo.email` would also work, see below). | + +## Current setup + +- Static public IP **`178.219.143.96`** (ISP: Multiplay). +- Traffic → **router** → **Synology DSM** → DSM **reverse proxy** → **QNAP** (the webmail). +- All DNS records are at **home.pl**: + - A `ultimo.email` → `178.219.143.96` (the QNAP, through the Synology); + - MX `ultimo.email` → `serwer2295308.home.pl` — **mail is still at home.pl**; + - other records also point at home.pl. + +## Checks of the connection (2026-10-10) + +| Check | Result | +|---|---| +| Blocklists — Spamhaus ZEN (incl. PBL), Barracuda, SpamCop, SORBS, UCEPROTECT | **Not listed** | +| Outbound port 25 (tested on the QNAP) | **Open** | +| Reverse DNS of `178.219.143.96` | `pub-143.96.multiplay.pl` — generic: **must change** (below) | +| Inbound 25 / 465 / 587 / 993 from outside | Time out — expected: not forwarded yet, nothing listening. Re-test after setup. | +| Inbound 443 | Open (webmail) | + +## To do before switching + +### 1. Reverse DNS (ask Multiplay) + +Set the reverse DNS (PTR) of `178.219.143.96` to **`mail.ultimo.email`**. + +Why: receiving servers (Gmail, Outlook…) check that three things agree — the +IP's reverse DNS name, that name's A record pointing back to the IP, and the +name the mail server introduces itself with (its SMTP greeting). A generic ISP +name or a mismatch reads as a hijacked home computer and hurts delivery. +`ultimo.email` itself would work too (its A record already points here); a +separate `mail.` name keeps mail working if the website ever moves elsewhere. + +### 2. Router: forward the mail ports straight to the QNAP + +DSM's reverse proxy carries only web traffic (HTTP/HTTPS); SMTP and IMAP are +other protocols, so these ports go from the router directly to the QNAP: + +| Outside port | To | Purpose | +|---|---|---| +| 443, 80 | Synology (as today) | webmail, CalDAV/CardDAV (`/dav/`, `/.well-known/…`), certificates | +| **25** | QNAP | receiving mail from other servers (must be 25: MX delivery always uses it) | +| **465** | QNAP | sending from mail apps (SMTP over TLS) | +| **587** | QNAP | sending from mail apps (SMTP + STARTTLS) | +| **993** | QNAP | mail apps reading mail (IMAP over TLS) | + +Mail sent by the QNAP leaves through the same router, i.e. from +`178.219.143.96` — the address the reverse DNS names. + +### 3. The container's ports + +Stalwart listens inside its container on the standard ports; Docker publishes +them on the QNAP — the same numbers if free (`"25:25"`, `"465:465"`, `"587:587"`, +`"993:993"`), or any free QNAP port (e.g. `"2525:25"`) with the router mapping +the standard outside port to it. Outside ports stay standard: 25 is mandatory, +and mail apps assume 465/587/993 when setting up an account. + +Verify after setup: Stalwart must see the **real IP** of connecting servers and +apps (not a Docker address) — its spam checks and sign-in throttling use it. + +### 4. TLS certificate for the mail server + +The Synology holds the HTTPS certificate, but IMAP/SMTP connections end at the +QNAP, so Stalwart needs its own for `mail.ultimo.email`. Options: + +- **(recommended)** Stalwart's own Let's Encrypt certificate: Let's Encrypt + checks over port 80, which goes to the Synology — add a **DSM reverse-proxy + rule: host `mail.ultimo.email`, port 80 → QNAP, Stalwart's HTTP port**. + Renews itself. +- DNS-based check, if home.pl's DNS can be updated automatically. +- Copy the Synology's certificate to the QNAP after every renewal (clumsiest). + +### 5. DNS records at home.pl (at switch-over) + +Lower the TTLs a day before. + +| Record | Value | +|---|---| +| A `mail.ultimo.email` | `178.219.143.96` | +| MX `ultimo.email` | `10 mail.ultimo.email.` (replaces `serwer2295308.home.pl`) | +| TXT `ultimo.email` (SPF) | `v=spf1 mx -all` (add the relay's include if one is used) | +| TXT `._domainkey.ultimo.email` (DKIM) | the public key Stalwart generates | +| TXT `_dmarc.ultimo.email` | `v=DMARC1; p=none; rua=mailto:postmaster@ultimo.email` — watch the reports, then move to `quarantine` / `reject` | +| (optional) `autoconfig` / SRV records | so Thunderbird and phones find the server settings by themselves | +| (optional) MTA-STS, TLS-RPT | enforce encrypted delivery to us | + +### 6. Moving the existing mail from home.pl + +1. Create the mailboxes in Ultimo. +2. Copy each home.pl mailbox into its new one over IMAP. +3. Switch the MX. +4. Keep the home.pl account in the webmail for a while to catch mail that + still arrives there (DNS caches), then remove it. + +### 7. Checks after switching + +- From outside: ports 25 / 465 / 587 / 993 answer (with a TLS certificate for + `mail.ultimo.email`). +- Reverse DNS → `mail.ultimo.email` → `178.219.143.96`, and Stalwart greets as + `mail.ultimo.email`. +- Mail to and from Gmail and Outlook: headers show SPF, DKIM and DMARC **pass**, + delivered to the inbox (not spam). +- Thunderbird sets up an account with just the address and an app password. diff --git a/webmail-client-spec_v1.5.md b/webmail-client-spec_v1.5.md index 063cdeb..ecbfd50 100644 --- a/webmail-client-spec_v1.5.md +++ b/webmail-client-spec_v1.5.md @@ -843,6 +843,8 @@ Receiving needs inbound port 25, an MX record and a fixed address; many home ISP | **B. NAS + relay (recommended)** | Small VPS holds the MX, forwards to the NAS over WireGuard | Relay service (SMTP2GO / Postmark / SES) or the VPS | Mail stays on the NAS; reliable delivery; the VPS is the SMTP-time spam edge (§C.7). | | **C. Stalwart on a VPS** | VPS | VPS | Mail stored off the NAS; webmail reaches it over the internet. | +**Chosen (2026-10-10): option A** — everything on the QNAP; see `docs/mail-server-network.md` for the network, DNS and port plan and the connection checks. + ### D.2 Infrastructure - `stalwart` service in both compose stacks (dev `webmail`, prod `webmail-prod` — never share the project name), image pinned to an exact version. - **Stores:** data store = a separate `stalwart` database on the existing Postgres; blob store = filesystem under `DATA_ROOT/stalwart` (bind mount, not a named volume). `backup.sh` and `webmail.sh update` (backup → migrate → roll → health-gate) then cover it; no RocksDB to snapshot separately.