Self-host your own digital island
1{ config, lib, ... }: 2 3let 4 cfg = config.eilean; 5 domain = config.networking.domain; 6in { 7 options.eilean.mailserver.enable = lib.mkEnableOption "mailserver"; 8 9 config = lib.mkIf cfg.mailserver.enable { 10 mailserver = { 11 enable = true; 12 fqdn = "mail.${domain}"; 13 domains = [ "${domain}" ]; 14 15 # A list of all login accounts. To create the password hashes, use 16 # nix run nixpkgs.apacheHttpd -c htpasswd -nbB "" "super secret password" | cut -d: -f2 17 loginAccounts = { 18 "${cfg.username}@${domain}" = { 19 hashedPasswordFile = "${config.eilean.secretsDir}/email-pswd"; 20 aliases = [ 21 "dns@${domain}" 22 "postmaster@${domain}" 23 ]; 24 }; 25 "misc@${domain}" = { 26 hashedPasswordFile = "${config.eilean.secretsDir}/email-pswd"; 27 aliases = [ 28 "git@${domain}" 29 "mastodon@${domain}" 30 ]; 31 catchAll = [ "${domain}" ]; 32 }; 33 }; 34 35 # Use Let's Encrypt certificates. Note that this needs to set up a stripped 36 # down nginx and opens port 80. 37 certificateScheme = 3; 38 39 localDnsResolver = false; 40 }; 41 42 services.nginx.enable = true; 43 services.nginx.virtualHosts."${config.mailserver.fqdn}".extraConfig = '' 44 return 301 $scheme://${domain}$request_uri; 45 ''; 46 47 eilean.dns.enable = true; 48 eilean.services.dns.zones.${config.networking.domain}.records = [ 49 { 50 name = "mail"; 51 type = "A"; 52 data = cfg.serverIpv4; 53 } 54 { 55 name = "mail"; 56 type = "AAAA"; 57 data = cfg.serverIpv6; 58 } 59 { 60 name = "@"; 61 type = "MX"; 62 data = "10 mail"; 63 } 64 { 65 name = "@"; 66 type = "TXT"; 67 data = "\"v=spf1 a:mail.${config.networking.domain} -all\""; 68 } 69 { 70 name = "mail._domainkey"; 71 ttl = 10800; 72 type = "TXT"; 73 data = "\"v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6YmYYvoFF7VqtGcozpVQa78aaGgZdvc5ZIHqzmkKdCBEyDF2FRbCEK4s2AlC8hhc8O4mSSe3S4AzEhlRgHXbU22GBaUZ3s2WHS8JJwZvWeTjsbXQwjN/U7xpkqXPHLH9IVfOJbHlp4HQmCAXw4NaypgkkxIGK0jaZHm2j6/1izQIDAQAB\""; 74 } 75 { 76 name = "_dmarc"; 77 ttl = 10800; 78 type = "TXT"; 79 data = "\"v=DMARC1; p=none\""; 80 } 81 ]; 82 }; 83}