2024-02-05 20:36:51 +00:00
# Adapted and simplified from https://nixos.wiki/wiki/Mailman
{
config ,
lib ,
2024-03-31 14:26:11 +00:00
pkgs ,
2024-02-05 20:36:51 +00:00
. . .
} : let
inherit
( lib )
mkIf
mkEnableOption
mkOption
;
inherit ( lib . types ) str ;
cfg = config . services . mathebau-mailman ;
in {
options . services . mathebau-mailman = {
enable = mkEnableOption " m a t h e b a u m a i l m a n s e r v i c e " ;
hostName = mkOption {
type = str ;
} ;
siteOwner = mkOption {
type = str ;
} ;
} ;
config = mkIf cfg . enable {
services = {
postfix = {
enable = true ;
relayDomains = [ " h a s h : / v a r / l i b / m a i l m a n / d a t a / p o s t f i x _ d o m a i n s " ] ;
sslCert = config . security . acme . certs . ${ cfg . hostName } . directory + " / f u l l . p e m " ;
sslKey = config . security . acme . certs . ${ cfg . hostName } . directory + " / k e y . p e m " ;
config = {
transport_maps = [ " h a s h : / v a r / l i b / m a i l m a n / d a t a / p o s t f i x _ l m t p " ] ;
local_recipient_maps = [ " h a s h : / v a r / l i b / m a i l m a n / d a t a / p o s t f i x _ l m t p " ] ;
proxy_interfaces = " 1 3 0 . 8 3 . 2 . 1 8 4 " ;
smtputf8_enable = " n o " ; # HRZ does not know SMTPUTF8
} ;
2024-03-31 18:28:40 +00:00
relayHost = " 1 9 2 . 1 6 8 . 0 . 2 4 " ; # Relay to eihort which relays to HRZ (see https://www.hrz.tu-darmstadt.de/services/it_services/email_infrastruktur/index.de.jsp)
2024-02-05 20:36:51 +00:00
} ;
mailman = {
enable = true ;
inherit ( cfg ) siteOwner ;
hyperkitty . enable = true ;
webHosts = [ cfg . hostName ] ;
serve . enable = true ; #
2024-03-31 14:26:11 +00:00
# Don't include confirmation tokens in reply addresses, because we would need to send them to HRZ otherwise.
settings . mta . verp_confirmations = " n o " ;
2024-02-05 20:36:51 +00:00
} ;
nginx . virtualHosts . ${ cfg . hostName } = {
2024-03-31 14:26:11 +00:00
enableACME = true ; # Get certificates (primarily for postfix)
forceSSL = false ; # Don't use HTTPS behind the proxy
2024-02-05 20:36:51 +00:00
} ;
} ;
environment . persistence . ${ config . impermanence . name } = {
directories = [
" / v a r / l i b / a c m e " # Persist TLS keys and account
" / v a r / l i b / m a i l m a n "
" / v a r / l i b / m a i l m a n - w e b "
] ;
2024-03-31 18:28:40 +00:00
files = [ " / r o o t / . s s h / k n o w n _ h o s t s " ] ; # for the backup server bragi
2024-02-05 20:36:51 +00:00
} ;
security . acme . defaults . email = cfg . siteOwner ;
security . acme . acceptTerms = true ;
networking . firewall . allowedTCPPorts = [ 25 80 443 ] ;
2024-03-31 14:26:11 +00:00
# Update HRZ allowlist
# For account details see https://www-cgi.hrz.tu-darmstadt.de/mail/
# will stop working if no valid TUIDs are associated to our domain.
systemd . timers . " m a i l A l l o w l i s t " = {
wantedBy = [ " t i m e r s . t a r g e t " ] ;
timerConfig = {
OnBootSec = " 5 m " ; # Run every 5 minutes
OnUnitActiveSec = " 5 m " ;
RandomizedDelaySec = " 2 m " ; # prevent overload on regular intervals
Unit = " m a i l A l l o w l i s t . s e r v i c e " ;
} ;
} ;
systemd . services . " m a i l A l l o w l i s t " = {
description = " A l l o w l i s t u p d a t e : P o s t t h e m a i l a d d r e s s e s u s e d b y m a i l m a n t o t h e H R Z a l l o w l l i s t " ;
script = ''
# Get the mail addresses' local-part
cut - d ' @ ' - f 1 /var/lib/mailman/data/postfix_lmtp | grep - v ' #' | grep "\S" > /tmp/addresses
# Post local-parts to HRZ
$ { pkgs . curl } /bin/curl https://www-cgi.hrz.tu-darmstadt.de/mail/whitelist-update.php - F emaildomain = $ { cfg . hostName } - F password = $ ( cat /run/secrets/allowlistPass ) - F emailliste = @ /tmp/addresses - F meldungen = voll
# Cleanup
rm /tmp/addresses
'' ;
serviceConfig = {
Type = " o n e s h o t " ;
User = " m a i l m a n " ;
2024-04-04 15:13:12 +00:00
NoNewPrivileges = true ;
# See https://www.man7.org/linux/man-pages/man5/systemd.exec.5.html
2024-03-31 14:26:11 +00:00
PrivateTmp = true ;
2024-04-04 15:13:12 +00:00
ProtectHome = true ;
ReadOnlyPaths = " / " ;
ReadWritePaths = " / t m p " ;
InaccessiblePaths = " - / l o s t + f o u n d " ;
PrivateDevices = true ;
PrivateUsers = true ;
ProtectHostname = true ;
ProtectClock = true ;
ProtectKernelTunables = true ;
ProtectKernelModules = true ;
ProtectKernelLogs = true ;
ProtectControlGroups = true ;
LockPersonality = true ;
MemoryDenyWriteExecute = true ;
RestrictRealtime = true ;
RestrictSUIDSGID = true ;
2024-03-31 14:26:11 +00:00
} ;
} ;
2024-03-31 18:28:40 +00:00
# Backups
services . borgbackup . jobs . mailman = {
paths = [
" / v a r / l i b / m a i l m a n / d a t a "
" / v a r / l i b / m a i l m a n - w e b "
] ;
encryption . mode = " n o n e " ; # Otherwise the key is next to the backup or we have human interaction.
environment = {
BORG_RSH = " s s h - i / r u n / s e c r e t s / b a c k u p K e y " ;
# “Borg ensures that backups are not created on random drives that ‘ just happen’ to contain a Borg repository.”
# https://borgbackup.readthedocs.io/en/stable/deployment/automated-local.html
# We don't want this in order to not need to persist borg cache and simplify new deployments.
BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = " y e s " ;
} ;
repo = " b o r g @ 1 9 2 . 1 6 8 . 1 . 1 1 : l o b o n " ; # TODO for https://gitea.mathebau.de/Fachschaft/nixConfig/issues/33
startAt = " d a i l y " ;
user = " r o o t " ;
group = " r o o t " ;
2024-03-31 14:26:11 +00:00
} ;
2024-02-05 20:36:51 +00:00
} ;
}