My Nix Configuration
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

[flake] stop hosting my own mail

Now using purelymail

dish f17d6751 ca5551e1

+29 -826
+9 -8
homeModules/programs/ssh/default.nix
··· 30 30 "PreferredAuthentications" = "publickey"; 31 31 }; 32 32 }; 33 - "prefect" = { 33 + "prefect-old" = { 34 34 hostname = "100.93.63.54"; 35 35 user = "thehedgehog"; 36 36 port = 22; ··· 39 39 "PreferredAuthentications" = "publickey"; 40 40 }; 41 41 }; 42 - "botw" = { 43 - hostname = "bandit.labs.overthewire.org"; 44 - port = 2220; 45 - sendEnv = [ 46 - "WECHALLUSER" 47 - "WECHALLTOKEN" 48 - ]; 42 + "prefect" = { 43 + hostname = "100.107.252.71"; 44 + user = "thehedgehog"; 45 + port = 22; 46 + extraOptions = { 47 + "IdentitiesOnly" = "no"; 48 + "PreferredAuthentications" = "publickey"; 49 + }; 49 50 }; 50 51 }; 51 52 extraOptionOverrides = {
+1 -1
hosts/marvin/services/git.nix
··· 54 54 ENABLED = true; 55 55 FROM = "dishNet Git <git@pyrox.dev>"; 56 56 PROTOCOL = "smtps"; 57 - SMTP_ADDR = "mail.pyrox.dev"; 57 + SMTP_ADDR = "smtp.purelymail.com"; 58 58 SMTP_PORT = 465; 59 59 USER = "git@pyrox.dev"; 60 60 };
+1 -1
hosts/marvin/services/grafana.nix
··· 58 58 enabled = true; 59 59 user = "grafana@pyrox.dev"; 60 60 from_address = "grafana@pyrox.dev"; 61 - host = "mail.pyrox.dev:465"; 61 + host = "smtp.purelymail.com:465"; 62 62 password = "$__file{${config.age.secrets.grafana-smtp-password.path}}"; 63 63 }; 64 64 };
+2 -2
hosts/marvin/services/immich-config.json
··· 172 172 "from": "dishNet Photos <immich@pyrox.dev>", 173 173 "replyTo": "", 174 174 "transport": { 175 - "host": "mail.pyrox.dev", 175 + "host": "smtp.purelymail.com", 176 176 "ignoreCert": false, 177 - "port": 25, 177 + "port": 465, 178 178 "secure": true, 179 179 "username": "immich@pyrox.dev" 180 180 }
+1 -1
hosts/marvin/services/paperless.nix
··· 19 19 settings = { 20 20 PAPERLESS_EMAIL_TASK_CRON = "0 */4 * * *"; 21 21 PAPERLESS_TIME_ZONE = "America/New_York"; 22 - PAPERLESS_EMAIL_HOST = "mail.pyrox.dev"; 22 + PAPERLESS_EMAIL_HOST = "smtp.purelymail.com"; 23 23 PAPERLESS_EMAIL_PORT = 465; 24 24 PAPERLESS_EMAIL_HOST_USER = "paperless@pyrox.dev"; 25 25 PAPERLESS_EMAIL_FROM = "dish Docs<paperless@pyrox.dev>";
+1 -1
hosts/marvin/services/pocket-id.nix
··· 23 23 EMAILS_VERIFIED = true; 24 24 ALLOW_OWN_ACCOUNT_EDIT = true; 25 25 DISABLE_ANIMATIONS = true; 26 - SMTP_HOST = "mail.pyrox.dev"; 26 + SMTP_HOST = "smtp.purelymail.com"; 27 27 SMTP_PORT = 465; 28 28 SMTP_FROM = "auth@pyrox.dev"; 29 29 SMTP_USER = "auth@pyrox.dev";
+1 -1
hosts/marvin/services/vaultwarden.nix
··· 66 66 smtpUsername = "vault@pyrox.dev"; 67 67 smtpSecurity = "force_tls"; 68 68 smtpPort = 465; 69 - smtpHost = "mail.pyrox.dev"; 69 + smtpHost = "smtp.purelymail.com"; 70 70 smtpAuthMechanism = "Login"; 71 71 smtpTimeout = 20; 72 72 smtpEmbedImages = true;
-1
hosts/prefect/default.nix
··· 18 18 ./services/acme.nix 19 19 ./services/caddy.nix 20 20 ./services/fail2ban.nix 21 - ./services/mailserver 22 21 ./services/prometheus.nix 23 22 ./services/secrets.nix 24 23 ./services/tailscale.nix
-10
hosts/prefect/services/acme.nix
··· 2 2 { 3 3 security.acme = { 4 4 acceptTerms = true; 5 - certs."pyroxdev-mail" = { 6 - domain = "mail.pyrox.dev"; 7 - extraDomainNames = [ 8 - "dav.pyrox.dev" 9 - "mta-sts.pyrox.dev" 10 - "autoconfig.pyrox.dev" 11 - "autodiscover.pyrox.dev" 12 - ]; 13 - reloadServices = [ "stalwart" ]; 14 - }; 15 5 defaults = { 16 6 # LE Production Server 17 7 server = "https://acme-v02.api.letsencrypt.org/directory";
-100
hosts/prefect/services/caddy.nix
··· 21 21 }; 22 22 email = "pyrox@pyrox.dev"; 23 23 virtualHosts = { 24 - "mail2.pyrox.dev" = { }; 25 24 # Redirect old domains -> pyrox.dev 26 25 "blog.pyrox.dev" = { 27 26 serverAliases = [ ··· 248 247 reverse_proxy ${marvin}:${toString pns.pinchflat.port} 249 248 ''; 250 249 }; 251 - 252 - "http://mail.pyrox.dev" = { 253 - serverAliases = [ 254 - "http://mail2.pyrox.dev" 255 - "http://mta-sts.pyrox.dev" 256 - "http://autodiscover.pyrox.dev" 257 - "http://autoconfig.pyrox.dev" 258 - "http://dav.pyrox.dev" 259 - ]; 260 - extraConfig = '' 261 - reverse_proxy 127.0.0.1:${toString mail.intHTTP} { 262 - transport http { 263 - proxy_protocol v2 264 - } 265 - } 266 - 267 - ''; 268 - }; 269 250 }; 270 251 # Mail Config 271 252 globalConfig = '' ··· 273 254 ref refs/heads/pages 274 255 refresh_period 10m 275 256 } 276 - servers :80 { 277 - listener_wrappers { 278 - layer4 { 279 - @maildomains http host mail.pyrox.dev mail2.pyrox.dev mta-sts.pyrox.dev autoconfig.pyrox.dev autodiscover.pyrox.dev dav.pyrox.dev 280 - route @maildomains { 281 - subroute { 282 - @a http 283 - route @a { 284 - proxy { 285 - proxy_protocol v2 286 - upstream 127.0.0.1:${toString mail.intHTTP} 287 - } 288 - } 289 - } 290 - } 291 - } 292 - http_redirect 293 - } 294 - } 295 - servers :443 { 296 - listener_wrappers { 297 - layer4 { 298 - @maildomains tls sni mail.pyrox.dev mail2.pyrox.dev mta-sts.pyrox.dev autoconfig.pyrox.dev autodiscover.pyrox.dev dav.pyrox.dev 299 - route @maildomains { 300 - proxy { 301 - proxy_protocol v2 302 - upstream 127.0.0.1:${toString mail.intHTTPS} 303 - } 304 - } 305 - } 306 - tls 307 - } 308 - } 309 257 layer4 { 310 258 :22 { 311 259 @a ssh 312 260 route @a { 313 261 proxy { 314 262 upstream ${marvinIP}:2222 315 - } 316 - } 317 - } 318 - :25 { 319 - route { 320 - proxy { 321 - proxy_protocol v2 322 - upstream 127.0.0.1:40025 323 - } 324 - } 325 - } 326 - :143 { 327 - route { 328 - proxy { 329 - proxy_protocol v2 330 - upstream 127.0.0.1:${toString mail.intIMAP} 331 - } 332 - } 333 - } 334 - :465 { 335 - route { 336 - proxy { 337 - proxy_protocol v2 338 - upstream 127.0.0.1:${toString mail.intSMTPS} 339 - } 340 - } 341 - } 342 - :587 { 343 - route { 344 - proxy { 345 - proxy_protocol v2 346 - upstream 127.0.0.1:${toString mail.intSMTP} 347 - } 348 - } 349 - } 350 - :993 { 351 - route { 352 - proxy { 353 - proxy_protocol v2 354 - upstream 127.0.0.1:${toString mail.intIMAPS} 355 - } 356 - } 357 - } 358 - :4190 { 359 - route { 360 - proxy { 361 - proxy_protocol v2 362 - upstream 127.0.0.1:${toString mail.intManageSieve} 363 263 } 364 264 } 365 265 }
-22
hosts/prefect/services/mailserver/acme.nix
··· 1 - # ACME for certs, using TLS-ALPN-01 Challenges(one fewer ports open) 2 - # https://stalw.art/docs/server/tls/acme/configuration 3 - { cfg, sec }: 4 - { 5 - letsencrypt = { 6 - directory = "https://acme-staging-v02.api.letsencrypt.org/directory"; 7 - challenge = "dns-01"; 8 - contact = [ "pyrox@pyrox.dev" ]; 9 - domains = [ 10 - "mail.pyrox.dev" 11 - "mail2.pyrox.dev" 12 - "mta-sts.pyrox.dev" 13 - "autoconfig.pyrox.dev" 14 - "autodiscover.pyrox.dev" 15 - ]; 16 - cache = "${cfg.dataDir}/acme/certs"; 17 - renew-before = "30d"; 18 - default = true; 19 - provider = "desec"; 20 - secret = "%{file:${sec.stalwart-desec-token.path}}%"; 21 - }; 22 - }
-21
hosts/prefect/services/mailserver/auth.nix
··· 1 - { ifThen, otherwise }: 2 - let 3 - relVer = [ 4 - (ifThen "protocol = 'smtp'" "relaxed") 5 - (otherwise "disable") 6 - ]; 7 - in 8 - { 9 - dkim = { 10 - sign = [ 11 - (ifThen "sender_domain = 'pyrox.dev'" "['rsa', 'ed25519']") 12 - (otherwise false) 13 - ]; 14 - }; 15 - spf.verify.ehlo = relVer; 16 - spf.verify.mail-from = relVer; 17 - dmarc.verify = relVer; 18 - iprev.verify = relVer; 19 - arc.seal = "'ed25519'"; 20 - arc.verify = "relaxed"; 21 - }
-25
hosts/prefect/services/mailserver/auto-ban.nix
··· 1 - # Strict Auto-ban 2 - # https://stalw.art/docs/server/auto-ban 3 - { 4 - auth.rate = "15/1d"; 5 - abuse.rate = "15/1d"; 6 - loiter.rate = "15/1d"; 7 - scan = { 8 - rate = "20/1d"; 9 - paths = [ 10 - "*.php*" 11 - "*.cgi*" 12 - "*.asp*" 13 - "*/wp-*" 14 - "*/php*" 15 - "*/cgi-bin*" 16 - "*xmlrpc*" 17 - "*../*" 18 - "*/..*" 19 - "*joomla*" 20 - "*wordpress*" 21 - "*drupal*" 22 - "/.git*" 23 - ]; 24 - }; 25 - }
-25
hosts/prefect/services/mailserver/calendar.nix
··· 1 - # Calendar settings 2 - # https://stalw.art/docs/collaboration/calendar 3 - { 4 - max-recurrence-expansions = 2048; 5 - # 512 KiB 6 - max-size = 524288; 7 - max-attendees-per-instance = 20; 8 - default.href-name = "default"; 9 - default.display-name = "Personal"; 10 - # Scheduling 11 - # https://stalw.art/docs/collaboration/scheduling 12 - scheduling.enable = true; 13 - # 1 MiB 14 - scheduling.inbound.max-size = 1048576; 15 - scheduling.outbound.max-recipients = 100; 16 - scheduling.inbox.auto-expunge = "30d"; 17 - scheduling.http-rsvp.enable = true; 18 - scheduling.http-rsvp.expiration = "7d"; 19 - # Notifications 20 - # https://stalw.art/docs/collaboration/notifications 21 - alarms.enable = true; 22 - alarms.minimum-interval = "1h"; 23 - alarms.from.name = "PyroNet Calendars"; 24 - alarms.from.email = "calendar-notifs@pyrox.dev"; 25 - }
-218
hosts/prefect/services/mailserver/default.nix
··· 1 - { 2 - config, 3 - lib, 4 - self, 5 - ... 6 - }: 7 - let 8 - d = self.lib.data.mail; 9 - cfg = config.services.stalwart; 10 - sec = config.age.secrets; 11 - credsDir = "/run/credentials/stalwart.service"; 12 - certDir = config.security.acme.certs."pyroxdev-mail".directory; 13 - isAuthenticated = d: { 14 - "if" = "!is_empty(authenticated_as)"; 15 - "then" = d; 16 - }; 17 - otherwise = d: { 18 - "else" = d; 19 - }; 20 - ifThen = f: d: { 21 - "if" = f; 22 - "then" = d; 23 - }; 24 - smSecret = { 25 - owner = cfg.user; 26 - inherit (cfg) group; 27 - }; 28 - in 29 - { 30 - services.stalwart = { 31 - credentials = { 32 - cert = "${certDir}/cert.pem"; 33 - key = "${certDir}/key.pem"; 34 - }; 35 - enable = true; 36 - dataDir = "/var/lib/stalwart"; 37 - settings = { 38 - tracer.stdout.level = "info"; 39 - authentication.fallback-admin = { 40 - user = "fallback"; 41 - secret = "%{file:${sec.stalwart-fallback-admin-pw.path}}%"; 42 - }; 43 - config = { 44 - local-keys = [ 45 - "asn.*" 46 - "auth.*" 47 - "authentication.*" 48 - "auto-ban.*" 49 - "calendar.*" 50 - "certificate.*" 51 - "changes.*" 52 - "cluster.*" 53 - "config.*" 54 - "contacts.*" 55 - "directory.*" 56 - "http.*" 57 - "imap.*" 58 - "jmap.*" 59 - "queue.*" 60 - "report.*" 61 - "resolver.*" 62 - "server.*" 63 - "session.*" 64 - "signature.*" 65 - "storage.*" 66 - "store.*" 67 - "tracer.*" 68 - "webadmin.*" 69 - "form.*" 70 - "email.*" 71 - "spam-filter.*" 72 - ]; 73 - }; 74 - certificate = { 75 - default = { 76 - default = true; 77 - cert = "%{file:${credsDir}/cert}%"; 78 - private-key = "%{file:${credsDir}/key}%"; 79 - subjects = [ 80 - "dav.pyrox.dev" 81 - "mail.pyrox.dev" 82 - "mail2.pyrox.dev" 83 - "mta-sts.pyrox.dev" 84 - "autoconfig.pyrox.dev" 85 - "autodiscover.pyrox.dev" 86 - ]; 87 - }; 88 - }; 89 - server = import ./server.nix { inherit d; }; 90 - # Use NixOS-generated certs now, since stalwart can't do it on its own 91 - # (DeSec API Errors abound) 92 - # acme = import ./acme.nix { inherit cfg sec; }; 93 - # HTTP Configuration 94 - # https://stalw.art/docs/http/overview 95 - http = { 96 - url = "'https://${d.extUrl}'"; 97 - hsts = true; 98 - rate-limit = { 99 - account = "10000/1m"; 100 - }; 101 - }; 102 - # Disable HTTP Forms submission 103 - # https://stalw.art/docs/http/form-submission 104 - form.enable = false; 105 - # DKIM Signatures 106 - signature = import ./signature.nix { inherit sec; }; 107 - # Storage Settings 108 - # https://stalw.art/docs/storage/overview 109 - store = { 110 - data = { 111 - type = "rocksdb"; 112 - path = "${cfg.dataDir}/db"; 113 - purge.frequency = "0 3 *"; 114 - }; 115 - blob = { 116 - type = "fs"; 117 - path = "${cfg.dataDir}/blobs"; 118 - depth = 2; 119 - compression = "lz4"; 120 - purge.frequency = "0 4 *"; 121 - }; 122 - db.path = "${cfg.dataDir}/db2"; 123 - }; 124 - storage = { 125 - data = "data"; 126 - blob = "blob"; 127 - fts = "data"; 128 - lookup = "data"; 129 - directory = "default"; 130 - }; 131 - directory = { 132 - default = { 133 - type = "internal"; 134 - store = "data"; 135 - }; 136 - }; 137 - # ASN/GeoIP Lookups 138 - # https://stalw.art/docs/server/asn 139 - asn = { 140 - type = "dns"; 141 - separator = "|"; 142 - zone.ipv4 = "origin.asn.cymru.com"; 143 - zone.ipv6 = "origin6.asn.cymru.com"; 144 - index.asn = 0; 145 - index.asn-name = 1; 146 - index.country = 2; 147 - }; 148 - auto-ban = import ./auto-ban.nix; 149 - # JMAP Settings 150 - # https://stalw.art/docs/email/jmap 151 - jmap = { 152 - mailbox.max-depth = 10; 153 - mailbox.max-name-length = 255; 154 - # 50 MB 155 - email.max-attachment-size = 50 * 1000 * 1000; 156 - # 75 MB 157 - email.max-size = 75 * 1000 * 1000; 158 - email.parse.max-items = 10; 159 - }; 160 - imap = import ./imap.nix; 161 - # Maintainance 162 - # https://stalw.art/docs/email/maintenance 163 - email.auto-expunge = "180d"; 164 - changes.max-history = 10000; 165 - session = import ./session.nix { inherit isAuthenticated otherwise ifThen; }; 166 - queue = import ./queue.nix { inherit d ifThen otherwise; }; 167 - # DNS Settings 168 - # https://stalw.art/docs/mta/outbound/dns 169 - resolver = { 170 - custom = [ 171 - "tls://dns11.quad9.net" 172 - "tcp://1.1.1.1" 173 - ]; 174 - concurrency = 2; 175 - preserve-intermediates = true; 176 - timeout = "5s"; 177 - attempts = 3; 178 - edns = true; 179 - }; 180 - report = import ./report.nix { inherit d; }; 181 - calendar = import ./calendar.nix; 182 - # Authentication 183 - auth = import ./auth.nix { inherit ifThen otherwise; }; 184 - # Contacts 185 - # https://stalw.art/docs/collaboration/contact 186 - contacts = { 187 - # 512 KiB 188 - max-size = 524288; 189 - default.href-name = "default"; 190 - default.display-name = "Contacts"; 191 - }; 192 - # Spam Filtering 193 - # https://stalw.art/docs/spamfilter/overview 194 - spam-filter = { 195 - card-is-ham = true; 196 - }; 197 - }; 198 - }; 199 - systemd.services.stalwart.serviceConfig = { 200 - Restart = lib.mkForce "always"; 201 - RestartSec = lib.mkForce 1; 202 - ReadWritePaths = lib.mkForce [ ]; 203 - }; 204 - age.secrets = { 205 - stalwart-secret-rsa = smSecret // { 206 - file = ../../secrets/stalwart-secret-rsa.age; 207 - }; 208 - stalwart-secret-ed25519 = smSecret // { 209 - file = ../../secrets/stalwart-secret-ed25519.age; 210 - }; 211 - stalwart-desec-token = smSecret // { 212 - file = ../../secrets/stalwart-desec-token.age; 213 - }; 214 - stalwart-fallback-admin-pw = smSecret // { 215 - file = ../../secrets/stalwart-fallback-admin-pw.age; 216 - }; 217 - }; 218 - }
-42
hosts/prefect/services/mailserver/imap.nix
··· 1 - # https://stalw.art/docs/email/imap 2 - { 3 - # 50 MiB 4 - request.max-size = 52428800; 5 - auth.max-failures = 3; 6 - auth.allow-plain-text = false; 7 - folders = 8 - let 9 - folder = { 10 - create = true; 11 - subscribe = true; 12 - }; 13 - in 14 - { 15 - inbox = folder // { 16 - name = "Inbox"; 17 - }; 18 - drafts = folder // { 19 - name = "Drafts"; 20 - }; 21 - sent = folder // { 22 - name = "Sent"; 23 - }; 24 - trash = folder // { 25 - name = "Trash"; 26 - }; 27 - archive = folder // { 28 - name = "Archive"; 29 - }; 30 - junk = folder // { 31 - name = "Junk"; 32 - }; 33 - shared = { 34 - name = "Shared Folders"; 35 - create = true; 36 - subscribe = false; 37 - }; 38 - }; 39 - timeout.authenticated = "30m"; 40 - timeout.anonymous = "1m"; 41 - timeout.idle = "30m"; 42 - }
-97
hosts/prefect/services/mailserver/queue.nix
··· 1 - { 2 - d, 3 - ifThen, 4 - otherwise, 5 - }: 6 - # Queue Management 7 - # https://stalw.art/docs/mta/outbound/overview 8 - { 9 - # Virtual Queues 10 - # https://stalw.art/docs/mta/outbound/queue 11 - virtual.default.threads-per-node = 100; 12 - virtual.admin.threads-per-node = 10; 13 - virtual.local.threads-per-node = 100; 14 - # Schedules 15 - # https://stalw.art/docs/mta/outbound/schedule 16 - schedule = 17 - let 18 - queue = { 19 - retry = [ 20 - "1m" 21 - "2m" 22 - "5m" 23 - "10m" 24 - "15m" 25 - "30m" 26 - "1h" 27 - "2h" 28 - ]; 29 - notify = [ 30 - "1d" 31 - "3d" 32 - ]; 33 - max-attempts = 15; 34 - }; 35 - in 36 - { 37 - default = queue // { 38 - queue-name = "default"; 39 - }; 40 - admin = queue // { 41 - queue-name = "admin"; 42 - }; 43 - local = queue // { 44 - queue-name = "local"; 45 - }; 46 - }; 47 - # Routes 48 - # https://stalw.art/docs/mta/outbound/routing 49 - route = { 50 - local.type = "local"; 51 - remote = { 52 - type = "mx"; 53 - ip-lookup = "ipv6_then_ipv4"; 54 - tls.implicit = false; 55 - tls.allow-invalid-certs = false; 56 - }; 57 - }; 58 - # Strategies 59 - # https://stalw.art/docs/mta/outbound/strategy 60 - strategy = { 61 - schedule = [ 62 - (ifThen "is_local_domain('', rcpt_domain)" "'local'") 63 - (ifThen "source = 'dsn'" "'admin'") 64 - (ifThen "source = 'report'" "'admin'") 65 - (ifThen "source = 'autogenerated'" "'admin'") 66 - (otherwise "'default'") 67 - ]; 68 - route = [ 69 - (ifThen "is_local_domain('', rcpt_domain)" "'local'") 70 - (otherwise "'remote'") 71 - ]; 72 - connection = "'default'"; 73 - tls = "'default'"; 74 - }; 75 - # Remote Connection 76 - # https://stalw.art/docs/mta/outbound/connection 77 - connection.default = { 78 - ehlo-hostname = d.extUrl; 79 - source-ips = d.extIPs; 80 - timeout = { 81 - connect = "3m"; 82 - greeting = "3m"; 83 - ehlo = "3m"; 84 - mail-from = "3m"; 85 - rcpt-to = "3m"; 86 - data = "10m"; 87 - }; 88 - }; 89 - tls.default = { 90 - dane = "optional"; 91 - mta-sts = "optional"; 92 - starttls = "optional"; 93 - allow-invalid-certs = false; 94 - timeout.tls = "3m"; 95 - timeout.mta-sts = "3m"; 96 - }; 97 - }
-64
hosts/prefect/services/mailserver/report.nix
··· 1 - { d }: 2 - # Reports 3 - # https://stalw.art/docs/mta/reports/overview 4 - { 5 - domain = "pyrox.dev"; 6 - submitter = "'${d.extUrl}'"; 7 - analysis = { 8 - addresses = [ 9 - "dmarc@" 10 - "reports@" 11 - "spf@" 12 - "dkim@" 13 - "abuse@" 14 - ]; 15 - forward = true; 16 - store = "30d"; 17 - }; 18 - dsn = { 19 - from-name = "'PyroNet Mail'"; 20 - from-address = "'mail@pyrox.dev'"; 21 - sign = "['rsa', 'ed25519']"; 22 - }; 23 - dkim = { 24 - from-name = "'PyroNet Mail Reports'"; 25 - from-address = "'noreply-dkim@pyrox.dev'"; 26 - subject = "'DKIM Authentication Failure Report'"; 27 - sign = "['rsa', 'ed25519']"; 28 - send = "1/1d"; 29 - }; 30 - spf = { 31 - from-name = "'PyroNet Mail Reports'"; 32 - from-address = "'noreply-spf@pyrox.dev'"; 33 - subject = "'SPF Authentication Failure Report'"; 34 - sign = "['rsa', 'ed25519']"; 35 - send = "1/1d"; 36 - }; 37 - dmarc = { 38 - from-name = "'PyroNet Mail Reports'"; 39 - from-address = "'noreply-dmarc@pyrox.dev'"; 40 - subject = "'DMARC Authentication Failure Report'"; 41 - sign = "['rsa', 'ed25519']"; 42 - send = "1/1d"; 43 - aggregate = { 44 - from-name = "'DMARC Report'"; 45 - from-address = "'noreply-dmarc@pyrox.dev'"; 46 - org-name = "'PyroNet Mail'"; 47 - contact-info = "'pyrox@pyrox.dev'"; 48 - send = "daily"; 49 - # 25 MiB 50 - max-size = 26214400; 51 - sign = "['rsa', 'ed25519']"; 52 - }; 53 - }; 54 - tls.aggregate = { 55 - from-name = "'PyroNet Mail Reports'"; 56 - from-address = "'noreply-tls@pyrox.dev'"; 57 - org-name = "'PyroNet Mail'"; 58 - contact-info = "'pyrox@pyrox.dev'"; 59 - send = "daily"; 60 - # 25 MiB 61 - max-size = 26214400; 62 - sign = "['rsa', 'ed25519']"; 63 - }; 64 - }
-69
hosts/prefect/services/mailserver/server.nix
··· 1 - { d }: 2 - { 3 - hostname = d.extUrl; 4 - # TLS 5 - # https://stalw.art/docs/server/tls/overview 6 - tls = { 7 - enable = true; 8 - implicit = false; 9 - ignore-client-order = true; 10 - }; 11 - # Listeners 12 - # https://stalw.art/docs/server/listener 13 - listener = { 14 - smtp = { 15 - bind = [ 16 - "[::]:${toString d.intSMTP}" 17 - "[::]:40025" 18 - ]; 19 - protocol = "smtp"; 20 - # Explicit TLS 21 - tls.implicit = false; 22 - }; 23 - smtps = { 24 - bind = "[::]:${toString d.intSMTPS}"; 25 - protocol = "smtp"; 26 - # Implicit TLS 27 - tls.implicit = true; 28 - }; 29 - imap = { 30 - bind = "[::]:${toString d.intIMAP}"; 31 - protocol = "imap"; 32 - # Explicit TLS 33 - tls.implicit = false; 34 - }; 35 - imaps = { 36 - bind = "[::]:${toString d.intIMAPS}"; 37 - protocol = "imap"; 38 - # Implicit TLS 39 - tls.implicit = true; 40 - }; 41 - managesieve = { 42 - bind = "[::]:${toString d.intManageSieve}"; 43 - protocol = "managesieve"; 44 - # Explicit TLS 45 - tls.implicit = false; 46 - }; 47 - https = { 48 - bind = "[::]:${toString d.intHTTPS}"; 49 - protocol = "http"; 50 - # Implicit TLS 51 - tls.implicit = true; 52 - }; 53 - http = { 54 - bind = "[::]:${toString d.intHTTP}"; 55 - protocol = "http"; 56 - # Implicit TLS 57 - tls.implicit = false; 58 - }; 59 - }; 60 - # Proxy Protocol from Caddy 61 - # Only accepts proxy protocol from Tailscale IP Ranges 62 - # https://tailscale.com/kb/1015/100.x-addresses 63 - # https://tailscale.com/kb/1033/ip-and-dns-addresses 64 - proxy.trusted-networks = [ 65 - "fd7a:115c:a1e0::/48" 66 - "100.64.0.0/10" 67 - "127.0.0.1/8" 68 - ]; 69 - }
-63
hosts/prefect/services/mailserver/session.nix
··· 1 - { 2 - isAuthenticated, 3 - otherwise, 4 - ifThen, 5 - }: 6 - # MTA Settings 7 - # https://stalw.art/docs/mta/overview 8 - { 9 - # Inbound 10 - # https://stalw.art/docs/mta/inbound/overview 11 - # # EHLO Stage 12 - # # https://stalw.art/docs/mta/inbound/ehlo 13 - ehlo = { 14 - require = true; 15 - reject-non-fqdn = [ 16 - (ifThen "protocol = 'smtp'" true) 17 - (otherwise false) 18 - ]; 19 - }; 20 - # # RCPT Stage 21 - # # https://stalw.art/docs/mta/inbound/rcpt 22 - rcpt = { 23 - relay = [ 24 - (isAuthenticated true) 25 - (otherwise false) 26 - ]; 27 - subaddressing = true; 28 - }; 29 - auth = { 30 - mechanisms = [ 31 - (ifThen "local_port != 40025 && is_tls" "[plain, login, oauthbearer, xoauth2]") 32 - (ifThen "local_port != 40025" "[oauthbearer, xoauth2]") 33 - (otherwise false) 34 - ]; 35 - directory = "'default'"; 36 - require = [ 37 - (ifThen "local_port != 40025" true) 38 - (otherwise false) 39 - ]; 40 - must-match-sender = true; 41 - }; 42 - extensions = 43 - let 44 - ifAuthed = [ 45 - (isAuthenticated true) 46 - (otherwise false) 47 - ]; 48 - in 49 - { 50 - pipelining = true; 51 - chunking = true; 52 - requiretls = true; 53 - no-soliciting = ""; 54 - dsn = ifAuthed; 55 - deliver-by = [ 56 - (isAuthenticated "15d") 57 - (otherwise false) 58 - ]; 59 - mt-priority = false; 60 - vrfy = ifAuthed; 61 - expn = ifAuthed; 62 - }; 63 - }
-42
hosts/prefect/services/mailserver/signature.nix
··· 1 - { sec }: 2 - let 3 - headers = [ 4 - "From" 5 - "To" 6 - "Cc" 7 - "Date" 8 - "Subject" 9 - "Message-ID" 10 - "Organization" 11 - "MIME-Version" 12 - "Content-Type" 13 - "In-Reply-To" 14 - "References" 15 - "List-Id" 16 - "User-Agent" 17 - "Thread-Topic" 18 - "Thread-Index" 19 - ]; 20 - in 21 - { 22 - rsa = { 23 - inherit headers; 24 - private-key = "%{file:${sec.stalwart-secret-rsa.path}}%"; 25 - domain = "pyrox.dev"; 26 - selector = "rsa-default"; 27 - algorithm = "rsa-sha256"; 28 - canonicalization = "relaxed/relaxed"; 29 - expire = "10d"; 30 - report = true; 31 - }; 32 - ed25519 = { 33 - inherit headers; 34 - private-key = "%{file:${sec.stalwart-secret-ed25519.path}}%"; 35 - domain = "pyrox.dev"; 36 - selector = "default"; 37 - algorithm = "ed25519-sha256"; 38 - canonicalization = "relaxed/relaxed"; 39 - expire = "10d"; 40 - report = true; 41 - }; 42 - }
+13 -2
lib/data/hosts.toml
··· 5 5 # ts.ip6: The node's tailscale IPv6 address 6 6 [marvin] 7 7 role = "server" 8 + 8 9 [marvin.ts] 9 10 ip4 = "100.123.15.72" 10 11 ip6 = "fd7a:115c:a1e0:ab12:4843:cd96:627b:f48" 12 + 13 + [prefect_old] 14 + role = "server" 15 + 16 + [prefect_old.ts] 17 + ip4 = "100.93.63.54" 18 + ip6 = "fd7a:115c:a1e0:ab12:4843:cd96:625d:3f36" 11 19 12 20 [prefect] 13 21 role = "server" 22 + 14 23 [prefect.ts] 15 - ip4 = "100.93.63.54" 16 - ip6 = "fd7a:115c:a1e0:ab12:4843:cd96:625d:3f36" 24 + ip4 = "100.107.252.71" 25 + ip6 = "fd7a:115c:a1e0::f938:fc47" 17 26 18 27 [zaphod] 19 28 role = "desktop" 29 + 20 30 [zaphod.ts] 21 31 ip4 = "100.125.9.36" 22 32 ip6 = "fd7a:115c:a1e0:ab12:4843:cd96:627d:924" 23 33 24 34 [thought] 25 35 role = "server" 36 + 26 37 [thought.ts] 27 38 ip4 = "" 28 39 ip6 = ""
-10
lib/data/mail.toml
··· 1 - extUrl = "mail.pyrox.dev" 2 - extIPs = ["5.161.140.5", "2a01:4ff:f0:98bf:0:0:0:1"] 3 - # internal port is 40k+real mail port 4 - intSMTP = 40587 5 - intSMTPS = 40465 6 - intIMAP = 40143 7 - intIMAPS = 40993 8 - intManageSieve = 44190 9 - intHTTPS = 40443 10 - intHTTP = 40080