forked from Fachschaft/nixConfig
Add basic mailserver configuration
This commit is contained in:
parent
2aa93c98f5
commit
d7b8f935cd
2 changed files with 178 additions and 0 deletions
|
@ -1,12 +1,19 @@
|
||||||
{config, ...}: {
|
{config, ...}: {
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
|
../../modules/mail.nix
|
||||||
../../roles
|
../../roles
|
||||||
../../roles/vm.nix
|
../../roles/vm.nix
|
||||||
../../modules/vmNetwork.nix
|
../../modules/vmNetwork.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
# System configuration here
|
# System configuration here
|
||||||
|
services.mathebau-mail = {
|
||||||
|
enable = true;
|
||||||
|
# see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH
|
||||||
|
stalwartAdminHash = "$argon2i$v=19$m=4096,t=3,p=1$d0hYOTkzclpzSmFTZUplWnhVeWE$I7q9uB19RWL0oZKaPlMPSlGfFp6FQ/vrx80FFKCsalg";
|
||||||
|
};
|
||||||
|
|
||||||
networking.hostName = "kaalut";
|
networking.hostName = "kaalut";
|
||||||
vmNetwork.ipv4 = "192.168.0.17";
|
vmNetwork.ipv4 = "192.168.0.17";
|
||||||
system.stateVersion = "24.05";
|
system.stateVersion = "24.05";
|
||||||
|
|
171
nixos/modules/mail.nix
Normal file
171
nixos/modules/mail.nix
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Using the web admin interface: Set your SSH to do portforwarding of some local port to port 80 of the VM and
|
||||||
|
* and use your personal admin account or create one using the fallback admin password.
|
||||||
|
* Create users with mail boxes: Go to the admin interface and create them.
|
||||||
|
* Stalwart mailserver docs can be found at https://stalw.art/docs
|
||||||
|
* DNS-Records: Collect the right DNS entries from the management interface and copy them to the DNS hoster. Caution:
|
||||||
|
* Not all entries are applicable since we relay via HRZ.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
mkIf
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
;
|
||||||
|
inherit (lib.types) listOf strMatching str path;
|
||||||
|
cfg = config.services.mathebau-mail;
|
||||||
|
in {
|
||||||
|
options.services.mathebau-mail = {
|
||||||
|
enable = mkEnableOption "mathebau mail service";
|
||||||
|
stalwartAdminHash = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "String containing the hashed fallback admin password";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
services = {
|
||||||
|
stalwart-mail = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
lookup.default.hostname = "fb04184.mathematik.tu-darmstadt.de"; # Because the DNS PTR of 130.83.2.184 is this and this should be used in SMTP EHLO.
|
||||||
|
listener = {
|
||||||
|
"smtp" = {
|
||||||
|
bind = ["[::]:25"];
|
||||||
|
protocol = "smtp";
|
||||||
|
};
|
||||||
|
"submissions" = {
|
||||||
|
bind = ["[::]:465"];
|
||||||
|
protocol = "smtp";
|
||||||
|
tls.implicit = true;
|
||||||
|
};
|
||||||
|
"imaptls" = {
|
||||||
|
bind = ["[::]:993"];
|
||||||
|
protocol = "imap";
|
||||||
|
tls.implicit = true;
|
||||||
|
};
|
||||||
|
"management" = {
|
||||||
|
# Cthulhu forwards requests for http://fb04184.mathematik.tu-darmstadt.de/.well-known/acme-challenge/ http://imap.mathebau.de/.well-known/acme-challenge/ and http://smtp.mathebau.de/.well-known/acme-challenge/
|
||||||
|
# for TLS certificate challenge validation
|
||||||
|
# whereas the rest of the management interface is not available publically.
|
||||||
|
# It can be reached via SSH and portforwarding.
|
||||||
|
bind = ["[::]:80"];
|
||||||
|
protocol = "http";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
acme.letsencrypt = {
|
||||||
|
directory = "https://acme-v02.api.letsencrypt.org/directory"; # This setting is necessary for this block to be activated
|
||||||
|
challenge = "http-01";
|
||||||
|
contact = ["root@mathebau.de"];
|
||||||
|
domains = ["fb04184.mathematik.tu-darmstadt.de" "imap.mathebau.de" "smtp.mathebau.de"];
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
spam.header.is-spam = "Dummyheader"; # disable moving to spam which would conflict with forwarding
|
||||||
|
auth = {
|
||||||
|
# TODO check if HRZ conforms to these standards and we can validate them strictly
|
||||||
|
dkim.verify = "relaxed";
|
||||||
|
arc.verify = "relaxed";
|
||||||
|
dmarc.verify = "relaxed";
|
||||||
|
iprev.verify = "relaxed";
|
||||||
|
spf.verify.ehlo = "relaxed";
|
||||||
|
spf.verify.mail-from = "relaxed";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Forward outgoing mail to HRZ or mail VMs.
|
||||||
|
# see https://stalw.art/docs/smtp/outbound/routing/ relay host example
|
||||||
|
queue.outbound = {
|
||||||
|
next-hop = [
|
||||||
|
{
|
||||||
|
"if" = "rcpt_domain = 'lists.mathebau.de'";
|
||||||
|
"then" = "'mailman'";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"if" = "is_local_domain('', rcpt_domain)";
|
||||||
|
"then" = "'local'";
|
||||||
|
}
|
||||||
|
{"else" = "'hrz'";}
|
||||||
|
];
|
||||||
|
tls = {
|
||||||
|
# we only talk to HRZ and our own VMs anyway
|
||||||
|
mta-sts = "disable";
|
||||||
|
dane = "disable";
|
||||||
|
starttls = "optional"; # e.g. Lobon does not offer starttls
|
||||||
|
};
|
||||||
|
};
|
||||||
|
remote."hrz" = {
|
||||||
|
address = "mailout.hrz.tu-darmstadt.de";
|
||||||
|
port = 25;
|
||||||
|
protocol = "smtp";
|
||||||
|
tls.implicit = false; # Don't assume TLS on this port but use STARTTLS
|
||||||
|
};
|
||||||
|
remote."mailman" = {
|
||||||
|
address = "lobon.mathebau.de"; # must be created in DNS as a MX record because this field does not accept ip addresses.
|
||||||
|
port = 25;
|
||||||
|
protocol = "smtp";
|
||||||
|
tls.implicit = false; # Don't assume TLS on this port but use STARTTLS
|
||||||
|
};
|
||||||
|
|
||||||
|
session.rcpt = {
|
||||||
|
# In order to accept mail that we only forward
|
||||||
|
# without having to generate an account.
|
||||||
|
# Invalid addresses are filtered by DFN beforehand.
|
||||||
|
catch-all = true;
|
||||||
|
relay = [
|
||||||
|
{
|
||||||
|
"if" = "!is_empty(authenticated_as) || rcpt_domain == 'lists.mathebau.de' || starts_with(remote_ip, '192.168.0.')"; #TODO restrict trust by IP
|
||||||
|
"then" = true;
|
||||||
|
}
|
||||||
|
{"else" = false;}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
authentication.fallback-admin = {
|
||||||
|
user = "admin";
|
||||||
|
# see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH
|
||||||
|
secret = cfg.stalwartAdminHash;
|
||||||
|
};
|
||||||
|
store = {
|
||||||
|
# structured data in SQLite, blobs on filesystem
|
||||||
|
db.type = "sqlite";
|
||||||
|
db.path = "/var/lib/stalwart-mail/data/index.sqlite3";
|
||||||
|
fs.type = "fs";
|
||||||
|
fs.path = "/var/lib/stalwart-mail/data/blobs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
environment.persistence.${config.impermanence.name} = {
|
||||||
|
directories = [
|
||||||
|
"/var/lib/stalwart-mail"
|
||||||
|
];
|
||||||
|
files = ["/root/.ssh/known_hosts"]; # for the backup server bragi
|
||||||
|
};
|
||||||
|
|
||||||
|
# Backups
|
||||||
|
services.borgbackup.jobs.mail = {
|
||||||
|
paths = [
|
||||||
|
"/var/lib/stalwart-mail/data"
|
||||||
|
];
|
||||||
|
encryption.mode = "none"; # Otherwise the key is next to the backup or we have human interaction.
|
||||||
|
environment = {
|
||||||
|
BORG_RSH = "ssh -i /run/secrets/backupKey";
|
||||||
|
# “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 = "yes";
|
||||||
|
};
|
||||||
|
repo = "borg@192.168.1.11:kaluut"; # TODO for https://gitea.mathebau.de/Fachschaft/nixConfig/issues/33
|
||||||
|
startAt = "daily";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue