From d7fea37e251915f5c49afe7a8f01856886f06418 Mon Sep 17 00:00:00 2001 From: Andrew Bryant Date: Sat, 26 Sep 2026 14:37:12 -0400 Subject: [PATCH] nixos-module: fix caddy Host-header matching for 127.0.0.1/[::1] Caddy strictly matches vhosts on the exact Host header, unlike nginx where a single vhost acts as the default regardless of Host. With hostname = "localhost" (the local-dev default), visiting the VM via http://127.0.0.1:PORT instead of http://localhost:PORT sent a Host header matching no vhost, and Caddy silently returned an empty 200 OK - a genuine white screen with no error anywhere (not in the console, not in the network tab). Adds serverAliases for 127.0.0.1:80 and [::1]:80 to the caddy vhost when hostname is "localhost", so all three ways of reaching the local VM resolve to the same site block. Verified directly: before this fix, curl with `Host: 127.0.0.1` got an empty response while `Host: localhost` got the full app shell; after, all three (localhost, 127.0.0.1, [::1]) return the same 200 response. Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 4 ++++ nixos-module/invoiceninja.nix | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 58225fb..c5a4b00 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -112,6 +112,10 @@ expect Nix to report the correct hash on a failed build (or use `nix-prefetch`/` earlier version of this module additionally set a second, static set of `Access-Control-*` headers at the proxy level, which browsers reject as conflicting duplicates (server-to-server/curl checks don't notice, since only browsers enforce CORS header validation). + - Caddy matches vhosts on the exact `Host` header, unlike nginx (where a single vhost acts as the default + regardless of `Host`). When `hostname == "localhost"`, the caddy vhost adds `serverAliases` for + `127.0.0.1:80`/`[::1]:80` too — otherwise visiting the VM via the IP literal instead of `localhost` matches no + vhost and Caddy silently returns an empty `200 OK` (a blank page with no error anywhere). - Chromium is required at runtime for PDF generation (`PDF_GENERATOR=snappdf`, `SNAPPDF_CHROMIUM_PATH`) and is added to the PHP-FPM and data-setup services' `path`. diff --git a/nixos-module/invoiceninja.nix b/nixos-module/invoiceninja.nix index 697b68b..5a0d6c7 100644 --- a/nixos-module/invoiceninja.nix +++ b/nixos-module/invoiceninja.nix @@ -557,6 +557,14 @@ in cfg.proxy.caddyConfig { hostName = lib.mkForce proto_hostname; + # Caddy matches vhosts on the exact Host header, unlike nginx's single-vhost-is-default + # behavior. For local dev, accept requests to 127.0.0.1/[::1] too - otherwise visiting + # via the IP literal instead of "localhost" hits no vhost and gets an empty 200 response + # (a silent white screen, no error anywhere). + serverAliases = lib.mkIf (cfg.hostname == "localhost") [ + "127.0.0.1:80" + "[::1]:80" + ]; extraConfig = '' encode zstd gzip root ${invoiceninja}/public