From b74e5aab627a0901ac0198c00e21303ff7a76461 Mon Sep 17 00:00:00 2001 From: Martin Berg Alstad Date: Mon, 2 Jun 2025 17:44:41 +0000 Subject: [PATCH] :sparkles: [pi4] Added initial Simple mailserver config --- flake.lock | 138 +++++++++++++++++++++++++++++++++++- flake.nix | 2 + hosts/pi4/caddy.nix | 46 ++++++------ hosts/pi4/default.nix | 2 + hosts/pi4/forgejo.nix | 5 +- hosts/pi4/mailserver.nix | 55 ++++++++++++++ shared/secrets/secrets.yaml | 6 +- 7 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 hosts/pi4/mailserver.nix diff --git a/flake.lock b/flake.lock index 6e9c17b..b9fa835 100644 --- a/flake.lock +++ b/flake.lock @@ -44,6 +44,22 @@ "type": "github" } }, + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, "catppuccin": { "inputs": { "nixpkgs": "nixpkgs" @@ -62,6 +78,70 @@ "type": "github" } }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "simple-nixos-mailserver", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "simple-nixos-mailserver", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1742649964, + "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "simple-nixos-mailserver", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "grayjay": { "inputs": { "nixpkgs": "nixpkgs_2" @@ -157,6 +237,22 @@ "type": "github" } }, + "nixpkgs-25_05": { + "locked": { + "lastModified": 1747610100, + "narHash": "sha256-rpR5ZPMkWzcnCcYYo3lScqfuzEw5Uyfh+R0EKZfroAc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ca49c4304acf0973078db0a9d200fd2bae75676d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs-stable": { "locked": { "lastModified": 1748162331, @@ -238,6 +334,22 @@ } }, "nixpkgs_5": { + "locked": { + "lastModified": 1747179050, + "narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { "locked": { "lastModified": 1743448293, "narHash": "sha256-bmEPmSjJakAp/JojZRrUvNcDX2R5/nuX6bm+seVaGhs=", @@ -262,11 +374,35 @@ "nixpkgs": "nixpkgs_4", "nixpkgs-stable": "nixpkgs-stable", "nixpkgs-unstable": "nixpkgs-unstable", + "simple-nixos-mailserver": "simple-nixos-mailserver", "sops-nix": "sops-nix", "spicetify-nix": "spicetify-nix", "zen-browser": "zen-browser" } }, + "simple-nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs_5", + "nixpkgs-25_05": "nixpkgs-25_05" + }, + "locked": { + "lastModified": 1747965231, + "narHash": "sha256-BW3ktviEhfCN/z3+kEyzpDKAI8qFTwO7+S0NVA0C90o=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "53007af63fade28853408370c4c600a63dd97f41", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "ref": "nixos-25.05", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ @@ -326,7 +462,7 @@ "zen-browser": { "inputs": { "home-manager": "home-manager_2", - "nixpkgs": "nixpkgs_5" + "nixpkgs": "nixpkgs_6" }, "locked": { "lastModified": 1748229380, diff --git a/flake.nix b/flake.nix index e9d632b..94db4db 100644 --- a/flake.nix +++ b/flake.nix @@ -31,6 +31,7 @@ catppuccin.url = "github:catppuccin/nix"; # Bar hyprpanel.url = "github:Jas-SinghFSU/HyprPanel"; + simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-25.05"; # Spotify spicetify-nix = { url = "github:Gerg-L/spicetify-nix"; @@ -47,6 +48,7 @@ self, nixpkgs, home-manager, + simple-nixos-mailserver, ... }@inputs: let diff --git a/hosts/pi4/caddy.nix b/hosts/pi4/caddy.nix index 50f8166..7e0d52e 100644 --- a/hosts/pi4/caddy.nix +++ b/hosts/pi4/caddy.nix @@ -4,11 +4,13 @@ let in { services.caddy = { - enable = true; + enable = false; email = "cert@${domain}"; virtualHosts = let - reverseProxy = port: "reverse_proxy localhost:${builtins.toString port}"; + localProxy = proxyTo "localhost"; + homelabProxy = proxyTo "192.168.10.231"; + proxyTo = ip: port: "reverse_proxy ${ip}:${builtins.toString port}"; redirect = subdomain: "redir https://${subdomain}.${domain}{uri}"; in { @@ -23,62 +25,66 @@ in ''; # Gitea "code.${domain}".extraConfig = '' - ${reverseProxy 3000} + ${homelabProxy 3000} + ''; + # Forgejo + "beta.code.${domain}".extraConfig = '' + ${localProxy 8001} ''; # Nextcloud "nextcloud.${domain}".extraConfig = '' redir /.well-known/carddav /remote.php/dav 301 redir /.well-known/caldav /remote.php/dav 301 - ${reverseProxy 11000} + ${homelabProxy 11000} ''; # Kitchenowl "grocery.${domain}".extraConfig = '' - ${reverseProxy 800} + ${homelabProxy 800} ''; # Actual Budget "budget.${domain}".extraConfig = '' - ${reverseProxy 5006} + ${homelabProxy 5006} ''; # Uptime Kuma "status.${domain}".extraConfig = '' - ${reverseProxy 3001} + ${homelabProxy 3001} ''; # Headscale "vpn.${domain}".extraConfig = '' - reverse_proxy /web* localhost:8084 - reverse_proxy * localhost:8082 + reverse_proxy /web* 192.168.10.231:8084 + reverse_proxy * 192.168.10.231:8082 ''; # Headscale SmartDNS "dns.${domain}".extraConfig = '' - ${reverseProxy 8082} + ${homelabProxy 8082} ''; # FreshRSS "rss.${domain}".extraConfig = '' - ${reverseProxy 8085} + ${homelabProxy 8085} ''; # Ente backend "api.ente.${domain}".extraConfig = '' - ${reverseProxy 8083} + ${homelabProxy 8083} ''; # Ente Photos frontend "ente.${domain}".extraConfig = '' - ${reverseProxy 3003} + ${homelabProxy 3003} ''; # Ente Auth frontend "mfa.${domain}".extraConfig = '' - ${reverseProxy 3004} + ${homelabProxy 3004} ''; # Homepage / portfolio - "${domain}".extraconfig = '' - ${reverseProxy 4321} + "${domain}".extraConfig = '' + ${homelabProxy 4321} ''; # Yamtrack "track.${domain}".extraConfig = '' - ${reverseProxy 8090} + ${homelabProxy 8090} ''; - # Postal - "mail.${domain}".extraConfig = '' - ${reverseProxy 5000} + # Donetick + "chore.${domain}".extraConfig = '' + ${homelabProxy 2021} ''; }; }; diff --git a/hosts/pi4/default.nix b/hosts/pi4/default.nix index 325cf69..8d0e097 100644 --- a/hosts/pi4/default.nix +++ b/hosts/pi4/default.nix @@ -4,8 +4,10 @@ imports = with lib.custom; [ (relativeToBase "modules") ./boot.nix + ./caddy.nix ./forgejo.nix ./hardware.nix + ./mailserver.nix ./nextcloud.nix ./podman.nix ./security diff --git a/hosts/pi4/forgejo.nix b/hosts/pi4/forgejo.nix index 4f67bf3..5bd13f5 100644 --- a/hosts/pi4/forgejo.nix +++ b/hosts/pi4/forgejo.nix @@ -34,9 +34,10 @@ in # Sending emails is completely optional # You can send a test email from the web UI at: # Profile Picture > Site Administration > Configuration > Mailer Configuration - mailer = { + mailer = lib.mkIf config.mailserver.enable { ENABLED = true; - SMTP_ADDR = "mail.${common.domain}"; + PROTOCOL = "smtps"; + SMTP_ADDR = config.mailserver.fqdn; FROM = "noreply-forgejo@${common.domain}"; USER = "noreply@${common.domain}"; }; diff --git a/hosts/pi4/mailserver.nix b/hosts/pi4/mailserver.nix new file mode 100644 index 0000000..f86dcf0 --- /dev/null +++ b/hosts/pi4/mailserver.nix @@ -0,0 +1,55 @@ +{ + lib, + config, + inputs, + common, + systemConfig, + ... +}: +let + cfg = config.mailserver; + passwordHashKey = "mailserver/password-hash"; +in +{ + imports = [ + inputs.simple-nixos-mailserver.nixosModule + ]; + + mailserver = { + enable = true; + # stateVersion = 1; TODO uncomment on 25.11 + fqdn = "mail.${common.domain}"; + domains = [ + common.domain + ]; + + # A list of all login accounts. To create the password hashes, use + # nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' + loginAccounts = { + "${systemConfig.username}@${common.domain}" = { + hashedPasswordFile = config.sops.secrets.${passwordHashKey}.path; + }; + }; + + # Use Let's Encrypt certificates. Note that this needs to set up a stripped + # down nginx and opens port 80. + # certificateScheme = "acme-nginx"; + }; + # security.acme.acceptTerms = true; + # security.acme.defaults.email = "security@example.com"; + + services.nginx.virtualHosts.${cfg.fqdn}.listen = lib.mkForce [ + { + addr = "127.0.0.1"; + port = 8003; + ssl = false; + } + { + addr = "192.168.10.188"; + port = 8003; + ssl = false; + } + ]; + + sops.secrets.${passwordHashKey}.neededForUsers = true; +} diff --git a/shared/secrets/secrets.yaml b/shared/secrets/secrets.yaml index e01f530..bbfefc3 100644 --- a/shared/secrets/secrets.yaml +++ b/shared/secrets/secrets.yaml @@ -3,6 +3,8 @@ forgejo: #ENC[AES256_GCM,data:oMpYBQ30sdCTtgxEZvYxTd9oi9QM0bYp5NisMdQHYT/nF2k=,iv:H9/g7XttJScVXV38+yHdbgWNFDhBYyudjK5BKHTt5wo=,tag:FNfkKfkKWDBUAXiGXkDchw==,type:comment] runner-token: ENC[AES256_GCM,data:xbULBWrqosktW7XHViLH7Sk76upH31RFQNsBcXWWN7bpRadF3tpBA/hksMyEdg==,iv:v3vzUb5wsWeKWRYWT+ks4ZWGXQRhZ+td3N3bpuwoVc8=,tag:rEVoEw/QOSs8puujsRBxXQ==,type:str] password-hash: ENC[AES256_GCM,data:FsGHBAw/z4tcBRObVlo//UotWHyHns0+vdJVgt2lfGiIfQG+1I60g2Tzgv/O+gz3oz41NIwAYf61SR9AfXhpnc1AxiZRlCBwMQ==,iv:oiJndSVZQ+00UPz0TuJXV+T8x9mtecrNDUaablOGffU=,tag:wQuow7C8KqelJOE9KqCxMA==,type:str] +mailserver: + password-hash: ENC[AES256_GCM,data:H5PlCVuwUxIjtWbNsxb/ROkY2KiNhSwvWDvTLBfR596ijRTkaH0xtltsvHiiNHmfKERfcAXKO9EyGNHc,iv:qev1fs0PPydz8cm9D7hLp6ULgUEQJm+E0Pg86bor1to=,tag:zFnJ23NDCXeur+kvNSQV6w==,type:str] nextcloud: admin-pass: ENC[AES256_GCM,data:RBuuNc7J/CCJXG8n73B5cw==,iv:uKNj40SdJn6LbZoV1i9fq+5TGmRDPYVhCxAUghV4vqs=,tag:wUHBPo5T+2tyjsQFlUXDEQ==,type:str] sops: @@ -34,7 +36,7 @@ sops: SGdNMnVlQlNEeVJkWmZEM1FRT2JJMGMKbZ/znJM6tFhzhHariRXMLgH/4CRZZKrb YtmSdeL/Pd5YIecCpjDHDn4vQ0TBAmLaX+zVbNbRKmMZoY7777ywfA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-05-31T15:36:05Z" - mac: ENC[AES256_GCM,data:Um09D7CR5+c4L6bTdRvz1Cy5qHthlKfLfH6k9Z2NTuD2QY9Ua4kXV8byvXiP+GrrKgzV11c0a3Hk7zaQoutXmwatnaOJRT9EH3FIEADLGAFwbsSAgV7ZJ+oamZnIw/XSW/LGpwvPrX5gaTnc7jJJ3V3+tWqgBUmL4wNb2SigglM=,iv:wAXaPUs20wqh7cn8ZmFI7XLlaOYLkjtcVRm1sosO9U4=,tag:FwfNbEf+YoQBHsYBw5k6mw==,type:str] + lastmodified: "2025-06-02T17:06:40Z" + mac: ENC[AES256_GCM,data:gwYDPAicJCWdCwW5hikEUkByf0KtSBGNOzfqyTdtsMvTi2HCOiKL2JgBnqjDF82o2XfbHalzzYTstxfWla62lLzF/xPWWoWOtAVB7w2YcEkptr66qU4q3iQi7t878B/+VVHva35TEho8b2JL2vgJNpBp3l06XeWMYCpupc5P7pM=,iv:ZaTpfjfcMeeExySTfI2wMSmFBFi6aoH83yYiucZXRQM=,tag:XwAvMtrX1bUumEaRf3T7Cg==,type:str] unencrypted_suffix: _unencrypted version: 3.10.2