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-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]
|
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]
|
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:
|
sops:
|
||||||
shamir_threshold: 1
|
shamir_threshold: 1
|
||||||
age:
|
age:
|
||||||
@@ -153,8 +155,8 @@ sops:
|
|||||||
WFJONHNsUjJuditvVEgxQ0Y1RVhXQ1kKwBM8ljdCTTbjdasCdtLj4wZ+fX2XQIXf
|
WFJONHNsUjJuditvVEgxQ0Y1RVhXQ1kKwBM8ljdCTTbjdasCdtLj4wZ+fX2XQIXf
|
||||||
IMgacJ5kxYHaYpNpY5wyK2kHzPY9Ovz75WyXicPj0SCojhoKvMAWXQ==
|
IMgacJ5kxYHaYpNpY5wyK2kHzPY9Ovz75WyXicPj0SCojhoKvMAWXQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2026-03-24T14:25:23Z"
|
lastmodified: "2026-04-09T19:46:52Z"
|
||||||
mac: ENC[AES256_GCM,data:H50AiSWZ3gzFw4EOfwQE2Z7D2Uj4ZqMbMdcOEY3umoA0wzN2JRBJuIU599tV+bRI4SqlJ/vsSDuoLEqxbDR1ZJfLTLzFxFOfr8kkj7bir1tkRWZPY6pkNBsIteWeaJktXyCodCRxaDuDiKNWlD3+tA5+X3Wjhg4RcAAQ+F18gkk=,iv:SffLSph1FL9Yg915VctG+TRJ/3aoJ3D1wBFiPS2MbAc=,tag:JQJ+rRPftBAeyKtUD+JQ2A==,type:str]
|
mac: ENC[AES256_GCM,data:sQm090y8Txfg/DATQZxhYTPFSKGne5tk9534EOmddLQo4PWFRy5FdssCU7L9gCrcWy2x/hRPq57vNgOSvXrU/JNS3Q/lC2xR8G5cFiwFTg+efXoiS4dnJnAkO8i+IROuh3kbAy0rsECcW8yQS2A1aEXi52hfEkMFrCd9nfX0BmY=,iv:HdjMqLqcztzntb2ChVxcj91KcnP3jYFNhHR8ezgoOkk=,tag:4yPrEKw+I+ECAWrCq0M+2Q==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2026-02-06T15:34:31Z"
|
- created_at: "2026-02-06T15:34:31Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
@@ -177,4 +179,4 @@ sops:
|
|||||||
-----END PGP MESSAGE-----
|
-----END PGP MESSAGE-----
|
||||||
fp: CBCB9B18A6B8930B0B6ABFD1CCB8CBEB30633684
|
fp: CBCB9B18A6B8930B0B6ABFD1CCB8CBEB30633684
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.12.1
|
version: 3.12.2
|
||||||
|
|||||||
@@ -64,6 +64,26 @@ in
|
|||||||
security.tpm.enable = true;
|
security.tpm.enable = true;
|
||||||
|
|
||||||
services = {
|
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 = {
|
home-assistant = {
|
||||||
enable = true;
|
enable = true;
|
||||||
automation = {
|
automation = {
|
||||||
|
|||||||
Reference in New Issue
Block a user