1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
{ inputs, pkgs, config, ... }:
let
mailAutoConfig = ''
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
<emailProvider id="ctu.cx">
<domain>ctu.cx</domain>
<displayName>${config.networking.fqdn}</displayName>
<displayShortName>${config.networking.domain}</displayShortName>
<incomingServer type="imap">
<hostname>${config.networking.fqdn}</hostname>
<port>993</port>
<socketType>SSL</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</incomingServer>
<outgoingServer type="smtp">
<hostname>${config.networking.fqdn}</hostname>
<port>465</port>
<socketType>SSL</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</outgoingServer>
</emailProvider>
</clientConfig>
'';
in {
imports = [
inputs.simple-nixos-mailserver.nixosModule
];
age.secrets.restic-mail.file = ./. + "/../../../secrets/${config.networking.hostName}/restic/mail.age";
age.secrets.mail-password-katja.file = ./. + "/../../../secrets/${config.networking.hostName}/mail/password-katja-ctu.cx.age";
age.secrets.mail-password-gts.file = ./. + "/../../../secrets/${config.networking.hostName}/mail/password-gts-ctu.cx.age";
age.secrets.mail-password-gts-zug.file = ./. + "/../../../secrets/${config.networking.hostName}/mail/password-gts-zuggeschmack.de.age";
age.secrets.mail-password-info-zug.file = ./. + "/../../../secrets/${config.networking.hostName}/mail/password-info-zuggeschmack.de.age";
age.secrets.mail-password-vaultwarden.file = ./. + "/../../../secrets/${config.networking.hostName}/mail/password-vaultwarden-ctu.cx.age";
dns.zones = with pkgs.dns.lib.combinators; let
TXT = [ "v=spf1 a mx ip4:${config.networking.primaryIP4} +ip6:${config.networking.primaryIP} ~all" ];
DMARC = "v=DMARC1; p=none";
MX = with mx; [ (mx 10 "${config.networking.fqdn}.") ];
in {
"ctu.cx" = {
inherit MX TXT;
SRV = [
{ proto = "tcp"; service = "imaps"; priority = 0; weight = 1; port = 993; target = "${config.networking.fqdn}."; }
{ proto = "tcp"; service = "imap"; priority = 0; weight = 1; port = 143; target = "${config.networking.fqdn}."; }
{ proto = "tcp"; service = "submission"; priority = 0; weight = 1; port = 587; target = "${config.networking.fqdn}."; }
];
subdomains = {
autoconfig.CNAME = [ config.networking.hostName ];
_dmarc.TXT = [ DMARC ];
"mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKryfX99NkcU5Xe4AmG+kO/sfuYSXk5RqJhzxS4uMqERE8UszgEGdteXcD8pqON2MfDmA3G6cA+Oa+N4tIWdIYNwTISVXXMGdHvjFIsVUEW0turM104tXESELaPRntkCvDBk/yOgsBDRZQHSx5MdGwpzeRC8TLdCbalh3W0jp5PQIDAQAB" ];
};
};
"ctucx.de" = {
inherit MX TXT;
subdomains = {
_dmarc.TXT = [ DMARC ];
"mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5fu690bKYCZLPAFfQQK+nl+aAmtetaWBKCWzGj6pt7HjpFjystgtgnQ6+DZLFXWUp8GRfMEycySB5kQULtYtSMUmx0gQBnTTLsRj+e55/CYUllLV6YXb5uca7LuVhlWPpH3sCr6TvC2VFWe4t0UC3uIXhYPrCm6p8OE7g+TdHHwIDAQAB" ];
};
};
"zuggeschmack.de" = {
inherit MX TXT;
subdomains = {
_dmarc.TXT = [ DMARC ];
"mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDf0PX32wWq068cThCnAaX1RJMBiMo6pGfT/VOp9/IzXWmNO2aSyWEFp5lVwYFJnlGX1Sg1uvThICVDiscOqG5jBUAc0gl3SPEBFJ0cqLl7CYhD3Nkvgc8+7zn4huKvFGYXRSDqQm+AL4SSEjZ8hF+N9bGxt0bYu2WlGwZX8mTptwIDAQAB" ];
};
};
"thein.ovh" = {
inherit MX TXT;
subdomains = {
_dmarc.TXT = [ DMARC ];
"mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8oumqNkHboF/S4dnKue+hEC3V226ToMmL/fmXqbAhsW88m+jUuLgZE8Nl7kc/lzD9yY7JmCXcWFzoLJWE8xusfmT1yMOW9sQmee7g0tHsm1fVqFMUetmC4+QuqAdvjIGU5QndjdWHP/gssIoLPT7lCNUL4/lkaPmFiiDyvaMpkQIDAQAB" ];
};
};
"flauschehorn.sexy" = {
inherit MX TXT;
subdomains = {
_dmarc.TXT = [ DMARC ];
"mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvEPR8068KtlsiWiexSPWqagKmd07ggGvDcYICzOvhxVB0MDrn+/VYIXEbVX0Y9z60oT1ynjkhFjDWEofk11EoXwrg7xjkqZuszDrhdYqUnoLrzlugmnK4jXO3cAD0qeblX0rDmu30cmPP1Aj21tLTU6loYpORY+y4VaVfwtHswwIDAQAB" ];
};
};
};
security.acme.certs."${config.networking.fqdn}".reloadServices = [
"postfix.service"
"dovecot2.service"
];
services.nginx = {
enable = true;
virtualHosts = {
"${config.networking.fqdn}" = {
enableACME = true;
forceSSL = true;
};
"autoconfig.ctu.cx" = {
enableACME = true;
forceSSL = true;
locations."= /mail/config-v1.1.xml".return = "200 '${mailAutoConfig}'";
};
};
};
services.redis.servers.rspamd.bind = "::1";
services.dovecot2.sieve.extensions = [
"editheader"
];
mailserver = {
enable = true;
fqdn = config.networking.fqdn;
openFirewall = true;
localDnsResolver = false;
virusScanning = false;
redis.address = "[::1]";
certificateScheme = "manual";
certificateFile = "${config.security.acme.certs.${config.networking.fqdn}.directory}/fullchain.pem";
keyFile = "${config.security.acme.certs.${config.networking.fqdn}.directory}/key.pem";
enableManageSieve = true;
enableSubmission = true;
enableSubmissionSsl = true;
enableImap = true;
enableImapSsl = true;
enablePop3 = false;
enablePop3Ssl = false;
mailDirectory = "/var/lib/mailboxes";
sieveDirectory = "/var/lib/sieve";
dkimKeyDirectory = "/var/lib/dkimKeys";
domains = [
"ctu.cx"
"ctucx.de"
"thein.ovh"
"flauschehorn.sexy"
"zuggeschmack.de"
];
loginAccounts = {
"katja@ctu.cx" = {
hashedPasswordFile = config.age.secrets.mail-password-katja.path;
sieveScript = builtins.readFile ./rules-katja.sieve;
aliases = [
"@ctu.cx"
"@ctucx.de"
"@thein.ovh"
];
};
"vaultwarden@ctu.cx" = {
hashedPasswordFile = config.age.secrets.mail-password-vaultwarden.path;
};
"gts@ctu.cx" = {
hashedPasswordFile = config.age.secrets.mail-password-gts.path;
};
"gts@zuggeschmack.de" = {
hashedPasswordFile = config.age.secrets.mail-password-gts-zug.path;
};
"info@zuggeschmack.de" = {
hashedPasswordFile = config.age.secrets.mail-password-info-zug.path;
aliases = [
"@zuggeschmack.de"
];
};
};
};
restic-backups.mail = {
passwordFile = config.age.secrets.restic-mail.path;
paths = [
"/var/lib/mailboxes"
"/var/lib/dkimKeys"
"/var/lib/sieve"
];
};
}