diff options
Diffstat (limited to 'hosts/surtr/email')
| -rw-r--r-- | hosts/surtr/email/ca/.gitignore | 1 | ||||
| -rw-r--r-- | hosts/surtr/email/default.nix | 148 | ||||
| -rw-r--r-- | hosts/surtr/email/dovecot-pipe-bin/learn_ham.sh | 3 | ||||
| -rw-r--r-- | hosts/surtr/email/dovecot-pipe-bin/learn_spam.sh | 3 |
4 files changed, 137 insertions, 18 deletions
diff --git a/hosts/surtr/email/ca/.gitignore b/hosts/surtr/email/ca/.gitignore index bc1d3eaf..adafac92 100644 --- a/hosts/surtr/email/ca/.gitignore +++ b/hosts/surtr/email/ca/.gitignore | |||
| @@ -2,4 +2,5 @@ | |||
| 2 | *.cnf | 2 | *.cnf |
| 3 | *.old | 3 | *.old |
| 4 | *.crt | 4 | *.crt |
| 5 | *.pkcs12 | ||
| 5 | certs \ No newline at end of file | 6 | certs \ No newline at end of file |
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix index 5d366ac5..e005a3c1 100644 --- a/hosts/surtr/email/default.nix +++ b/hosts/surtr/email/default.nix | |||
| @@ -3,12 +3,22 @@ | |||
| 3 | with lib; | 3 | with lib; |
| 4 | 4 | ||
| 5 | let | 5 | let |
| 6 | compileSieve = name: text: pkgs.runCommand name {} '' | 6 | dovecotSievePipeBin = pkgs.stdenv.mkDerivation { |
| 7 | mkdir $out | 7 | name = "dovecot-sieve-pipe-bin"; |
| 8 | cp ${pkgs.writeText name '' | 8 | src = ./dovecot-pipe-bin; |
| 9 | ''} $out/${name} | 9 | buildInputs = with pkgs; [ makeWrapper coreutils bash rspamd ]; |
| 10 | ${pkgs.dovecot_pigeonhole}/bin/sievec $out/${name} | 10 | buildCommand = '' |
| 11 | ''; | 11 | mkdir -p $out/pipe/bin |
| 12 | cp $src/* $out/pipe/bin/ | ||
| 13 | chmod a+x $out/pipe/bin/* | ||
| 14 | patchShebangs $out/pipe/bin | ||
| 15 | |||
| 16 | for file in $out/pipe/bin/*; do | ||
| 17 | wrapProgram $file \ | ||
| 18 | --set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin" | ||
| 19 | done | ||
| 20 | ''; | ||
| 21 | }; | ||
| 12 | in { | 22 | in { |
| 13 | config = { | 23 | config = { |
| 14 | nixpkgs.overlays = [ | 24 | nixpkgs.overlays = [ |
| @@ -193,7 +203,21 @@ in { | |||
| 193 | services.rspamd = { | 203 | services.rspamd = { |
| 194 | enable = true; | 204 | enable = true; |
| 195 | workers = { | 205 | workers = { |
| 196 | controller = {}; | 206 | controller = { |
| 207 | type = "controller"; | ||
| 208 | count = 1; | ||
| 209 | bindSockets = [ | ||
| 210 | { mode = "0660"; | ||
| 211 | socket = "/run/rspamd/worker-controller.sock"; | ||
| 212 | owner = config.services.rspamd.user; | ||
| 213 | group = config.services.rspamd.group; | ||
| 214 | } | ||
| 215 | ]; | ||
| 216 | includes = []; | ||
| 217 | extraConfig = '' | ||
| 218 | static_dir = "''${WWWDIR}"; # Serve the web UI static assets | ||
| 219 | ''; | ||
| 220 | }; | ||
| 197 | external = { | 221 | external = { |
| 198 | type = "rspamd_proxy"; | 222 | type = "rspamd_proxy"; |
| 199 | bindSockets = [ | 223 | bindSockets = [ |
| @@ -205,6 +229,7 @@ in { | |||
| 205 | ]; | 229 | ]; |
| 206 | extraConfig = '' | 230 | extraConfig = '' |
| 207 | milter = yes; | 231 | milter = yes; |
| 232 | timeout = 120s; | ||
| 208 | 233 | ||
| 209 | upstream "local" { | 234 | upstream "local" { |
| 210 | default = yes; | 235 | default = yes; |
| @@ -269,7 +294,7 @@ in { | |||
| 269 | }; | 294 | }; |
| 270 | }; | 295 | }; |
| 271 | 296 | ||
| 272 | users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user ]; | 297 | users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user "dovecot2" ]; |
| 273 | 298 | ||
| 274 | services.redis.servers.rspamd.enable = true; | 299 | services.redis.servers.rspamd.enable = true; |
| 275 | 300 | ||
| @@ -281,8 +306,9 @@ in { | |||
| 281 | sslServerCert = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.pem"; | 306 | sslServerCert = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.pem"; |
| 282 | sslServerKey = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.key.pem"; | 307 | sslServerKey = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.key.pem"; |
| 283 | sslCACert = toString ./ca/ca.crt; | 308 | sslCACert = toString ./ca/ca.crt; |
| 284 | mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8"; | 309 | mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8:INDEX=/var/lib/dovecot/indices/%u"; |
| 285 | modules = with pkgs; [ dovecot_pigeonhole ]; | 310 | modules = with pkgs; [ dovecot_pigeonhole dovecot_fts_xapian ]; |
| 311 | mailPlugins.globally.enable = [ "fts" "fts_xapian" ]; | ||
| 286 | protocols = [ "lmtp" "sieve" ]; | 312 | protocols = [ "lmtp" "sieve" ]; |
| 287 | extraConfig = let | 313 | extraConfig = let |
| 288 | dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" '' | 314 | dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" '' |
| @@ -377,6 +403,23 @@ in { | |||
| 377 | separator = / | 403 | separator = / |
| 378 | inbox = yes | 404 | inbox = yes |
| 379 | prefix = | 405 | prefix = |
| 406 | |||
| 407 | mailbox Trash { | ||
| 408 | auto = no | ||
| 409 | special_use = \Trash | ||
| 410 | } | ||
| 411 | mailbox Drafts { | ||
| 412 | auto = no | ||
| 413 | special_use = \Drafts | ||
| 414 | } | ||
| 415 | mailbox Sent { | ||
| 416 | auto = subscribe | ||
| 417 | special_use = \Sent | ||
| 418 | } | ||
| 419 | mailbox "Sent Messages" { | ||
| 420 | auto = no | ||
| 421 | special_use = \Sent | ||
| 422 | } | ||
| 380 | } | 423 | } |
| 381 | 424 | ||
| 382 | plugin { | 425 | plugin { |
| @@ -410,20 +453,89 @@ in { | |||
| 410 | 453 | ||
| 411 | plugin { | 454 | plugin { |
| 412 | sieve_plugins = sieve_imapsieve | 455 | sieve_plugins = sieve_imapsieve |
| 413 | 456 | sieve = file:~/sieve;active=~/dovecot.sieve | |
| 414 | sieve_redirect_envelope_from = orig_recipient | 457 | sieve_redirect_envelope_from = orig_recipient |
| 415 | sieve_before = /etc/dovecot/sieve_before.d | 458 | sieve_before = /etc/dovecot/sieve_before.d |
| 459 | |||
| 460 | sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment | ||
| 461 | sieve_pipe_bin_dir = ${dovecotSievePipeBin}/pipe/bin | ||
| 462 | |||
| 463 | imapsieve_mailbox1_name = * | ||
| 464 | imapsieve_mailbox1_causes = FLAG | ||
| 465 | imapsieve_mailbox1_before = /etc/dovecot/sieve_flag.d | ||
| 466 | } | ||
| 467 | |||
| 468 | plugin { | ||
| 469 | plugin = fts fts_xapian | ||
| 470 | fts = xapian | ||
| 471 | fts_xapian = partial=2 full=20 attachments=1 verbose=1 | ||
| 472 | |||
| 473 | fts_autoindex = yes | ||
| 474 | |||
| 475 | fts_enforced = no | ||
| 476 | } | ||
| 477 | |||
| 478 | service indexer-worker { | ||
| 479 | vsz_limit = ${toString (1024 * 1024 * 1024)} | ||
| 416 | } | 480 | } |
| 417 | ''; | 481 | ''; |
| 418 | }; | 482 | }; |
| 419 | 483 | ||
| 420 | environment.etc."dovecot/sieve_before.d/tag-junk.sieve".text = '' | 484 | systemd.services.dovecot-fts-xapian-optimize = { |
| 421 | require ["imap4flags"]; | 485 | description = "Optimize dovecot indices for fts_xapian"; |
| 486 | requisite = [ "dovecot2.service" ]; | ||
| 487 | after = [ "dovecot2.service" ]; | ||
| 488 | startAt = "*-*-* 22:00:00 Europe/Berlin"; | ||
| 489 | serviceConfig = { | ||
| 490 | Type = "oneshot"; | ||
| 491 | ExecStart = "${pkgs.dovecot}/bin/doveadm fts optimize -A"; | ||
| 492 | PrivateDevices = true; | ||
| 493 | PrivateNetwork = true; | ||
| 494 | ProtectKernelTunables = true; | ||
| 495 | ProtectKernelModules = true; | ||
| 496 | ProtectControlGroups = true; | ||
| 497 | ProtectHome = true; | ||
| 498 | ProtectSystem = true; | ||
| 499 | PrivateTmp = true; | ||
| 500 | }; | ||
| 501 | }; | ||
| 502 | systemd.timers.dovecot-fts-xapian-optimize = { | ||
| 503 | timerConfig = { | ||
| 504 | RandomizedDelaySec = 4 * 3600; | ||
| 505 | }; | ||
| 506 | }; | ||
| 507 | |||
| 508 | environment.etc = { | ||
| 509 | "dovecot/sieve_before.d/tag-junk.sieve".text = '' | ||
| 510 | require ["imap4flags"]; | ||
| 422 | 511 | ||
| 423 | if header :contains "X-Spam-Flag" "YES" { | 512 | if header :contains "X-Spam-Flag" "YES" { |
| 424 | addflag ["\\Junk"]; | 513 | addflag ["\\Junk"]; |
| 425 | } | 514 | } |
| 426 | ''; | 515 | ''; |
| 516 | |||
| 517 | "dovecot/sieve_flag.d/learn-junk.sieve".text = '' | ||
| 518 | require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables", "imap4flags"]; | ||
| 519 | |||
| 520 | if environment :matches "imap.user" "*" { | ||
| 521 | set "username" "''${1}"; | ||
| 522 | } | ||
| 523 | |||
| 524 | if environment :contains "imap.changedflags" "\\Junk" { | ||
| 525 | if hasflag "\\Junk" { | ||
| 526 | pipe :copy "learn_spam.sh" [ "''${username}" ]; | ||
| 527 | } else { | ||
| 528 | if environment :matches "imap.mailbox" "*" { | ||
| 529 | set "mailbox" "''${1}"; | ||
| 530 | } | ||
| 531 | |||
| 532 | if not string "''${mailbox}" "Trash" { | ||
| 533 | pipe :copy "learn_ham.sh" [ "''${username}" ]; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | } | ||
| 537 | ''; | ||
| 538 | }; | ||
| 427 | 539 | ||
| 428 | security.dhparams = { | 540 | security.dhparams = { |
| 429 | params = { | 541 | params = { |
| @@ -452,7 +564,7 @@ in { | |||
| 452 | 564 | ||
| 453 | systemd.services.dovecot2 = { | 565 | systemd.services.dovecot2 = { |
| 454 | preStart = '' | 566 | preStart = '' |
| 455 | for f in /etc/dovecot/sieve_before.d/*.sieve; do | 567 | for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do |
| 456 | ${pkgs.dovecot_pigeonhole}/bin/sievec $f | 568 | ${pkgs.dovecot_pigeonhole}/bin/sievec $f |
| 457 | done | 569 | done |
| 458 | ''; | 570 | ''; |
diff --git a/hosts/surtr/email/dovecot-pipe-bin/learn_ham.sh b/hosts/surtr/email/dovecot-pipe-bin/learn_ham.sh new file mode 100644 index 00000000..6e0bb076 --- /dev/null +++ b/hosts/surtr/email/dovecot-pipe-bin/learn_ham.sh | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/bash -e | ||
| 2 | |||
| 3 | exec rspamc -h /run/rspamd/worker-controller.sock learn_ham | ||
diff --git a/hosts/surtr/email/dovecot-pipe-bin/learn_spam.sh b/hosts/surtr/email/dovecot-pipe-bin/learn_spam.sh new file mode 100644 index 00000000..91dbd6c1 --- /dev/null +++ b/hosts/surtr/email/dovecot-pipe-bin/learn_spam.sh | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/bash -e | ||
| 2 | |||
| 3 | exec rspamc -h /run/rspamd/worker-controller.sock learn_spam | ||
