One container providing SMTP/IMAP/POP3/JMAP plus CalDAV/CardDAV, an admin UI and spam filtering — chosen over mailcow (owns its own installer, which is what killed the earlier attempt now sitting in scripts/unused/) and over Mailu (~7 containers) because a single image with a single data dir is the only shape that fits the existing conventions cleanly: one anchor service the updater can version, one path the backup engine can snapshot. Mail-specific departures from the usual app template, each deliberate: * Ports are FIXED, not random. Other mail servers connect to :25 by number and clients expect 465/587/993 — a randomised external port would silently make the server unreachable. Only the admin UI takes a random port, since that one really is just a browser behind Traefik. 143/995/4190/443 ship disabled; the port processor comments them out. * UPDATE_TYPE=manual and the image pinned to v0.16, not :latest. Stalwart is pre-1.0 and has said the storage schema is still being finalised, so an unattended minor bump could carry a data migration on the message store. This is the one app where the auto default is wrong. * BACKUP_STRATEGY=stop-snapshot-start. The message store is written continuously; a live copy can land mid-transaction. Seconds of queued delivery (senders retry) buys a consistent snapshot. * The install hook checks outbound port 25 and reverse DNS, then prints the MX/SPF/DMARC records with real values. A mail server whose container started is not a working mail server, and every remaining requirement lives at the registrar or the VPS provider. Admin credentials are seeded via STALWART_RECOVERY_ADMIN from the app config rather than left to Stalwart's first-run random password, which would otherwise exist only in the container log. Icon is a drawn placeholder, not the upstream trademark. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
93 lines
4.5 KiB
Bash
93 lines
4.5 KiB
Bash
#!/bin/bash
|
|
|
|
# Stalwart install hooks.
|
|
#
|
|
# Installing a mail server is not like installing any other app: the container
|
|
# starting successfully means almost nothing. Mail only works once DNS, reverse
|
|
# DNS and outbound port 25 are right, and every one of those lives OUTSIDE the
|
|
# box — at the registrar and the VPS provider. So the job of these hooks is to
|
|
# say plainly what still has to be done, with the actual values to enter, rather
|
|
# than reporting "installed" and leaving the admin to discover weeks later that
|
|
# their mail is landing in spam.
|
|
|
|
# Echo the admin credentials for the standard final-message block (word-split
|
|
# by the caller into positional args: user pass).
|
|
stalwart_install_message_data()
|
|
{
|
|
printf '%s %s' "${CFG_STALWART_ADMIN_USER:-admin}" "${CFG_STALWART_ADMIN_PASSWORD:-}"
|
|
}
|
|
|
|
stalwart_install_post_start()
|
|
{
|
|
local app_name="$1"
|
|
|
|
((menu_number++))
|
|
echo ""
|
|
echo "---- $menu_number. Mail server checks + the DNS records you still need"
|
|
echo ""
|
|
|
|
# Resolved admin port comes from the compose tag (format `external:internal`),
|
|
# the same source adguard's hook reads — the legacy $usedport1 isn't populated
|
|
# by the current install pipeline.
|
|
local compose_file="$containers_dir$app_name/docker-compose.yml"
|
|
local admin_pair admin_port
|
|
admin_pair=$(tagsManagerGetTagContent "$compose_file" "PORTS_TAG_1" 2>/dev/null)
|
|
admin_port="${admin_pair%%:*}"
|
|
|
|
# ---- 1. Can this host even send mail? --------------------------------
|
|
# Most cheap VPS providers block outbound 25 by default (and several only
|
|
# unblock on request). A blocked port 25 means no mail EVER leaves the box,
|
|
# and nothing in the WebUI would otherwise reveal it.
|
|
isNotice "Checking outbound port 25 (required to deliver mail to other servers)…"
|
|
if command -v timeout >/dev/null 2>&1 \
|
|
&& timeout 8 bash -c 'exec 3<>/dev/tcp/gmail-smtp-in.l.google.com/25' 2>/dev/null; then
|
|
isSuccessful "Outbound port 25 is open."
|
|
else
|
|
isError "Outbound port 25 appears BLOCKED or filtered on this host."
|
|
isNotice " Most VPS providers block it by default. Ask your provider to unblock"
|
|
isNotice " outbound 25, or mail will queue and never deliver."
|
|
fi
|
|
|
|
# ---- 2. Reverse DNS --------------------------------------------------
|
|
# Receiving servers check that the sending IP resolves back to a name. A
|
|
# generic provider PTR (e.g. static.1.2.3.4.provider.net) is a common reason
|
|
# for mail being junked, and it can only be fixed in the provider's panel.
|
|
if [[ -n "$public_ip_v4" ]] && command -v dig >/dev/null 2>&1; then
|
|
local ptr; ptr=$(dig +short -x "$public_ip_v4" 2>/dev/null | head -1)
|
|
if [[ -n "$ptr" ]]; then
|
|
isNotice "Reverse DNS (PTR) for $public_ip_v4 is: ${ptr%.}"
|
|
isNotice " It should match your mail hostname. Set it in your VPS provider's panel."
|
|
else
|
|
isError "No reverse DNS (PTR) record for $public_ip_v4 — set one at your VPS provider."
|
|
fi
|
|
fi
|
|
|
|
# ---- 3. The records the admin must add themselves --------------------
|
|
# Printed with real values so they can be pasted at the registrar. DKIM is
|
|
# deliberately NOT guessed here: Stalwart generates the keypair on first
|
|
# run, and the public key must be copied from its admin UI.
|
|
local mail_host="${host_setup:-your-mail-hostname}"
|
|
local mail_domain="${mail_host#*.}"
|
|
echo ""
|
|
isNotice "DNS records to add at your domain registrar:"
|
|
echo " MX @ 10 ${mail_host}"
|
|
echo " A ${mail_host} ${public_ip_v4:-<the IP of this server>}"
|
|
echo " TXT @ \"v=spf1 mx -all\""
|
|
echo " TXT _dmarc \"v=DMARC1; p=quarantine; rua=mailto:postmaster@${mail_domain}\""
|
|
echo " TXT <selector>._domainkey (DKIM — copy from Stalwart's admin UI once it has"
|
|
echo " generated the key; it is not known until then)"
|
|
echo ""
|
|
|
|
# ---- 4. Where to go next ---------------------------------------------
|
|
if [[ -n "$admin_port" ]]; then
|
|
isNotice "Finish setup in the admin interface:"
|
|
[[ -n "$public_ip_v4" ]] && echo " http://$public_ip_v4:$admin_port/"
|
|
echo ""
|
|
isNotice "Sign in as '${CFG_STALWART_ADMIN_USER:-admin}' with the password shown below,"
|
|
isNotice "then add your domain and create mailboxes."
|
|
fi
|
|
|
|
isNotice "Until MX, PTR, SPF, DKIM and DMARC are all in place, expect delivery"
|
|
isNotice "problems — that is normal for a new mail server, not a fault in the app."
|
|
}
|