server-configs/machines/gerd/services/stalwart/stalwart.nix

147 lines
4.5 KiB
Nix

{ config, lib, pkgs, ... }:
let
svc_domain = "mail.${config.mine.shared.settings.domain}";
svc_domain_smtp = "smtp.${config.mine.shared.settings.domain}";
svc_domain_imap = "imap.${config.mine.shared.settings.domain}";
ports = {
smtp = 25;
submissions = 465;
imaptls = 993;
http_management = 7377;
};
# place data into own zfs dataset
stateDir = config.mine.zfsMounts."rpool/safe/svcs/stalwart";
# user/group
stalwart_user = config.users.users.stalwart-mail.name;
stalwart_group = config.users.groups.stalwart-mail.name;
certLocation = config.security.acme.certs."${svc_domain}".directory;
in {
services.stalwart-mail = {
enable = true;
openFirewall = true;
package = pkgs.stalwart-mail.overrideAttrs (old: {
patches = old.patches ++ [
./patches/stalwart-cli-dns-records.patch
];
});
settings = {
lookup.default.hostname = svc_domain;
store.db.path = "${stateDir}/db";
directory.ldap = {
type = "ldap";
url = config.mine.shared.settings.ldap.url;
base-dn = config.mine.shared.settings.ldap.dc;
tls.enable = false;
bind = {
dn = config.mine.shared.settings.ldap.bind_dn;
secret = "%{file:${config.age.secrets.lldap-bind-user-pass.path}}%";
auth = {
enable = true;
dn = "cn=?,${config.mine.shared.settings.ldap.search_base}";
};
};
filter = let
_mkFilter = attrs: ph: config.mine.shared.lib.ldap.mkFilter (lconfig: llib:
llib.mkAnd [
(llib.mkGroup lconfig.groups.member)
(llib.mkOr (lib.forEach attrs (v: llib.mkSearch v ph)))
]
);
attrs = config.mine.shared.settings.ldap.attr // { emailAlias = "mailAlias"; emailList = "mailList"; };
in {
name = _mkFilter [ attrs.uid ] "?";
email = _mkFilter [ attrs.email attrs.emailAlias attrs.emailList ] "?";
verify = _mkFilter [ attrs.email attrs.emailAlias ] "*?*";
expand = _mkFilter [ attrs.emailList ] "?";
domains = _mkFilter [ attrs.email attrs.emailAlias ] "*@?";
};
attributes = {
name = "uid";
class = "objectClass";
description = "givenName";
secret = "uid";
groups = "memberOf";
email = "mail";
# email-alias = "mailAlias";
# quota = "diskQuota";
};
};
storage.directory = "ldap";
# listeners
server.listener = {
smtp = { bind = [ "[::]:${builtins.toString ports.smtp}"]; protocol = "smtp"; };
submissions = { bind = [ "[::]:${builtins.toString ports.submissions}"]; protocol = "smtp"; tls.implicit = true; };
imaptls = { bind = [ "[::]:${builtins.toString ports.imaptls}"]; protocol = "imap"; tls.implicit = true; };
management = { bind = [ "127.0.0.1:${builtins.toString ports.http_management}" ]; protocol = "http"; };
};
certificate.domain = {
cert = "%{file:${certLocation + "/cert.pem"}}%";
private-key = "%{file:${certLocation + "/key.pem"}}%";
};
server.tls = {
certificate = "domain";
enable = true;
implicit = true;
};
# authentication
authentication.fallback-admin = {
user = "admin";
secret = "%{file:${config.age.secrets.stalwart-admin-fallback-password.path}}%";
};
};
};
# setup so that stalwart can access and write to the directory
systemd.services.stalwart-mail.serviceConfig.ReadWritePaths = [ stateDir ];
systemd.tmpfiles.rules = [
"Z ${stateDir} 0700 ${stalwart_user} ${stalwart_group} -"
];
# setup certs
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
serverAliases = [ svc_domain_smtp svc_domain_imap ];
root = pkgs.writeTextDir "index.html" "Nothing.";
};
# need to change group to stalwart-mail for cert + add nginx to stalwart-mail group to do HTTP ACME
users.users.nginx.extraGroups = [ stalwart_group ];
security.acme.certs."${svc_domain}".group = stalwart_group;
# setup secrets for stalwart
# setup access to ldap bind user credential
users.groups.secrets-lldap-bind-user-pass.members = [ stalwart_user ];
age.secrets.stalwart-admin-fallback-password.owner = stalwart_user;
mine.shared.settings.mail = {
domain = svc_domain;
domain_smtp = svc_domain_smtp;
domain_imap = svc_domain_imap;
ports = ports;
};
}