Self-host your own digital island
1{ pkgs, config, lib, ... }:
2
3with lib;
4let
5 cfg = config.eilean;
6 domain = config.networking.domain;
7in {
8 options.eilean.mailserver = {
9 enable = mkEnableOption "mailserver";
10 systemAccountPasswordFile = mkOption {
11 type = types.nullOr types.str;
12 default = null;
13 };
14 };
15
16 config = mkIf cfg.mailserver.enable {
17 mailserver = {
18 enable = true;
19 fqdn = "mail.${domain}";
20 domains = [ "${domain}" ];
21
22 loginAccounts = {
23 "system@${domain}" = {
24 passwordFile = cfg.mailserver.systemAccountPasswordFile;
25 aliases = [
26 (mkIf cfg.gitea.enable "git@${domain}")
27 (mkIf cfg.mastodon.enable "mastodon@${domain}")
28 ];
29 };
30 };
31
32 # Use Let's Encrypt certificates. Note that this needs to set up a stripped
33 # down nginx and opens port 80.
34 certificateScheme = "acme-nginx";
35
36 localDnsResolver = false;
37 };
38
39 services.nginx.enable = true;
40 services.nginx.virtualHosts."${config.mailserver.fqdn}".extraConfig = ''
41 return 301 $scheme://${domain}$request_uri;
42 '';
43
44 services.postfix.config = {
45 smtpd_tls_protocols =
46 mkForce "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
47 smtp_tls_protocols =
48 mkForce "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
49 smtpd_tls_mandatory_protocols =
50 mkForce "TLSv1.3, !TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
51 smtp_tls_mandatory_protocols =
52 mkForce "TLSv1.3, !TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
53 };
54
55 eilean.dns.enable = true;
56 eilean.services.dns.zones.${config.networking.domain}.records = [
57 {
58 name = "mail";
59 type = "A";
60 data = cfg.serverIpv4;
61 }
62 {
63 name = "mail";
64 type = "AAAA";
65 data = cfg.serverIpv6;
66 }
67 {
68 name = "@";
69 type = "MX";
70 data = "10 mail";
71 }
72 {
73 name = "@";
74 type = "TXT";
75 data = ''"v=spf1 a:mail.${config.networking.domain} -all"'';
76 }
77 {
78 name = "mail._domainkey";
79 ttl = 10800;
80 type = "TXT";
81 data = ''
82 "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6YmYYvoFF7VqtGcozpVQa78aaGgZdvc5ZIHqzmkKdCBEyDF2FRbCEK4s2AlC8hhc8O4mSSe3S4AzEhlRgHXbU22GBaUZ3s2WHS8JJwZvWeTjsbXQwjN/U7xpkqXPHLH9IVfOJbHlp4HQmCAXw4NaypgkkxIGK0jaZHm2j6/1izQIDAQAB"'';
83 }
84 {
85 name = "_dmarc";
86 ttl = 10800;
87 type = "TXT";
88 data = ''"v=DMARC1; p=reject"'';
89 }
90 ];
91 };
92}