# Email server configuration # Copyright (C) 2023 Nguyễn Gia Phong # # This file is part of loang configuration. # # Loang configuration is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Loang configuration is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with loang configuration. If not, see . { config, options, pkgs, ... }: let certDir = config.security.acme.certs.${hostname}.directory; domain = config.networking.domain; hostname = "tem.${domain}"; in { networking.firewall.allowedTCPPorts = [ 25 # SMTP-MTA 465 # SMTP-MSA 993 # IMAPS ]; services = { alps = { enable = true; imaps.host = hostname; theme = "alps"; }; maddy = { config = '' auth_map email_localpart '' + (builtins.replaceStrings [ '' auth.pass_table local_authdb { table sql_table { driver sqlite3 dsn credentials.db table_name passwords } } '' "imap tcp://0.0.0.0:143" "submission tcp://0.0.0.0:587" ] [ '' auth.shadow local_authdb { debug yes use_helper no } '' "imap tls://0.0.0.0:993" "submission tls://0.0.0.0:465" ] options.services.maddy.config.default); enable = true; hostname = hostname; primaryDomain = domain; tls = { loader = "file"; certificates = [{ certPath = "${certDir}/cert.pem"; keyPath = "${certDir}/key.pem"; }]; }; }; nginx.virtualHosts = { "mta-sts.${domain}" = { enableACME = true; forceSSL = true; locations."/".root = pkgs.writeTextFile { name = "mta-sts.txt"; text = '' version: STSv1 mode: enforce max_age: 604800 mx: ${hostname} ''; destination = "/.well-known/mta-sts.txt"; }; }; ${domain}.locations."^~ /.well-known/openpgpkey" = { root = with pkgs; stdenvNoCC.mkDerivation { pname = "wkd"; version = domain; src = ./wkd; nativeBuildInputs = [ gnupg ]; installPhase = let printWKDHash = "${gnupg}/libexec/gpg-wks-client --print-wkd-hash"; in '' hu=$out/.well-known/openpgpkey/hu mkdir -p $hu for key in *.asc do mb="''${key%.asc}@${domain}" hash=$(echo "$mb" | ${printWKDHash}) gpg --dearmor < "$key" > $hu/''${hash%" $mb"} done touch $out/.well-known/openpgpkey/policy ''; }; extraConfig = '' add_header Access-Control-Allow-Origin *; ''; }; ${hostname} = let alps = config.services.alps; in { enableACME = true; forceSSL = true; locations."/".proxyPass = "http://${alps.bindIP}:${toString alps.port}"; }; }; }; systemd.services.alps.unitConfig.Requires = "maddy.service"; users.extraUsers.maddy.extraGroups = [ "nginx" "shadow" ]; }