fix(infra): Stalwart v0.16 management admin is a real account (admin@dezky.eu)
ci / changes (push) Successful in 3s
ci / tc_operator (push) Has been skipped
ci / build_portal (push) Has been skipped
ci / build_operator (push) Has been skipped
ci / build_platform_api (push) Has been skipped
ci / tc_portal (push) Has been skipped
ci / tc_booking (push) Has been skipped
ci / tc_website (push) Has been skipped
ci / tc_platform_api (push) Has been skipped
ci / test_platform_api (push) Has been skipped
ci / build_booking (push) Has been skipped
ci / deploy (push) Successful in 42s

The v0.16 config migration silently dropped the fallback admin — the live
server had ZERO accounts, so every platform-api JMAP call 401'd and tenant
mail provisioning was dead. Bootstrapped via recovery mode on node1
(STALWART_RECOVERY_ADMIN): created the dezky.eu domain + an admin account
with the Admin role and the existing STALWART_ADMIN_PASSWORD.

v0.16 logins use the full address, so STALWART_ADMIN_USER becomes
admin@dezky.eu; config-rev annotation bump rolls platform-api so it picks
up the new env. install.sh follow-ups now document the recovery-mode
bootstrap for rebuilds instead of the defunct fallback-admin promise.
This commit is contained in:
Ronni Baslund
2026-06-10 20:50:25 +02:00
parent a43a172449
commit f66a343472
3 changed files with 21 additions and 2 deletions
@@ -12,7 +12,11 @@ data:
# Stalwart runs on the HOST (not k3s). Pods reach it via the cni0 gateway IP
# on the JMAP management port; the firewall lets the pod CIDR through.
STALWART_API_URL: "http://10.42.0.1:8080"
STALWART_ADMIN_USER: "admin"
# Full address, not bare "admin": Stalwart v0.16 has no fallback admin —
# the management credential is a real account (admin@dezky.eu, Admin role)
# created during the 2026-06-10 recovery-mode bootstrap, and v0.16 logins
# use the full address.
STALWART_ADMIN_USER: "admin@dezky.eu"
STALWART_PROVISIONING_ENABLED: "true"
# Base for per-tenant service mail domains ({slug}.dezky.eu) AND the
# reserved namespace for customer domains: only the dezky tenant may claim
@@ -18,6 +18,10 @@ spec:
metadata:
labels:
app.kubernetes.io/name: platform-api
annotations:
# Bump to force a rolling restart when only the ConfigMap changed —
# pods read it as env, which is only resolved at container start.
dezky.eu/config-rev: "2"
spec:
containers:
- name: platform-api
@@ -142,9 +142,20 @@ echo "╚═══════════════════════
systemctl --no-pager --lines=0 status stalwart-mail || true
echo ""
warn "Follow-ups:"
warn " • v0.16 has NO fallback admin — STALWART_ADMIN_PASSWORD alone does"
warn " nothing. Bootstrap the management account once:"
warn " 1. add to $PREFIX/etc/stalwart.env:"
warn " STALWART_RECOVERY_MODE=1"
warn " STALWART_RECOVERY_ADMIN=admin:<STALWART_ADMIN_PASSWORD>"
warn " and restart stalwart-mail (recovery listener on :8080)"
warn " 2. via JMAP (basic auth, those creds): x:Domain/set create the"
warn " primary domain, then x:Account/set create name=admin in it with"
warn " roles {\"@type\":\"Admin\"} and a Password credential"
warn " 3. remove the two STALWART_RECOVERY_* lines, restart again"
warn " • PTR/rDNS for the server IP MUST be 'mail.dezky.eu' (Hetzner Robot)."
warn " • Publish DNS at simply.com: MX → mail.dezky.eu, SPF, DMARC; per-domain"
warn " DKIM records come from Stalwart's dnsZoneFile via platform-api."
warn " • platform-api (k3s) env: STALWART_API_URL=http://<node-ip>:8080"
warn " STALWART_ADMIN_USER=admin STALWART_ADMIN_PASSWORD=<same as here>"
warn " STALWART_ADMIN_USER=admin@<primary-domain> (full address — v0.16 logins)"
warn " STALWART_ADMIN_PASSWORD=<same as here>"
warn " STALWART_WEBHOOK_SECRET=<same as here> STALWART_PROVISIONING_ENABLED=true"