initial commit
flake-check / flake-check (push) Canceled after 0s
lint / lint (push) Canceled after 0s
diff-tag / dix (push) Canceled after 0s

This commit is contained in:
Floweynt
2026-08-31 08:41:45 -05:00
commit 76fa38e34c
54 changed files with 6747 additions and 0 deletions
+264
View File
@@ -0,0 +1,264 @@
{
name,
pkgs,
lib,
hostInfo,
dsl,
...
}:
let
inherit (dsl) mkContainer mkService;
inherit (hostInfo.paths) data secrets;
domain = "mail.floweytf.com";
accountName = "flowey";
stateDir = "/var/lib/stalwart";
acmeDir = "/etc/mail-acme";
taggingScript = ''
require ["envelope", "variables", "imap4flags", "fileinto"];
if envelope :localpart :matches "to" "*" {
addflag "''${1}";
}
fileinto "INBOX";
'';
cli = lib.getExe' pkgs.stalwart-cli "stalwart-cli";
jq = lib.getExe pkgs.jq;
curl = lib.getExe pkgs.curl;
grep = lib.getExe' pkgs.gnugrep "grep";
paste = lib.getExe' pkgs.coreutils "paste";
# use sqlite b/c rocksdb segfaults
configJsonTemplate = pkgs.writeText "stalwart-config.json" (
builtins.toJSON {
"@type" = "Sqlite";
path = "${stateDir}/data.sqlite3";
}
);
staticPlan = pkgs.writeText "mail-static-plan.json" (
builtins.concatStringsSep "\n" (
map builtins.toJSON [
{
"@type" = "upsert";
object = "Domain";
matchOn = [ "name" ];
value."domain-mail" = {
name = domain;
catchAllAddress = "${accountName}@${domain}";
isEnabled = true;
};
}
{
"@type" = "upsert";
object = "SieveSystemScript";
matchOn = [ "name" ];
value."sieve-tag" = {
name = "tag-by-recipient";
isActive = true;
contents = taggingScript;
};
}
]
)
+ "\n"
);
stalwartAuthEnv = ''
export STALWART_URL="http://127.0.0.1:8080"
export STALWART_USER="admin"
export STALWART_PASSWORD="$(cat "$CREDENTIALS_DIRECTORY/admin_password")"
'';
readyGate = pkgs.writeShellScript "mail-ready-gate" ''
set -uo pipefail
until ${curl} -sS -o /dev/null "http://127.0.0.1:8080/api/account"; do
if ! systemctl -q is-active stalwart.service; then
echo "mail: stalwart is not running" >&2
exit 1
fi
sleep 1
done
'';
bootstrapScript = pkgs.writeShellScript "mail-bootstrap" ''
set -uo pipefail
${stalwartAuthEnv}
out="$(${cli} update Bootstrap singleton \
--field defaultDomain=${domain} \
--field serverHostname=${domain} \
--field generateDkimKeys=true \
--field requestTlsCertificate=false \
--field 'directory={"@type":"Internal"}' 2>&1)"
status=$?
if [ "$status" -eq 0 ]; then
echo "mail-bootstrap: first-time setup complete, restarting stalwart into normal mode" >&2
systemctl restart stalwart.service
exit 0
fi
if ${grep} -qi 'bootstrap mode' <<<"$out"; then
exit 0
fi
echo "mail-bootstrap: $out" >&2
exit 1
'';
certCredCert = "/run/credentials/stalwart.service/mail_tls_cert";
certCredKey = "/run/credentials/stalwart.service/mail_tls_key";
retryOnFailure = {
Restart = "on-failure";
RestartSec = 5;
};
retryLimit = {
StartLimitBurst = 5;
StartLimitIntervalSec = 120;
};
provisionScript = pkgs.writeShellScript "mail-provision" ''
set -euo pipefail
${stalwartAuthEnv}
export account_pass="$(cat "$CREDENTIALS_DIRECTORY/account_password")"
account_entry="$(${jq} -nc --arg name "${accountName}" \
'{"@type":"upsert","object":"Account","matchOn":["name"],"value":{("account-"+$name):{"@type":"User","name":$name,"domainId":"#domain-mail","credentials":{"0":{"@type":"Password","secret":env.account_pass}}}}}')"
{ cat ${staticPlan}; echo "$account_entry"; } | ${cli} apply --stdin
existing_cert_ids="$(${cli} query Certificate --json --fields id | ${jq} -r .id | ${paste} -sd, -)"
if [ -n "$existing_cert_ids" ]; then
${cli} delete Certificate --ids "$existing_cert_ids"
fi
${cli} create Certificate \
--field 'certificate={"@type":"File","filePath":"${certCredCert}"}' \
--field 'privateKey={"@type":"File","filePath":"${certCredKey}"}'
systemctl restart stalwart.service
'';
in
mkContainer {
inherit name;
net.access = [ { to = "@internet"; } ];
svc.autoStart = true;
net.forward.tcp = [
25
993
];
resources.fs = {
"${stateDir}" = {
hostPath = "${data}/core/mail";
isReadOnly = false;
};
"${acmeDir}" = {
hostPath = "${data}/core/nginx/acme/${domain}";
isReadOnly = true;
};
"/run/secrets/mail-admin-password" = {
hostPath = "${secrets}/mail-admin-password";
isReadOnly = true;
};
"/run/secrets/mail-account-password" = {
hostPath = "${secrets}/mail-account-password";
isReadOnly = true;
};
};
users = [
{
name = "stalwart";
uid = 1000;
home = stateDir;
}
];
containerConfig = _: {
systemd.tmpfiles.rules = [
"Z ${stateDir} 0750 stalwart stalwart -"
"C ${stateDir}/config.json 0640 stalwart stalwart - ${configJsonTemplate}"
];
systemd.services.stalwart = mkService {
description = "Stalwart Mail Server";
execStart = pkgs.writeShellScript "stalwart-run" ''
set -euo pipefail
export STALWART_RECOVERY_ADMIN="admin:$(cat "$CREDENTIALS_DIRECTORY/admin_password")"
exec ${lib.getExe' pkgs.stalwart_0_16 "stalwart"} -c ${stateDir}/config.json
'';
serviceConfig = {
User = "stalwart";
Group = "stalwart";
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
ReadWritePaths = [ stateDir ];
LoadCredential = [
"admin_password:/run/secrets/mail-admin-password"
"mail_tls_cert:${acmeDir}/fullchain.pem"
"mail_tls_key:${acmeDir}/key.pem"
];
Restart = "on-failure";
RestartSec = 5;
};
};
systemd.paths.mail-cert-renew = {
wantedBy = [ "multi-user.target" ];
pathConfig = {
PathChanged = "${acmeDir}/key.pem";
Unit = "mail-provision.service";
};
};
systemd.services.mail-ready = mkService {
description = "Wait for the Stalwart management API";
execStart = readyGate;
after = [ "stalwart.service" ];
wants = [ "stalwart.service" ];
wantedBy = [ ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
TimeoutStartSec = 60;
};
};
systemd.services.mail-bootstrap = mkService {
description = "One-time Stalwart bootstrap (server identity + admin account)";
execStart = bootstrapScript;
after = [ "mail-ready.service" ];
wants = [ "mail-ready.service" ];
unitConfig = retryLimit;
serviceConfig = {
Type = "oneshot";
LoadCredential = [ "admin_password:/run/secrets/mail-admin-password" ];
}
// retryOnFailure;
};
systemd.services.mail-provision = mkService {
description = "Provision mail.floweytf.com domain + catch-all account in Stalwart";
execStart = provisionScript;
after = [
"mail-ready.service"
"mail-bootstrap.service"
];
wants = [
"mail-ready.service"
"mail-bootstrap.service"
];
serviceConfig = {
Type = "oneshot";
LoadCredential = [
"admin_password:/run/secrets/mail-admin-password"
"account_password:/run/secrets/mail-account-password"
];
}
// retryOnFailure;
unitConfig = retryLimit;
};
};
}