From 5ef38dbc022607d6b5135eacc23a3b6fc13cc837 Mon Sep 17 00:00:00 2001 From: Kyren223 Date: Wed, 16 Jul 2025 15:19:04 +0300 Subject: [PATCH] Added stalwart mail (basic) --- host/configuration.nix | 2 + nixosModules/stalwart.nix | 123 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 nixosModules/stalwart.nix diff --git a/host/configuration.nix b/host/configuration.nix index 3a44554..c1fc91d 100644 --- a/host/configuration.nix +++ b/host/configuration.nix @@ -14,6 +14,7 @@ ./../nixosModules/eko.nix ./../nixosModules/grafana.nix ./../nixosModules/loki.nix + ./../nixosModules/stalwart.nix ]; boot.loader.grub = { @@ -57,6 +58,7 @@ nextcloud.enable = false; wakapi.enable = true; eko.enable = true; + stalwart.enable = true; # Automatically pull this config from git autoUpdate.enable = true; diff --git a/nixosModules/stalwart.nix b/nixosModules/stalwart.nix new file mode 100644 index 0000000..02585ad --- /dev/null +++ b/nixosModules/stalwart.nix @@ -0,0 +1,123 @@ +{ pkgs, lib, config, ... }: { + + imports = [ + ./acme.nix + ]; + + options = { + stalwart.enable = lib.mkEnableOption "enables stalwart"; + }; + + config = lib.mkIf config.stalwart.enable { + + # Open http and https ports to the public + networking.firewall.allowedTCPPorts = [ 443 ]; + + # Make sure acme module is active for the "kyren.codes" ssl cert + acme.enable = true; + + environment.etc = { + "stalwart/mail-pw1".text = "foobar"; + "stalwart/mail-pw2".text = "foobar"; + "stalwart/admin-pw".text = "foobar"; + "stalwart/acme-secret".text = "secret123"; + }; + + services.caddy = { + enable = true; + virtualHosts = { + "webadmin.kyren.codes" = { + extraConfig = '' + reverse_proxy http://127.0.0.1:8080 + ''; + serverAliases = [ + "mta-sts.kyren.codes" + "autoconfig.kyren.codes" + "autodiscover.kyren.codes" + "mail.kyren.codes" + ]; + }; + }; + }; + + services.stalwart-mail = { + enable = true; + package = pkgs.stalwart-mail; + openFirewall = true; + settings = { + server = { + hostname = "mx1.kyren.codes"; + tls = { + enable = true; + implicit = true; + }; + listener = { + smtp = { + protocol = "smtp"; + bind = "[::]:25"; + }; + submissions = { + bind = "[::]:465"; + protocol = "smtp"; + }; + imaps = { + bind = "[::]:993"; + protocol = "imap"; + }; + jmap = { + bind = "[::]:8080"; + url = "https://mail.kyren.codes"; + protocol = "jmap"; + }; + management = { + bind = [ "127.0.0.1:8080" ]; + protocol = "http"; + }; + }; + }; + lookup.default = { + hostname = "mx1.kyren.codes"; + domain = "kyren.codes"; + }; + acme."letsencrypt" = { + directory = "https://acme-v02.api.letsencrypt.org/directory"; + challenge = "dns-01"; + contact = "user1@kyren.codes"; + domains = [ "kyren.codes" "mx1.kyren.codes" ]; + provider = "cloudflare"; + secret = "%{file:/etc/stalwart/acme-secret}%"; + }; + session.auth = { + mechanisms = "[plain]"; + directory = "'in-memory'"; + }; + storage.directory = "in-memory"; + session.rcpt.directory = "'in-memory'"; + queue.outbound.next-hop = "'local'"; + directory."imap".lookup.domains = [ "kyren.codes" ]; + directory."in-memory" = { + type = "memory"; + principals = [ + { + class = "individual"; + name = "User 1"; + secret = "%{file:/etc/stalwart/mail-pw1}%"; + email = [ "user1@kyren.codes" ]; + } + { + class = "individual"; + name = "postmaster"; + secret = "%{file:/etc/stalwart/mail-pw1}%"; + email = [ "postmaster@kyren.codes" ]; + } + ]; + }; + authentication.fallback-admin = { + user = "admin"; + secret = "%{file:/etc/stalwart/admin-pw}%"; + }; + }; + }; + + }; +}