mailnix/mailsystem/default.nix
2025-02-22 19:52:13 +01:00

234 lines
7.6 KiB
Nix

{
config,
lib,
...
}: let
cfg = config.mailsystem;
in {
options.mailsystem = {
enable = lib.mkEnableOption "nixos-mailsystem";
openFirewall = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Automatically open ports in the firewall.";
};
fqdn = lib.mkOption {
type = lib.types.str;
example = "mail.example.com";
description = "Fully qualified domain name of the mail server.";
};
reverseFqdn = lib.mkOption {
type = lib.types.str;
default = cfg.fqdn;
defaultText = lib.literalMD "{option}`mailsystem.fqdn`";
example = "server.example.com";
description = ''
Fully qualified domain name used by the server to identify
with other servers.
This needs to be set to the same value of the server's IP reverse DNS.
'';
};
domains = lib.mkOption {
type = lib.types.listOf lib.types.str;
example = ["example.com"];
default = [];
description = "List of domains to be served by the mail server";
};
messageSizeLimit = lib.mkOption {
type = lib.types.int;
default = 64 * 1024 * 1024;
description = "Maximum accepted mail size";
};
vmailUID = lib.mkOption {
type = lib.types.int;
default = 5000;
description = "The unix UID of the virtual mail user.";
};
vmailUserName = lib.mkOption {
type = lib.types.str;
default = "vmail";
description = "The user name of the user that owns the directory all the mail is stored.";
};
vmailGroupName = lib.mkOption {
type = lib.types.str;
default = "vmail";
description = "The group name of the user that owns the directory all the mail is stored.";
};
mailDirectory = lib.mkOption {
type = lib.types.str;
default = "/var/vmail";
description = "Storage location for all mail.";
};
accounts = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
options = {
name = lib.mkOption {
type = lib.types.str;
example = "user1@example.com";
description = "Username";
};
hashedPasswordFile = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
example = "/run/secrets/user1-passwordhash";
description = ''
A file containing the user's hashed password. Use `mkpasswd` as follows
```
nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
```
'';
};
isSystemUser = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
System users are not allowed to change their password and are
cannot receive any mails (-> send-only). Mails sent to such an
account will be rejected.
'';
};
rejectMessage = lib.mkOption {
type = lib.types.str;
default = "This account cannot receive emails.";
description = ''
The message that will be returned to the sender when an email is
sent to a system account.
'';
};
};
config.name = lib.mkDefault name;
}));
example = {
user1 = {
hashedPassword = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/";
};
user2 = {
hashedPassword = "$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/";
};
};
description = "All available accounts for the mailsystem.";
default = {};
};
virtualAliases = lib.mkOption {
type = let
isAccount = value: builtins.elem value (builtins.attrNames cfg.accounts);
isDomain = value: !(lib.hasInfix "@" value) && (builtins.elem value cfg.domains);
account = lib.mkOptionType {
name = "Mail Account";
check = isAccount;
};
accountOrDomain = lib.mkOptionType {
name = "Mail Account or Domain";
check = value: (isAccount value) || (isDomain value);
};
in
with lib.types; attrsOf (either (nonEmptyListOf account) accountOrDomain);
example = {
"info@example.com" = "user1@example.com";
"postmaster@example.com" = "user1@example.com";
"abuse@example.com" = "user1@example.com";
"multi@example.com" = ["user1@example.com" "user2@example.com"];
"aliasdomain.com" = "domain.com";
};
description = ''
Virtual account and domain aliases. A virtual alias means, that all mail directed
at a given target are forwarded to the specified other destinations, too.
For account aliases, this means that, e.g., `"user1@example.com"` receives all mail
sent to `"info@example.com"`. In addition, `"user1@example.com"` is also able to
impersonate `"info@example.com"` when sending mails. It is also possible to create
an alias for multiple accounts. In this example, all mails for `"multi@example.com"`
will be forwarded to both
`"user1@example.com"` and `"user2@example.com"`.
For domain aliases, this means that all mails directed at an aliased domain, e.g.,
`"aliasdomain.com"` are forwarded to `"domain.com"` This also entails, that any
account or alias of `"domain.com"` receives mails directed at `"aliasdomain.com"`.
However, if `"user@domain.com"` shall be able to send mails using
`"user@aliasdomain.com"`, an explicit alias needs to be configured.
'';
default = {};
};
dkimSettings = lib.mkOption {
type = with lib.types;
attrsOf (listOf (submodule {
options = {
selector = lib.mkOption {
type = lib.types.str;
example = "mail";
description = "DKIM Selector";
};
keyFile = lib.mkOption {
type = lib.types.path;
example = "/run/secrets/dkim/example.com.mail.key";
description = ''
Path to DKIM private-key-file. A public-private-pair can be generated as follows:
```
nix-shell -p rspamd --run 'rspamadm dkim_keygen -s "selector" -t ed25519 -d example.com
nix-shell -p rspamd --run 'rspamadm dkim_keygen -s "selector" -b 2048 -d example.com
```
'';
};
};
}));
example = {
"example.com" = [
{
selector = "mail";
keyFile = "/run/secrets/dkim/example.com.mail.key";
}
];
};
description = ''
Per-domain DKIM configuration.
This option allows to optionally set one or more DKIM private keys
and their respective selectors for each domain individually.
'';
default = {};
};
certificateScheme = lib.mkOption {
type = lib.types.enum ["acme" "selfsigned"];
default = "acme";
description = ''
The scheme to use for managing TLS certificates:
1. `acme`: The server retrieves letsencrypt certificates via NixOS's acme module using nginx.
2. `selfsigned`: The server creates self-signed certificates on the fly (intended for testing).
'';
internal = true;
visible = false;
};
};
imports = [
./dovecot.nix
./kresd.nix
./nginx.nix
./postfix.nix
./redis.nix
./roundcube.nix
./rspamd.nix
./selfsigned.nix
./user.nix
];
}