summaryrefslogtreecommitdiff
path: root/hosts/surtr
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/surtr')
-rw-r--r--hosts/surtr/default.nix3
-rw-r--r--hosts/surtr/dns/zones/email.nights.soa8
-rw-r--r--hosts/surtr/dns/zones/li.141.soa9
-rw-r--r--hosts/surtr/dns/zones/li.kleen.soa9
-rw-r--r--hosts/surtr/dns/zones/li.synapse.soa2
-rw-r--r--hosts/surtr/dns/zones/li.yggdrasil.soa4
-rw-r--r--hosts/surtr/dns/zones/org.praseodym.soa9
-rw-r--r--hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py15
-rw-r--r--hosts/surtr/email/default.nix114
-rw-r--r--hosts/surtr/kimai.nix2
-rw-r--r--hosts/surtr/postgresql/default.nix41
-rw-r--r--hosts/surtr/tls/default.nix2
12 files changed, 132 insertions, 86 deletions
diff --git a/hosts/surtr/default.nix b/hosts/surtr/default.nix
index 9d3101c0..1c66df2b 100644
--- a/hosts/surtr/default.nix
+++ b/hosts/surtr/default.nix
@@ -22,7 +22,6 @@ with lib;
22 device = "/dev/vda"; 22 device = "/dev/vda";
23 }; 23 };
24 24
25
26 tmp.useTmpfs = true; 25 tmp.useTmpfs = true;
27 26
28 zfs.devNodes = "/dev"; # /dev/vda2 does not show up in /dev/disk/by-id 27 zfs.devNodes = "/dev"; # /dev/vda2 does not show up in /dev/disk/by-id
@@ -31,7 +30,7 @@ with lib;
31 kernelPatches = [ 30 kernelPatches = [
32 { name = "zswap-default"; 31 { name = "zswap-default";
33 patch = null; 32 patch = null;
34 extraStructuredConfig = with lib.kernel; { 33 structuredExtraConfig = with lib.kernel; {
35 ZSWAP_DEFAULT_ON = yes; 34 ZSWAP_DEFAULT_ON = yes;
36 ZSWAP_SHRINKER_DEFAULT_ON = yes; 35 ZSWAP_SHRINKER_DEFAULT_ON = yes;
37 }; 36 };
diff --git a/hosts/surtr/dns/zones/email.nights.soa b/hosts/surtr/dns/zones/email.nights.soa
index 913a88d4..34209a99 100644
--- a/hosts/surtr/dns/zones/email.nights.soa
+++ b/hosts/surtr/dns/zones/email.nights.soa
@@ -1,7 +1,7 @@
1$ORIGIN nights.email. 1$ORIGIN nights.email.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( 3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li (
4 2023013000 ; serial 4 2025060700 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -27,11 +27,7 @@ $TTL 3600
27 27
28_acme-challenge IN NS ns.yggdrasil.li. 28_acme-challenge IN NS ns.yggdrasil.li.
29 29
30ymir._domainkey IN TXT ( 30ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li.
31 "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2"
32 "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24"
33 "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ=="
34)
35 31
36_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. 32_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li.
37_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. 33_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li.
diff --git a/hosts/surtr/dns/zones/li.141.soa b/hosts/surtr/dns/zones/li.141.soa
index ab117f09..78d137bb 100644
--- a/hosts/surtr/dns/zones/li.141.soa
+++ b/hosts/surtr/dns/zones/li.141.soa
@@ -1,7 +1,7 @@
1$ORIGIN 141.li. 1$ORIGIN 141.li.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( 3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li (
4 2025020900 ; serial 4 2025060701 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -45,11 +45,8 @@ ymir IN AAAA 2a03:4000:6:d004::
45ymir IN MX 0 ymir.yggdrasil.li 45ymir IN MX 0 ymir.yggdrasil.li
46ymir IN TXT "v=spf1 redirect=ymir.yggdrasil.li" 46ymir IN TXT "v=spf1 redirect=ymir.yggdrasil.li"
47 47
48ymir._domainkey IN TXT ( 48ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li.
49 "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" 49surtr._domainkey IN CNAME surtr._domainkey.yggdrasil.li.
50 "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24"
51 "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ=="
52)
53 50
54_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. 51_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li.
55_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. 52_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li.
diff --git a/hosts/surtr/dns/zones/li.kleen.soa b/hosts/surtr/dns/zones/li.kleen.soa
index a1c7d35a..5dd3e697 100644
--- a/hosts/surtr/dns/zones/li.kleen.soa
+++ b/hosts/surtr/dns/zones/li.kleen.soa
@@ -1,7 +1,7 @@
1$ORIGIN kleen.li. 1$ORIGIN kleen.li.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( 3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li (
4 2023013000 ; serial 4 2025060701 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -27,11 +27,8 @@ $TTL 3600
27 27
28_acme-challenge IN NS ns.yggdrasil.li. 28_acme-challenge IN NS ns.yggdrasil.li.
29 29
30ymir._domainkey IN TXT ( 30ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li.
31 "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" 31surtr._domainkey IN CNAME surtr._domainkey.yggdrasil.li.
32 "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24"
33 "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ=="
34)
35 32
36_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. 33_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li.
37_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. 34_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li.
diff --git a/hosts/surtr/dns/zones/li.synapse.soa b/hosts/surtr/dns/zones/li.synapse.soa
index 086d4a85..247cf025 100644
--- a/hosts/surtr/dns/zones/li.synapse.soa
+++ b/hosts/surtr/dns/zones/li.synapse.soa
@@ -1,7 +1,7 @@
1$ORIGIN synapse.li. 1$ORIGIN synapse.li.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( 3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li (
4 2023092100 ; serial 4 2025060701 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
diff --git a/hosts/surtr/dns/zones/li.yggdrasil.soa b/hosts/surtr/dns/zones/li.yggdrasil.soa
index ebb298b4..500194ae 100644
--- a/hosts/surtr/dns/zones/li.yggdrasil.soa
+++ b/hosts/surtr/dns/zones/li.yggdrasil.soa
@@ -1,7 +1,7 @@
1$ORIGIN yggdrasil.li. 1$ORIGIN yggdrasil.li.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( 3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li (
4 2025052400 ; serial 4 2025060700 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -115,6 +115,8 @@ vidhar IN TXT "v=spf1 redirect=yggdrasil.li"
115 115
116mailout IN A 188.68.51.254 116mailout IN A 188.68.51.254
117mailout IN AAAA 2a03:4000:6:d004:: 117mailout IN AAAA 2a03:4000:6:d004::
118mailout IN A 202.61.241.61
119mailout IN AAAA 2a03:4000:52:ada::
118mailout IN MX 0 ymir.yggdrasil.li 120mailout IN MX 0 ymir.yggdrasil.li
119mailout IN TXT "v=spf1 redirect=yggdrasil.li" 121mailout IN TXT "v=spf1 redirect=yggdrasil.li"
120 122
diff --git a/hosts/surtr/dns/zones/org.praseodym.soa b/hosts/surtr/dns/zones/org.praseodym.soa
index df505b4c..2b97ca19 100644
--- a/hosts/surtr/dns/zones/org.praseodym.soa
+++ b/hosts/surtr/dns/zones/org.praseodym.soa
@@ -1,7 +1,7 @@
1$ORIGIN praseodym.org. 1$ORIGIN praseodym.org.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( 3@ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li (
4 2023013000 ; serial 4 2025060701 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -32,11 +32,8 @@ surtr IN AAAA 2a03:4000:52:ada::
32surtr IN MX 0 ymir.yggdrasil.li 32surtr IN MX 0 ymir.yggdrasil.li
33surtr IN TXT "v=spf1 redirect=yggdrasil.li" 33surtr IN TXT "v=spf1 redirect=yggdrasil.li"
34 34
35ymir._domainkey IN TXT ( 35ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li.
36 "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" 36surtr._domainkey IN CNAME surtr._domainkey.yggdrasil.li.
37 "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24"
38 "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ=="
39)
40 37
41_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. 38_xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li.
42_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. 39_xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li.
diff --git a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
index 7117eb63..7c931559 100644
--- a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
+++ b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
@@ -28,10 +28,12 @@ class PolicyHandler(StreamRequestHandler):
28 28
29 allowed = False 29 allowed = False
30 user = None 30 user = None
31 relay_eligible = False
31 if self.args['sasl_username']: 32 if self.args['sasl_username']:
32 user = self.args['sasl_username'] 33 user = self.args['sasl_username']
33 if self.args['ccert_subject']: 34 if self.args['ccert_subject']:
34 user = self.args['ccert_subject'] 35 user = self.args['ccert_subject']
36 relay_eligible = True
35 37
36 if user: 38 if user:
37 with self.server.db_pool.connection() as conn: 39 with self.server.db_pool.connection() as conn:
@@ -44,9 +46,16 @@ class PolicyHandler(StreamRequestHandler):
44 46
45 with conn.cursor() as cur: 47 with conn.cursor() as cur:
46 cur.row_factory = namedtuple_row 48 cur.row_factory = namedtuple_row
47 cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s) as "exists"', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) 49
48 if (row := cur.fetchone()) is not None: 50 if relay_eligible:
49 allowed = row.exists 51 cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "relay_access" ON "mailbox".id = "relay_access"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("domain" = %(domain)s OR %(domain)s ilike CONCAT(\'%%_.\', "domain"))) as "exists"', params = {'user': user, 'domain': domain})
52 if (row := cur.fetchone()) is not None:
53 allowed = row.exists
54
55 if not allowed:
56 cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s) as "exists"', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True)
57 if (row := cur.fetchone()) is not None:
58 allowed = row.exists
50 59
51 action = '550 5.7.0 Sender address not authorized for current user' 60 action = '550 5.7.0 Sender address not authorized for current user'
52 if allowed: 61 if allowed:
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix
index c6253e4c..a3e06ca6 100644
--- a/hosts/surtr/email/default.nix
+++ b/hosts/surtr/email/default.nix
@@ -124,19 +124,20 @@ in {
124 services.postfix = { 124 services.postfix = {
125 enable = true; 125 enable = true;
126 enableSmtp = false; 126 enableSmtp = false;
127 hostname = "surtr.yggdrasil.li";
128 recipientDelimiter = "";
129 setSendmail = true; 127 setSendmail = true;
130 postmasterAlias = ""; rootAlias = ""; extraAliases = ""; 128 postmasterAlias = ""; rootAlias = ""; extraAliases = "";
131 destination = []; 129 settings.main = {
132 sslCert = "/run/credentials/postfix.service/surtr.yggdrasil.li.pem"; 130 recpipient_delimiter = "";
133 sslKey = "/run/credentials/postfix.service/surtr.yggdrasil.li.key.pem"; 131 mydestination = [];
134 networks = []; 132 mynetworks = [];
135 config = let 133 myhostname = "surtr.yggdrasil.li";
136 relay_ccert = "texthash:${pkgs.writeText "relay_ccert" ""}"; 134
137 in {
138 smtpd_tls_security_level = "may"; 135 smtpd_tls_security_level = "may";
139 136
137 smtpd_tls_chain_files = [
138 "/run/credentials/postfix.service/surtr.yggdrasil.li.full.pem"
139 ];
140
140 #the dh params 141 #the dh params
141 smtpd_tls_dh1024_param_file = toString config.security.dhparams.params."postfix-1024".path; 142 smtpd_tls_dh1024_param_file = toString config.security.dhparams.params."postfix-1024".path;
142 smtpd_tls_dh512_param_file = toString config.security.dhparams.params."postfix-512".path; 143 smtpd_tls_dh512_param_file = toString config.security.dhparams.params."postfix-512".path;
@@ -171,21 +172,14 @@ in {
171 172
172 smtp_tls_connection_reuse = true; 173 smtp_tls_connection_reuse = true;
173 174
174 tls_server_sni_maps = ''texthash:${pkgs.writeText "sni" ( 175 tls_server_sni_maps = "inline:{${concatMapStringsSep ", " (domain: "{ ${domain} = /run/credentials/postfix.service/${removePrefix "." domain}.full.pem }") (concatMap (domain: [domain "mailin.${domain}" "mailsub.${domain}" ".${domain}"]) emailDomains)}}";
175 concatMapStringsSep "\n\n" (domain:
176 concatMapStringsSep "\n" (subdomain: "${subdomain} /run/credentials/postfix.service/${removePrefix "." subdomain}.full.pem")
177 [domain "mailin.${domain}" "mailsub.${domain}" ".${domain}"]
178 ) emailDomains
179 )}'';
180 176
181 smtp_tls_policy_maps = "socketmap:unix:${config.services.postfix-mta-sts-resolver.settings.path}:postfix"; 177 smtp_tls_policy_maps = "socketmap:unix:${config.services.postfix-mta-sts-resolver.settings.path}:postfix";
182 178
183 local_recipient_maps = ""; 179 local_recipient_maps = "";
184 180
185 # 10 GiB 181 message_size_limit = 10 * 1024 * 1024 * 1024;
186 message_size_limit = "10737418240"; 182 mailbox_size_limit = 10 * 1024 * 1024 * 1024;
187 # 10 GiB
188 mailbox_size_limit = "10737418240";
189 183
190 smtpd_delay_reject = true; 184 smtpd_delay_reject = true;
191 smtpd_helo_required = true; 185 smtpd_helo_required = true;
@@ -200,7 +194,6 @@ in {
200 dbname = email 194 dbname = email
201 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' 195 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s'
202 ''}" 196 ''}"
203 "check_ccert_access ${relay_ccert}"
204 "reject_non_fqdn_helo_hostname" 197 "reject_non_fqdn_helo_hostname"
205 "reject_invalid_helo_hostname" 198 "reject_invalid_helo_hostname"
206 "reject_unauth_destination" 199 "reject_unauth_destination"
@@ -221,7 +214,6 @@ in {
221 address_verify_sender_ttl = "30045s"; 214 address_verify_sender_ttl = "30045s";
222 215
223 smtpd_relay_restrictions = [ 216 smtpd_relay_restrictions = [
224 "check_ccert_access ${relay_ccert}"
225 "reject_unauth_destination" 217 "reject_unauth_destination"
226 ]; 218 ];
227 219
@@ -268,13 +260,26 @@ in {
268 virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; 260 virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp";
269 smtputf8_enable = false; 261 smtputf8_enable = false;
270 262
271 authorized_submit_users = "inline:{ root= postfwd= dovecot2= }"; 263 authorized_submit_users = "inline:{ root= postfwd= ${config.services.dovecot2.user}= }";
264 authorized_flush_users = "inline:{ root= }";
265 authorized_mailq_users = "inline:{ root= }";
272 266
273 postscreen_access_list = ""; 267 postscreen_access_list = "";
274 postscreen_denylist_action = "drop"; 268 postscreen_denylist_action = "drop";
275 postscreen_greet_action = "enforce"; 269 postscreen_greet_action = "enforce";
270
271 sender_bcc_maps = ''pgsql:${pkgs.writeText "sender_bcc_maps.cf" ''
272 hosts = postgresql:///email
273 dbname = email
274 query = SELECT value FROM sender_bcc_maps WHERE key = '%s'
275 ''}'';
276 recipient_bcc_maps = ''pgsql:${pkgs.writeText "recipient_bcc_maps.cf" ''
277 hosts = postgresql:///email
278 dbname = email
279 query = SELECT value FROM recipient_bcc_maps WHERE key = '%s'
280 ''}'';
276 }; 281 };
277 masterConfig = { 282 settings.master = {
278 "465" = { 283 "465" = {
279 type = "inet"; 284 type = "inet";
280 private = false; 285 private = false;
@@ -342,7 +347,10 @@ in {
342 maxproc = 0; 347 maxproc = 0;
343 args = [ 348 args = [
344 "-o" "header_checks=pcre:${pkgs.writeText "header_checks_submission" '' 349 "-o" "header_checks=pcre:${pkgs.writeText "header_checks_submission" ''
350 if /^Received: /
351 !/by surtr\.yggdrasil\.li/ STRIP
345 /^Received: from [^ ]+ \([^ ]+ [^ ]+\)\s+(.*)$/ REPLACE Received: $1 352 /^Received: from [^ ]+ \([^ ]+ [^ ]+\)\s+(.*)$/ REPLACE Received: $1
353 endif
346 ''}" 354 ''}"
347 ]; 355 ];
348 }; 356 };
@@ -390,7 +398,7 @@ in {
390 enable = true; 398 enable = true;
391 user = "postfix"; group = "postfix"; 399 user = "postfix"; group = "postfix";
392 socket = "local:/run/opendkim/opendkim.sock"; 400 socket = "local:/run/opendkim/opendkim.sock";
393 domains = ''csl:${concatStringsSep "," (["surtr.yggdrasil.li"] ++ emailDomains)}''; 401 domains = ''csl:${concatStringsSep "," (["surtr.yggdrasil.li" "yggdrasil.li" "141.li" "kleen.li" "synapse.li" "praseodym.org"] ++ emailDomains)}'';
394 selector = "surtr"; 402 selector = "surtr";
395 configFile = builtins.toFile "opendkim.conf" '' 403 configFile = builtins.toFile "opendkim.conf" ''
396 Syslog true 404 Syslog true
@@ -494,7 +502,7 @@ in {
494 }; 502 };
495 }; 503 };
496 504
497 users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user "dovecot2" ]; 505 users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user config.services.dovecot2.user ];
498 506
499 services.redis.servers.rspamd.enable = true; 507 services.redis.servers.rspamd.enable = true;
500 508
@@ -504,22 +512,22 @@ in {
504 services.dovecot2 = { 512 services.dovecot2 = {
505 enable = true; 513 enable = true;
506 enablePAM = false; 514 enablePAM = false;
507 sslServerCert = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.pem"; 515 sslServerCert = "/run/credentials/dovecot.service/surtr.yggdrasil.li.pem";
508 sslServerKey = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.key.pem"; 516 sslServerKey = "/run/credentials/dovecot.service/surtr.yggdrasil.li.key.pem";
509 sslCACert = toString ./ca/ca.crt; 517 sslCACert = toString ./ca/ca.crt;
510 mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8:INDEX=/var/lib/dovecot/indices/%u"; 518 mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8:INDEX=/var/lib/dovecot/indices/%u";
511 mailPlugins.globally.enable = [ "fts" "fts_xapian" ]; 519 mailPlugins.globally.enable = [ "fts" "fts_xapian" ];
512 protocols = [ "lmtp" "sieve" ]; 520 protocols = [ "lmtp" "sieve" ];
513 sieve = { 521 sieve = {
514 extensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation"]; 522 extensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation" "vacation-seconds" "vnd.dovecot.debug"];
515 globalExtensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation"]; 523 globalExtensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation" "vacation-seconds" "vnd.dovecot.debug"];
516 }; 524 };
517 extraConfig = let 525 extraConfig = let
518 dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" '' 526 dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" ''
519 driver = pgsql 527 driver = pgsql
520 connect = dbname=email 528 connect = dbname=email
521 password_query = SELECT (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' 529 password_query = SELECT (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, '${config.services.dovecot2.user}' as uid, '${config.services.dovecot2.group}' as gid FROM imap_user WHERE "user" = '%n'
522 user_query = SELECT "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' 530 user_query = SELECT "user", quota_rule, '${config.services.dovecot2.user}' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n'
523 iterate_query = SELECT "user" FROM imap_user 531 iterate_query = SELECT "user" FROM imap_user
524 ''; 532 '';
525 in '' 533 in ''
@@ -527,16 +535,16 @@ in {
527 535
528 mail_plugins = $mail_plugins quota 536 mail_plugins = $mail_plugins quota
529 537
530 first_valid_uid = ${toString config.users.users.dovecot2.uid} 538 first_valid_uid = ${toString config.users.users.${config.services.dovecot2.user}.uid}
531 last_valid_uid = ${toString config.users.users.dovecot2.uid} 539 last_valid_uid = ${toString config.users.users.${config.services.dovecot2.user}.uid}
532 first_valid_gid = ${toString config.users.groups.dovecot2.gid} 540 first_valid_gid = ${toString config.users.groups.${config.services.dovecot2.group}.gid}
533 last_valid_gid = ${toString config.users.groups.dovecot2.gid} 541 last_valid_gid = ${toString config.users.groups.${config.services.dovecot2.group}.gid}
534 542
535 ${concatMapStringsSep "\n\n" (domain: 543 ${concatMapStringsSep "\n\n" (domain:
536 concatMapStringsSep "\n" (subdomain: '' 544 concatMapStringsSep "\n" (subdomain: ''
537 local_name ${subdomain} { 545 local_name ${subdomain} {
538 ssl_cert = </run/credentials/dovecot2.service/${subdomain}.pem 546 ssl_cert = </run/credentials/dovecot.service/${subdomain}.pem
539 ssl_key = </run/credentials/dovecot2.service/${subdomain}.key.pem 547 ssl_key = </run/credentials/dovecot.service/${subdomain}.key.pem
540 } 548 }
541 '') ["imap.${domain}" domain] 549 '') ["imap.${domain}" domain]
542 ) emailDomains} 550 ) emailDomains}
@@ -557,10 +565,10 @@ in {
557 auth_debug = yes 565 auth_debug = yes
558 566
559 service auth { 567 service auth {
560 user = dovecot2 568 user = ${config.services.dovecot2.user}
561 } 569 }
562 service auth-worker { 570 service auth-worker {
563 user = dovecot2 571 user = ${config.services.dovecot2.user}
564 } 572 }
565 573
566 userdb { 574 userdb {
@@ -581,7 +589,7 @@ in {
581 args = ${pkgs.writeText "dovecot-sql.conf" '' 589 args = ${pkgs.writeText "dovecot-sql.conf" ''
582 driver = pgsql 590 driver = pgsql
583 connect = dbname=email 591 connect = dbname=email
584 user_query = SELECT DISTINCT ON (extension IS NULL, local IS NULL) "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM lmtp_mapping WHERE CASE WHEN extension IS NOT NULL AND local IS NOT NULL THEN ('%n' :: citext) = local || '+' || extension AND domain = ('%d' :: citext) WHEN local IS NOT NULL THEN (local = ('%n' :: citext) OR ('%n' :: citext) ILIKE local || '+%%') AND domain = ('%d' :: citext) WHEN extension IS NOT NULL THEN ('%n' :: citext) ILIKE '%%+' || extension AND domain = ('%d' :: citext) ELSE domain = ('%d' :: citext) END ORDER BY (extension IS NULL) ASC, (local IS NULL) ASC 592 user_query = SELECT DISTINCT ON (extension IS NULL, local IS NULL) "user", quota_rule, '${config.services.dovecot2.user}' as uid, '${config.services.dovecot2.group}' as gid FROM lmtp_mapping WHERE CASE WHEN extension IS NOT NULL AND local IS NOT NULL THEN ('%n' :: citext) = local || '+' || extension AND domain = ('%d' :: citext) WHEN local IS NOT NULL THEN (local = ('%n' :: citext) OR ('%n' :: citext) ILIKE local || '+%%') AND domain = ('%d' :: citext) WHEN extension IS NOT NULL THEN ('%n' :: citext) ILIKE '%%+' || extension AND domain = ('%d' :: citext) ELSE domain = ('%d' :: citext) END ORDER BY (extension IS NULL) ASC, (local IS NULL) ASC
585 ''} 593 ''}
586 594
587 skip = never 595 skip = never
@@ -651,7 +659,7 @@ in {
651 quota_status_success = DUNNO 659 quota_status_success = DUNNO
652 quota_status_nouser = DUNNO 660 quota_status_nouser = DUNNO
653 quota_grace = 10%% 661 quota_grace = 10%%
654 quota_max_mail_size = ${config.services.postfix.config.message_size_limit} 662 quota_max_mail_size = ${toString config.services.postfix.settings.main.message_size_limit}
655 quota_vsizes = yes 663 quota_vsizes = yes
656 } 664 }
657 665
@@ -704,8 +712,8 @@ in {
704 712
705 systemd.services.dovecot-fts-xapian-optimize = { 713 systemd.services.dovecot-fts-xapian-optimize = {
706 description = "Optimize dovecot indices for fts_xapian"; 714 description = "Optimize dovecot indices for fts_xapian";
707 requisite = [ "dovecot2.service" ]; 715 requisite = [ "dovecot.service" ];
708 after = [ "dovecot2.service" ]; 716 after = [ "dovecot.service" ];
709 startAt = "*-*-* 22:00:00 Europe/Berlin"; 717 startAt = "*-*-* 22:00:00 Europe/Berlin";
710 serviceConfig = { 718 serviceConfig = {
711 Type = "oneshot"; 719 Type = "oneshot";
@@ -770,28 +778,26 @@ in {
770 778
771 security.acme.rfc2136Domains = { 779 security.acme.rfc2136Domains = {
772 "surtr.yggdrasil.li" = { 780 "surtr.yggdrasil.li" = {
773 restartUnits = [ "postfix.service" "dovecot2.service" ]; 781 restartUnits = [ "postfix.service" "dovecot.service" ];
774 }; 782 };
775 } // listToAttrs (map (domain: nameValuePair "spm.${domain}" { restartUnits = ["nginx.service"]; }) spmDomains) 783 } // listToAttrs (map (domain: nameValuePair "spm.${domain}" { restartUnits = ["nginx.service"]; }) spmDomains)
776 // listToAttrs (concatMap (domain: [ 784 // listToAttrs (concatMap (domain: [
777 (nameValuePair domain { restartUnits = ["postfix.service" "dovecot2.service"]; }) 785 (nameValuePair domain { restartUnits = ["postfix.service" "dovecot.service"]; })
778 (nameValuePair "mailin.${domain}" { restartUnits = ["postfix.service"]; }) 786 (nameValuePair "mailin.${domain}" { restartUnits = ["postfix.service"]; })
779 (nameValuePair "mailsub.${domain}" { restartUnits = ["postfix.service"]; }) 787 (nameValuePair "mailsub.${domain}" { restartUnits = ["postfix.service"]; })
780 (nameValuePair "imap.${domain}" { restartUnits = ["dovecot2.service"]; }) 788 (nameValuePair "imap.${domain}" { restartUnits = ["dovecot.service"]; })
781 (nameValuePair "mta-sts.${domain}" { restartUnits = ["nginx.service"]; }) 789 (nameValuePair "mta-sts.${domain}" { restartUnits = ["nginx.service"]; })
782 ]) emailDomains); 790 ]) emailDomains);
783 791
784 systemd.services.postfix = { 792 systemd.services.postfix = {
785 serviceConfig.LoadCredential = [ 793 serviceConfig.LoadCredential = let
786 "surtr.yggdrasil.li.key.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/key.pem" 794 tlsCredential = domain: "${domain}.full.pem:${config.security.acme.certs.${domain}.directory}/full.pem";
787 "surtr.yggdrasil.li.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/fullchain.pem" 795 in [
788 ] ++ concatMap (domain: 796 (tlsCredential "surtr.yggdrasil.li")
789 map (subdomain: "${subdomain}.full.pem:${config.security.acme.certs.${subdomain}.directory}/full.pem") 797 ] ++ concatMap (domain: map tlsCredential [domain "mailin.${domain}" "mailsub.${domain}"]) emailDomains;
790 [domain "mailin.${domain}" "mailsub.${domain}"]
791 ) emailDomains;
792 }; 798 };
793 799
794 systemd.services.dovecot2 = { 800 systemd.services.dovecot = {
795 preStart = '' 801 preStart = ''
796 for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do 802 for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do
797 ${getExe' pkgs.dovecot_pigeonhole "sievec"} $f 803 ${getExe' pkgs.dovecot_pigeonhole "sievec"} $f
diff --git a/hosts/surtr/kimai.nix b/hosts/surtr/kimai.nix
index a3712bb2..454b3d80 100644
--- a/hosts/surtr/kimai.nix
+++ b/hosts/surtr/kimai.nix
@@ -47,6 +47,8 @@
47 client_max_body_size 0; 47 client_max_body_size 0;
48 proxy_request_buffering off; 48 proxy_request_buffering off;
49 proxy_buffering off; 49 proxy_buffering off;
50
51 proxy_read_timeout 300;
50 ''; 52 '';
51 }; 53 };
52 }; 54 };
diff --git a/hosts/surtr/postgresql/default.nix b/hosts/surtr/postgresql/default.nix
index 0ae29058..3786ea7c 100644
--- a/hosts/surtr/postgresql/default.nix
+++ b/hosts/surtr/postgresql/default.nix
@@ -297,6 +297,47 @@ in {
297 297
298 COMMIT; 298 COMMIT;
299 299
300 BEGIN;
301 SELECT _v.register_patch('014-relay', ARRAY['000-base'], null);
302
303 CREATE TABLE relay_access (
304 id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(),
305 mailbox uuid REFERENCES mailbox(id),
306 domain citext NOT NULL CONSTRAINT domain_non_empty CHECK (domain <> ''')
307 );
308
309 COMMIT;
310
311 BEGIN;
312 SELECT _v.register_patch('015-relay-unique', ARRAY['000-base', '014-relay'], null);
313
314 CREATE UNIQUE INDEX relay_unique ON relay_access (mailbox, domain);
315
316 COMMIT;
317
318 BEGIN;
319 SELECT _v.register_patch('015-sender_bcc', null, null);
320
321 CREATE TABLE sender_bcc_maps (
322 id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(),
323 key text NOT NULL CONSTRAINT key_not_empty CHECK (key <> '''),
324 value text NOT NULL CONSTRAINT value_not_empty CHECK (value <> '''),
325 CONSTRAINT key_unique UNIQUE (key)
326 );
327
328 COMMIT;
329
330 BEGIN;
331 SELECT _v.register_patch('016-recipient_bcc', null, null);
332
333 CREATE TABLE recipient_bcc_maps (
334 id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(),
335 key text NOT NULL CONSTRAINT key_not_empty CHECK (key <> '''),
336 value text NOT NULL CONSTRAINT value_not_empty CHECK (value <> '''),
337 CONSTRAINT recipient_bcc_maps_key_unique UNIQUE (key)
338 );
339
340 COMMIT;
300 ''} 341 ''}
301 342
302 psql etebase postgres -eXf ${pkgs.writeText "etebase.sql" '' 343 psql etebase postgres -eXf ${pkgs.writeText "etebase.sql" ''
diff --git a/hosts/surtr/tls/default.nix b/hosts/surtr/tls/default.nix
index b1c05888..b25bd2ea 100644
--- a/hosts/surtr/tls/default.nix
+++ b/hosts/surtr/tls/default.nix
@@ -41,7 +41,7 @@ in {
41 41
42 acceptTerms = true; 42 acceptTerms = true;
43 # DNS challenge is slow 43 # DNS challenge is slow
44 preliminarySelfsigned = true; 44 # preliminarySelfsigned = true;
45 defaults = { 45 defaults = {
46 email = "phikeebaogobaegh@141.li"; 46 email = "phikeebaogobaegh@141.li";
47 # We don't like NIST curves and Let's Encrypt doesn't support 47 # We don't like NIST curves and Let's Encrypt doesn't support