nixos-config/modules/system/services/caddy.nix

115 lines
3.1 KiB
Nix

{
config,
pkgs,
lib,
...
}:
let
caddyWithTailscale = pkgs.caddy.withPlugins {
plugins = [ "github.com/tailscale/caddy-tailscale@v0.0.0-20250508175905-642f61fea3cc" ];
hash = "sha256-bw2ZH+XTQlyYw5LgkVr+oEeL8Nf4j/KO2XQIUrsVpiU=";
};
virtualHosts =
config.custom.services.caddy.virtualHosts |> lib.filterAttrs (_: value: value.enable);
isTailscaleDomain = domain: domain |> lib.hasSuffix config.custom.services.tailscale.domain;
tailscaleHostsExist =
virtualHosts |> lib.attrValues |> lib.any (value: isTailscaleDomain value.domain);
nonTailscaleHostsExist =
virtualHosts |> lib.attrValues |> lib.any (value: !isTailscaleDomain value.domain);
getSubdomain = domain: domain |> lib.splitString "." |> lib.head;
mkVirtualHostConfig =
{
domain,
port,
extraReverseProxyConfig,
...
}:
{
logFormat = "output file ${config.services.caddy.logDir}/access-${domain}.log { mode 640 }";
extraConfig = ''
${lib.optionalString (isTailscaleDomain domain) "bind tailscale/${getSubdomain domain}"}
reverse_proxy localhost:${builtins.toString port} ${
lib.optionalString (extraReverseProxyConfig != "") "{ ${extraReverseProxyConfig} }"
}
'';
};
ports = [
80
443
];
in
{
options.custom.services.caddy.virtualHosts = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
enable = lib.mkEnableOption "" // {
default = true;
};
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = name;
};
port = lib.mkOption {
type = lib.types.port;
default = null;
};
tls = lib.mkEnableOption "" // {
default = true;
};
extraReverseProxyConfig = lib.mkOption {
type = lib.types.lines;
default = "";
};
};
}
)
);
default = { };
};
config = lib.mkIf (virtualHosts != { }) (
lib.mkMerge [
{
meta.ports.tcp.list = lib.mkIf nonTailscaleHostsExist ports;
networking.firewall.allowedTCPPorts = lib.mkIf nonTailscaleHostsExist ports;
services.caddy = {
enable = true;
enableReload = false;
globalConfig = "admin off";
virtualHosts =
virtualHosts
|> lib.mapAttrs' (
_: value:
lib.nameValuePair ((lib.optionalString (!value.tls) "http://") + value.domain) (
mkVirtualHostConfig value
)
);
};
}
(lib.mkIf tailscaleHostsExist {
sops.secrets."tailscale/service-auth-key".owner = config.services.caddy.user;
services.caddy = {
package = caddyWithTailscale;
globalConfig = ''
tailscale {
auth_key {file.${config.sops.secrets."tailscale/service-auth-key".path}}
}
'';
};
})
]
);
}