caddy int

This commit is contained in:
mjallen18
2026-04-09 14:57:27 -05:00
parent b73ad049e7
commit 7cc6732a7e
4 changed files with 171 additions and 3 deletions

View File

@@ -0,0 +1,107 @@
{
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
name = "caddy-internal";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
caddyPackage = pkgs.caddy.withPlugins {
plugins = [
"github.com/caddy-dns/cloudflare@v0.2.3"
];
hash = "sha256-20o+14cn/eeLuf1c8uGE1ODRZGC0oxocaIVlv4tFSvA=";
};
# Build a virtual-host block for one proxy entry.
# Access is restricted to LAN + Nebula subnets; all other clients get 403.
mkProxyBlock =
entryName: proxyCfg:
let
fqdn = "${proxyCfg.subdomain}.${net.domain}";
in
''
@${entryName} host ${fqdn}
handle @${entryName} {
@${entryName}_internal {
remote_ip ${net.subnet.lan} ${net.subnet.nebula}
host ${fqdn}
}
handle @${entryName}_internal {
reverse_proxy ${proxyCfg.upstream}
${proxyCfg.extraCaddyConfig}
}
handle {
respond "Forbidden" 403
}
}
'';
proxyBlocks = lib.concatStringsSep "\n" (
lib.mapAttrsToList mkProxyBlock (lib.filterAttrs (_: p: p.enable) cfg.proxies)
);
caddy-internal = lib.${namespace}.mkModule {
inherit config name;
description = "Internal-only Caddy reverse proxy with HTTPS via Cloudflare DNS challenge";
options = {
proxies = mkOption {
type = types.attrsOf (
types.submodule {
options = {
enable = lib.${namespace}.mkBoolOpt true "Whether to enable this proxy entry";
subdomain = lib.${namespace}.mkOpt types.str "" "Subdomain under ${net.domain}";
upstream = lib.${namespace}.mkOpt types.str "" "Upstream address (e.g. http://127.0.0.1:8123)";
extraCaddyConfig =
lib.${namespace}.mkOpt types.lines ""
"Extra Caddyfile directives for this entry";
};
}
);
default = { };
description = "Internal services to proxy, each restricted to LAN + Nebula subnets";
};
};
moduleConfig = {
services.caddy = {
enable = true;
package = caddyPackage;
environmentFile = config.sops.templates."caddy-internal.env".path;
email = "jalle008@proton.me";
enableReload = true;
dataDir = "${cfg.configDir}/caddy";
globalConfig = ''
metrics
http_port 80
https_port 443
default_bind 0.0.0.0
'';
virtualHosts."*.${net.domain}" = {
extraConfig = ''
tls {
dns cloudflare {$CLOUDFLARE_DNS_API_TOKEN}
}
${proxyBlocks}
'';
};
};
networking.firewall.allowedTCPPorts = [
80
443
];
};
};
in
{
imports = [
caddy-internal
./sops.nix
];
}

View File

@@ -0,0 +1,39 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.services.caddy-internal;
caddyUser = config.users.users.caddy.name;
caddyGroup = config.users.users.caddy.group;
caddySecret = {
owner = caddyUser;
group = caddyGroup;
sopsFile = lib.snowfall.fs.get-file "secrets/nuc-secrets.yaml";
restartUnits = [ "caddy.service" ];
};
in
{
config = lib.mkIf cfg.enable {
sops = {
secrets = {
# Add this key to secrets/nuc-secrets.yaml:
# nuc/caddy/cloudflare-dns-api-token: <token>
"nuc/caddy/cloudflare-dns-api-token" = caddySecret;
};
templates."caddy-internal.env" = {
content = ''
CLOUDFLARE_DNS_API_TOKEN=${config.sops.placeholder."nuc/caddy/cloudflare-dns-api-token"}
'';
owner = caddyUser;
group = caddyGroup;
restartUnits = [ "caddy.service" ];
};
};
};
}