mailnix/mailsystem/rspamd.nix

129 lines
3.7 KiB
Nix

{
config,
lib,
pkgs,
...
}:
with (import ./common.nix {inherit config;}); let
cfg = config.mailsystem;
nginxcfg = config.services.nginx;
postfixCfg = config.services.postfix;
redisCfg = config.services.redis.servers.rspamd;
rspamdCfg = config.services.rspamd;
genSystemdSocketCfg = name: socketPath: additionalUser: {
description = "rspamd ${name} worker socket";
listenStreams = [socketPath];
requiredBy = ["rspamd.service"];
socketConfig = {
Service = "rspamd.service";
SocketUser = rspamdCfg.user;
SocketMode = 0600;
ExecStartPost =
lib.mkIf (additionalUser != "")
''${pkgs.acl.bin}/bin/setfacl -m "u:${additionalUser}:rw" "${socketPath}"'';
};
};
in {
options.mailsystem.rspamd.webUi = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to enable the rspamd webui on `https://${config.mailsystem.fqdn}/rspamd`";
};
basicAuthFile = lib.mkOption {
type = lib.types.str;
description = "Path to basic auth file";
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = !cfg.rspamd.webUi.enable || cfg.rspamd.webUi.basicAuthFile != null;
message = "Setting basicAuthFile is required if rspamd's web interface is enabled";
}
];
services.rspamd = {
enable = true;
overrides = {
"classifier-bayes.conf" = {
text = ''
autolearn {
spam_threshold = 6.0 # When to learn spam (score >= threshold)
ham_threshold = -2.0 # When to learn ham (score <= threshold)
}
'';
};
"milter_headers.conf" = {
text = ''
# Add headers related to spam-detection
extended_spam_headers = true;
'';
};
"redis.conf" = {
text = ''
servers = "${redisCfg.unixSocket}";
'';
};
"worker-controller.inc" = lib.mkIf cfg.rspamd.webUi.enable {
text = ''
secure_ip = "0.0.0.0/0";
secure_ip = "::/0";
'';
};
};
workers = {
rspamd_proxy = {
bindSockets = ["systemd:rspamd-proxy.socket"];
count = 1; # Do not spawn too many processes of this type
extraConfig = ''
milter = yes; # Enable milter mode
timeout = 120s; # Needed for Milter usually
upstream "local" {
default = yes; # Self-scan upstreams are always default
self_scan = yes; # Enable self-scan
}
'';
};
controller = {
count = 1;
bindSockets = ["systemd:rspamd-controller.socket"];
extraConfig = ''
static_dir = "''${WWWDIR}"; # Serve the web UI static assets
'';
};
};
};
systemd.sockets = {
rspamd-proxy = genSystemdSocketCfg "proxy" rspamdProxySocket postfixCfg.user;
rspamd-controller = genSystemdSocketCfg "controller" rspamdControllerSocket (
lib.optionalString cfg.rspamd.webUi.enable nginxCfg.user
);
};
systemd.services.rspamd = {
requires = ["redis-rspamd.service"];
after = ["redis-rspamd.service"];
};
services.nginx = lib.mkIf cfg.rspamd.webUi.enable {
enable = true;
virtualHosts."${cfg.fqdn}" = {
forceSSL = true;
locations."/rspamd" = {
proxyPass = "http://unix:${rspamdControllerSocket}:/";
basicAuthFile = cfg.rspamd.webUi.basicAuthFile;
};
sslCertificate = lib.mkIf (cfg.certificateScheme == "selfsigned") sslCertPath;
sslCertificateKey = lib.mkIf (cfg.certificateScheme == "selfsigned") sslKeyPath;
};
};
};
}