From afd3360582d91957d4e6ed90bd98456d86819282 Mon Sep 17 00:00:00 2001 From: Jet Pham Date: Fri, 20 Feb 2026 02:46:08 -0800 Subject: [PATCH] feat: fix qemu onto hetzner and fix mailserver --- .gitignore | 3 ++- README.md | 10 +++++++++- configuration.nix | 2 +- modules/caddy.nix | 36 ++++++++++++++++++++++++++++++++---- modules/mail.nix | 39 +++++++++++++++++++++++++++++++++------ 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 29a6690..6d12da4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,9 @@ result-* # Secrets (Untracked) secrets/secrets.nix +dkim_private.pem # Only track the example file !secrets/secrets.nix.example -install.log \ No newline at end of file +install.log diff --git a/README.md b/README.md index 37da4a3..956da57 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,15 @@ This repository uses **untracked secrets**, so you must build the system locally 2. Fill in the values (generate random keys, etc). - `tailscaleKey` must be a **Reusable** key from the Tailscale admin console. -### 2. Initial Install (Wite & Install) +### 2. Verify Configuration Locally +Because `secrets/secrets.nix` is untracked by git, standard `nix flake check` will fail. +To build the server configuration locally and ensure there are no syntax or evaluation errors before pushing to the server, run: + +```bash +nix build path:.#nixosConfigurations.extremist-software.config.system.build.toplevel --impure --dry-run +``` + +### 3. Initial Install (Wipe & Install) Run this command to build and deploy. **Warning: Wipes the server disk.** ```bash diff --git a/configuration.nix b/configuration.nix index 2d0850e..415f677 100644 --- a/configuration.nix +++ b/configuration.nix @@ -2,12 +2,12 @@ { imports = [ + (modulesPath + "/profiles/qemu-guest.nix") ./modules/caddy.nix ./modules/forgejo.nix ./modules/mail.nix ./modules/searx.nix ./modules/matrix.nix - ./modules/matrix.nix ./modules/monitoring.nix ./secrets/secrets-scheme.nix # Impure Secrets diff --git a/modules/caddy.nix b/modules/caddy.nix index 932a9df..7c8c621 100644 --- a/modules/caddy.nix +++ b/modules/caddy.nix @@ -3,10 +3,18 @@ { services.caddy = { enable = true; + email = "postmaster@extremist.software"; virtualHosts = { "extremist.software" = { + useACMEHost = "extremist.software"; extraConfig = '' - respond "Hi" + handle /.well-known/acme-challenge/* { + root * /var/lib/acme/acme-challenge + file_server + } + handle { + respond "Hi" + } ''; }; @@ -17,10 +25,15 @@ }; "mail.extremist.software" = { - # Stalwart handles its own certs usually, or we can proxy UI here - # Stalwart UI is usually on 8080 + useACMEHost = "extremist.software"; extraConfig = '' - reverse_proxy localhost:8080 + handle /.well-known/acme-challenge/* { + root * /var/lib/acme/acme-challenge + file_server + } + handle { + reverse_proxy localhost:8080 + } ''; }; @@ -45,5 +58,20 @@ }; }; + # Configure ACME to fetch Let's Encrypt certificates so they can be shared with other services like Stalwart + security.acme = { + acceptTerms = true; + defaults.email = "postmaster@extremist.software"; + defaults.server = "https://acme-v02.api.letsencrypt.org/directory"; + certs."extremist.software" = { + webroot = "/var/lib/acme/acme-challenge"; + extraDomainNames = [ "mail.extremist.software" ]; + group = "acme"; + }; + }; + + # Ensure Caddy can read the certs too now that they are in the acme group + users.users.caddy.extraGroups = [ "acme" ]; + networking.firewall.allowedTCPPorts = [ 80 443 ]; } diff --git a/modules/mail.nix b/modules/mail.nix index 874ff35..dc60e4f 100644 --- a/modules/mail.nix +++ b/modules/mail.nix @@ -3,29 +3,56 @@ { services.stalwart = { enable = true; + # Let stalwart open its own ports if needed for the main services + openFirewall = true; + settings = { server = { - hostname = "mail.extremist.software"; + hostname = "extremist.software"; tls = { enable = true; implicit = false; # StartTLS usually on 587 }; + listener = { + smtp = { + protocol = "smtp"; + bind = "[::]:25"; + }; + submissions = { + bind = "[::]:465"; + protocol = "smtp"; + tls.implicit = true; + }; + imaps = { + bind = "[::]:993"; + protocol = "imap"; + tls.implicit = true; + }; + management = { + bind = [ "127.0.0.1:8080" ]; + protocol = "http"; + }; + }; + }; + + # Use the certificate procured by security.acme for Caddy + certificate."default" = { + cert = "%{file:/var/lib/acme/extremist.software/fullchain.pem}%"; + private-key = "%{file:/var/lib/acme/extremist.software/key.pem}%"; }; authentication.fallback-admin = { user = "admin"; secret = config.mySecrets.stalwartAdmin; }; - - # Stalwart configuration is quite extensive. - # By default it listens on standard ports (25, 465, 587, 993, 4190) - # and provides a web admin UI on 8080. }; }; + # Allow Stalwart to read the ACME certificate procured for Caddy + systemd.services.stalwart.serviceConfig.SupplementaryGroups = [ "acme" ]; + # Open Firewalls for Mail networking.firewall.allowedTCPPorts = [ - 25 465 587 # SMTP 993 # IMAP (Secure) 4190 # Sieve 8080 # Admin UI (Reverse proxied, but good to double check loopback)