caddy int
This commit is contained in:
107
modules/nixos/services/caddy-internal/default.nix
Normal file
107
modules/nixos/services/caddy-internal/default.nix
Normal 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
|
||||
];
|
||||
}
|
||||
39
modules/nixos/services/caddy-internal/sops.nix
Normal file
39
modules/nixos/services/caddy-internal/sops.nix
Normal 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" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -6,6 +6,8 @@ nuc:
|
||||
nuc-nixos-cert: ENC[AES256_GCM,data:lRB9M1D7xMjf/XNxljM7wPitZzY8105Hu6GmmaBgenWIsewIoSfk3tTMwFEe8nzp2jraOzcurTEujl++YOy46S0FDg3bPzdlXBwWZw12F6akfgGTGl8XX7BB7vu9UiQ8stpgUd+6G8NhNmbmVw/0oDnEsSfd4KiJgyf8Hfd9wOBhw+xZEVzHJ+D98ixChH5RB1CyFDpK1qrU9+K7GhsRFEQQdIkr4Xv6ZKnQfcB/uuwQ9Po1vFyfZRmRbRrcYFWIhJSoBr7YY5Kn5LXJxpWPDLZGNe7zibE11J09gXBRXB2Oni2G7TEsNiMlY2w4SA4aBpVngyitw9So7hzwSPX+JCYZnHr3nBCDvkWaECvju9i6pclnuuEN4PFXghaxy3QOweWA4l1DF1jrgdQ+XU8VJk4H,iv:ZdGsr5AldRJYvoG+tXW2cnS7iEs4C14qjp7hQRNdKcI=,tag:fC/DbuFeSWA0vtn9fTV7bg==,type:str]
|
||||
nuc-nixos-key: ENC[AES256_GCM,data:7VhntGkRDoXulB9FNelvF0YwxriuVCpUCb43V33LlCRI8dizGIGtayr4g4hwg88rdgGBZMIzpG0MrR65DhLriR+yJAuvgHBuNHb/IOt9x0Jjo4a5g9r4wwMjcj8TBFM0FiFh5oSysY/S6VYJif7aBTnqGWvrwyfWIuDOD7MWfQ==,iv:rVlATexxX7k9jrk6i11+Wgy6GhWKxTYkBBlGAqOAtMQ=,tag:YHELFmDNyHq1amjYQgTWTQ==,type:str]
|
||||
ca-cert: ENC[AES256_GCM,data:ZXmAZdQ0BSGJB5IZ2VJx9IxrrNTqmEYGYKua0gk61/EOnebMp5yg+swKl94+pmFWtqwKlaH+jaChAqYchONHGxOt55AAAlhGzM7BzoUseWdjTf0mFRq4Kr49Tjsz1iOK5XHr8aLESF2E3RkBRi5r0MzstutuagSO59Dj74ZT176sMYWiT7yjPXBgxlLuROQGHBV1/l+N8AMt9M2OLp/0+QYcwSrDh3u8Ts82d9YMODcbNbnCaeo64xmHLW7jJBkDTeH89rfWA5hE+haqUDv/BWe1mBvkV0YIJceyfPZdku0+hOdUIw1iXOTH9Q3KTL5FR9i7lRrCz/ZJzOVrNA==,iv:Td7TBKn+5/1V3WblVwaWjYTOZXMvJ/SMSoUnrNXdAOU=,tag:6YDpTM9kADs2KHKERNeVFQ==,type:str]
|
||||
caddy:
|
||||
cloudflare-dns-api-token: ENC[AES256_GCM,data:QMbo5KFej5MVIpWeWr+B4msS1dUPTtinKNJER44FPiKMNiFzkfGa4w==,iv:h18CzpdvPNOx/IWKEyuNlGmltdBeTUx4i8VMs0Dz8z0=,tag:Ke8nakp2VA/YSAH5Mvf9sQ==,type:str]
|
||||
sops:
|
||||
shamir_threshold: 1
|
||||
age:
|
||||
@@ -153,8 +155,8 @@ sops:
|
||||
WFJONHNsUjJuditvVEgxQ0Y1RVhXQ1kKwBM8ljdCTTbjdasCdtLj4wZ+fX2XQIXf
|
||||
IMgacJ5kxYHaYpNpY5wyK2kHzPY9Ovz75WyXicPj0SCojhoKvMAWXQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-03-24T14:25:23Z"
|
||||
mac: ENC[AES256_GCM,data:H50AiSWZ3gzFw4EOfwQE2Z7D2Uj4ZqMbMdcOEY3umoA0wzN2JRBJuIU599tV+bRI4SqlJ/vsSDuoLEqxbDR1ZJfLTLzFxFOfr8kkj7bir1tkRWZPY6pkNBsIteWeaJktXyCodCRxaDuDiKNWlD3+tA5+X3Wjhg4RcAAQ+F18gkk=,iv:SffLSph1FL9Yg915VctG+TRJ/3aoJ3D1wBFiPS2MbAc=,tag:JQJ+rRPftBAeyKtUD+JQ2A==,type:str]
|
||||
lastmodified: "2026-04-09T19:46:52Z"
|
||||
mac: ENC[AES256_GCM,data:sQm090y8Txfg/DATQZxhYTPFSKGne5tk9534EOmddLQo4PWFRy5FdssCU7L9gCrcWy2x/hRPq57vNgOSvXrU/JNS3Q/lC2xR8G5cFiwFTg+efXoiS4dnJnAkO8i+IROuh3kbAy0rsECcW8yQS2A1aEXi52hfEkMFrCd9nfX0BmY=,iv:HdjMqLqcztzntb2ChVxcj91KcnP3jYFNhHR8ezgoOkk=,tag:4yPrEKw+I+ECAWrCq0M+2Q==,type:str]
|
||||
pgp:
|
||||
- created_at: "2026-02-06T15:34:31Z"
|
||||
enc: |-
|
||||
@@ -177,4 +179,4 @@ sops:
|
||||
-----END PGP MESSAGE-----
|
||||
fp: CBCB9B18A6B8930B0B6ABFD1CCB8CBEB30633684
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.12.1
|
||||
version: 3.12.2
|
||||
|
||||
@@ -64,6 +64,26 @@ in
|
||||
security.tpm.enable = true;
|
||||
|
||||
services = {
|
||||
caddy-internal = {
|
||||
enable = true;
|
||||
proxies = {
|
||||
esphome = {
|
||||
subdomain = "esphome";
|
||||
upstream = "http://127.0.0.1:${toString net.ports.nuc.esphome}";
|
||||
};
|
||||
otbr = {
|
||||
subdomain = "otbr";
|
||||
upstream = "http://127.0.0.1:${toString net.ports.nuc.otbr}";
|
||||
};
|
||||
# hass is currently proxied by the NAS Caddy (modules/nixos/services/caddy).
|
||||
# To migrate it here, remove the @hass block from that module and add:
|
||||
# hass = {
|
||||
# subdomain = "hass";
|
||||
# upstream = "http://127.0.0.1:${toString net.ports.nuc.homeAssistant}";
|
||||
# };
|
||||
};
|
||||
};
|
||||
|
||||
home-assistant = {
|
||||
enable = true;
|
||||
automation = {
|
||||
|
||||
Reference in New Issue
Block a user