Stalwart: Difference between revisions
Add mail alias configuration |
→Tips and tricks: Auto update TLSA |
||
| Line 247: | Line 247: | ||
== Tips and tricks == | == Tips and tricks == | ||
=== Auto update TLSA records === | |||
Stalwart [https://github.com/stalwartlabs/stalwart/issues/1664 does not yet] automatically update the TLSA record if your ACME certificate changes. | |||
Following script is a possible workaounrd. It extracts the ACME cert every five minute, calculates the TLSA hash and compares it with the upstream record. If it doesn't match, it uses [https://github.com/Stenstromen/gotlsaflare gotlsaflare] to update the TLSA record on Cloudflare. | |||
{{file|/etc/nixos/configuration.nix|nix|3= | |||
systemd.services.tlsa-cloudflare-update = { | |||
description = "Check and update TLSA/DANE record for mx1 from Stalwart ACME Cert"; | |||
after = [ | |||
"network-online.target" | |||
"stalwart-mail.service" | |||
]; | |||
wants = [ | |||
"network-online.target" | |||
"stalwart-mail.service" | |||
]; | |||
serviceConfig = { | |||
Type = "oneshot"; | |||
User = "stalwart-mail"; | |||
Group = "stalwart-mail"; | |||
EnvironmentFile = config.age.secrets.stalwart-mail-cloudflare-secret.path; | |||
RuntimeDirectory = "stalwart-tlsa"; | |||
}; | |||
path = with pkgs; [ | |||
bash | |||
coreutils | |||
openssl | |||
dnsutils | |||
gotlsaflare | |||
rocksdb.tools | |||
gawk | |||
]; | |||
script = '' | |||
set -eu | |||
DOMAIN="example.org" | |||
SUBDOMAIN="mail" | |||
PORT="25" | |||
ACME_PROVIDER_ID="cloudflare" | |||
TLSA_RECORD="_$PORT._tcp.$SUBDOMAIN.$DOMAIN" | |||
DB_PATH="/var/lib/stalwart-mail/db" | |||
TEMP_RAW="/run/stalwart-tlsa/cert.bundle" | |||
TEMP_CRT="/run/stalwart-tlsa/cert.crt" | |||
echo "Starting TLSA update process for $DOMAIN" | |||
ldb --db="$DB_PATH" --column_family=s get "acme.$ACME_PROVIDER_ID.cert" | base64 -d > "$TEMP_RAW" | |||
if [ ! -s "$TEMP_RAW" ]; then | |||
echo "ERROR: ACME certificate extraction failed" | |||
exit 1 | |||
fi | |||
openssl x509 -in "$TEMP_RAW" -out "$TEMP_CRT" | |||
LOCAL_HASH=$(openssl x509 -in "$TEMP_CRT" -pubkey -noout | openssl pkey -pubin -outform DER | openssl sha256 | awk '{print tolower($2)}') | |||
echo "Local hash: $LOCAL_HASH" | |||
UPSTREAM_HASH=$(dig +nosplit +short TLSA "$TLSA_RECORD" | awk '{print tolower($4)}' | head -n1) | |||
echo "Upstream hash: $UPSTREAM_HASH" | |||
if [ "$LOCAL_HASH" = "$UPSTREAM_HASH" ]; then | |||
echo "Hashes match. DNS is up to date." | |||
exit 0 | |||
fi | |||
echo "Hashes differ! Updating Cloudflare..." | |||
gotlsaflare update \ | |||
--url "$DOMAIN" \ | |||
--subdomain "$SUBDOMAIN" \ | |||
--tcp"$PORT" \ | |||
--cert "$TEMP_CRT" | |||
echo "TLSA update completed successfully." | |||
''; | |||
}; | |||
systemd.timers.tlsa-cloudflare-update = { | |||
description = "Run TLSA check and update every 5 minutes"; | |||
wantedBy = [ "timers.target" ]; | |||
timerConfig = { | |||
OnBootSec = "2m"; | |||
OnUnitActiveSec = "5m"; | |||
Unit = "tlsa-cloudflare-update.service"; | |||
}; | |||
}; | |||
}} | |||
=== Test mail server === | === Test mail server === | ||