From 08d9fc594e05db1ab0c3ab041d0db82796a6fb20 Mon Sep 17 00:00:00 2001 From: Lars Nolden Date: Wed, 1 Jul 2026 13:09:08 +0200 Subject: [PATCH] Fix invalid Caddyfile: put layer4 in globalConfig, not a 2nd global block The NixOS caddy module already emits one global options block (for `email`) and appends extraConfig after it. gebos-caddy also prepended its own keyless `{ layer4 { ... } }` block, so the rendered Caddyfile had two keyless blocks and caddy rejected it: "server block without any key is global configuration, and if used, it must be first" -> caddy.service failed -> mqtt-ingest activation exited 4 and deploy-rs rolled back. Move the layer4 directive into services.caddy.globalConfig so it lands inside the module's single global block. Verified the rendered Caddyfile for mqtt-ingest; app-host (http-only) output is unchanged. Co-Authored-By: Claude Opus 4.8 --- nix/modules/gebos-caddy.nix | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/nix/modules/gebos-caddy.nix b/nix/modules/gebos-caddy.nix index e8ed7a7..bfa18d7 100644 --- a/nix/modules/gebos-caddy.nix +++ b/nix/modules/gebos-caddy.nix @@ -59,13 +59,15 @@ let } ''; - # Caddyfile global options block must come first and exist once; we fold every - # layer4 listener into a single `layer4 { ... }` inside it. - globalOptions = lib.optionalString needsLayer4 '' - { - layer4 { + # caddy-l4 listeners, folded into one `layer4` directive that lives INSIDE the + # Caddyfile global options block. We must NOT emit our own `{ }` block here: + # the NixOS caddy module already generates the single global block (for + # `email`), and a second keyless block is invalid ("server block without any + # key is global configuration, and if used, it must be first"). So this goes to + # services.caddy.globalConfig, which the module places inside that one block. + layer4Global = lib.optionalString needsLayer4 '' + layer4 { ${lib.concatStrings (lib.mapAttrsToList layer4Listener tcpProxySites)} } - } ''; in { @@ -82,9 +84,9 @@ in enable = true; package = if needsLayer4 then caddyWithL4 else pkgs.caddy; email = "ops@gebos.online"; # TODO: confirm ACME contact + globalConfig = layer4Global; extraConfig = lib.concatStringsSep "\n" ( - [ globalOptions ] - ++ lib.mapAttrsToList httpSiteBlock httpSites + lib.mapAttrsToList httpSiteBlock httpSites ++ lib.mapAttrsToList certSiteBlock tcpProxySites ); };