diff --git a/modules/nixos/mail-server/autodiscover.nix b/modules/nixos/mail-server/autodiscover.nix index 26b30d9..2d73d0a 100644 --- a/modules/nixos/mail-server/autodiscover.nix +++ b/modules/nixos/mail-server/autodiscover.nix @@ -102,8 +102,6 @@ let ); in { - networking.firewall.allowedTCPPorts = [ 80 443 ]; - services.nginx.virtualHosts = mailDiscoveryVirtualHosts // { ${config.mailserver.fqdn}.enableACME = true; }; diff --git a/modules/nixos/mail-server/default.nix b/modules/nixos/mail-server/default.nix index b4a6492..40636dc 100644 --- a/modules/nixos/mail-server/default.nix +++ b/modules/nixos/mail-server/default.nix @@ -1,7 +1,15 @@ { + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + security.acme = { + acceptTerms = true; + defaults.email = "postmaster@billenius.com"; + }; + imports = [ ./autodiscover.nix ./mail.nix + ./radicale.nix ./roundcube.nix ]; } diff --git a/modules/nixos/mail-server/mail.nix b/modules/nixos/mail-server/mail.nix index 66c8a0a..7722856 100644 --- a/modules/nixos/mail-server/mail.nix +++ b/modules/nixos/mail-server/mail.nix @@ -1,10 +1,5 @@ { ... }: { - security.acme = { - acceptTerms = true; - defaults.email = "postmaster@billenius.com"; - }; - mailserver = { enable = true; fqdn = "mail.billenius.com"; @@ -12,7 +7,7 @@ certificateScheme = "acme"; # A list of all login accounts. To create the password hashes, use - # nix-shell -p mkpasswd --run 'mkpasswd -s' + # nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' loginAccounts = { "love@billenius.com" = { hashedPasswordFile = "${../../../resources/mail-server}/love@billenius.com"; @@ -23,7 +18,10 @@ enable = true; autoIndex = true; enforced = "body"; - autoIndexExclude = [ "Trash" "\\Junk" ]; + autoIndexExclude = [ + "Trash" + "\\Junk" + ]; }; }; } diff --git a/modules/nixos/mail-server/radicale.nix b/modules/nixos/mail-server/radicale.nix new file mode 100644 index 0000000..f4b056c --- /dev/null +++ b/modules/nixos/mail-server/radicale.nix @@ -0,0 +1,78 @@ +{ + config, + lib, + pkgs, + ... +}: +let + domain = builtins.head config.mailserver.domains; + radicaleHost = "cal.${domain}"; + mailAccounts = config.mailserver.loginAccounts; + discoveryHosts = lib.unique ( + config.mailserver.domains + ++ [ + config.mailserver.fqdn + radicaleHost + ] + ); + + accountHash = + mail: account: + if account ? hashedPassword then + account.hashedPassword + else if account ? hashedPasswordFile then + lib.removeSuffix "\n" (builtins.readFile account.hashedPasswordFile) + else + throw "Radicale requires ${mail} to define hashedPassword or hashedPasswordFile"; + + htpasswd = pkgs.writeText "radicale.users" ( + lib.concatStrings ( + lib.mapAttrsToList (mail: account: "${mail}:${accountHash mail account}\n") mailAccounts + ) + ); + + mkWellKnownLocations = { + "/.well-known/caldav".return = "301 https://${radicaleHost}/"; + "/.well-known/carddav".return = "301 https://${radicaleHost}/"; + }; + + discoveryVirtualHosts = lib.listToAttrs ( + map (host: { + name = host; + value = { + enableACME = true; + forceSSL = true; + locations = mkWellKnownLocations; + }; + }) discoveryHosts + ); +in +{ + services.radicale = { + enable = true; + settings = { + auth = { + type = "htpasswd"; + htpasswd_filename = htpasswd; + htpasswd_encryption = "bcrypt"; + }; + }; + }; + + services.nginx.virtualHosts = discoveryVirtualHosts // { + ${radicaleHost} = { + enableACME = true; + forceSSL = true; + locations = mkWellKnownLocations // { + "/" = { + proxyPass = "http://127.0.0.1:5232/"; + extraConfig = '' + proxy_set_header X-Script-Name /; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass_header Authorization; + ''; + }; + }; + }; + }; +} diff --git a/modules/nixos/mail-server/roundcube.nix b/modules/nixos/mail-server/roundcube.nix index 9ec9074..86be188 100644 --- a/modules/nixos/mail-server/roundcube.nix +++ b/modules/nixos/mail-server/roundcube.nix @@ -38,9 +38,4 @@ enableACME = true; forceSSL = true; }; - - networking.firewall.allowedTCPPorts = [ - 80 - 443 - ]; }