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=reject\"";
80 }
81 ];
82 };
83}