nix/modules/networking/caddy.nix
2025-01-06 18:24:12 +01:00

198 lines
4.9 KiB
Nix

{
config,
pkgs,
lib,
...
}:
with lib;
let
cfg = config.my.networking.caddy;
in
{
options.my.networking.caddy = {
enable = lib.mkEnableOption "Enable caddy as reverse proxy";
domainsList = lib.mkOption {
type = lib.types.listOf (lib.types.attrsOf lib.types.str);
description = ''
A list of sets, each containing three parameters of type string: domain, email, and cloudflareApiKeyFile.
'';
default = [
{
domain = "example.com";
email = "user@domain.com";
cloudflareApiKeyFile = "/path/to/cloudflare/api/key";
}
];
};
# claudflareApiKeyFile = lib.mkOption {
# default = "";
# type = lib.types.str;
# description = ''
# Cloudflare API key file
# '';
# };
# domain = lib.mkOption {
# default = "example.com";
# type = lib.types.str;
# description = ''
# The domain where Caddy is reachable
# '';
# };
# email = lib.mkOption {
# default = "user@domain.com";
# type = lib.types.str;
# description = ''
# Email for Certbot
# '';
# };
};
config = lib.mkIf cfg.enable {
# Insted on relying on caddy to provide TLS, we use certbot to get a certificate
# https://aottr.dev/posts/2024/08/homelab-setting-up-caddy-reverse-proxy-with-ssl-on-nixos/
security.acme = {
acceptTerms = true;
# TESTING ONLY!
# defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
certs = lib.mkMerge (
map (domainConfig: {
"${domainConfig.domain}" = {
group = config.services.caddy.group;
email = domainConfig.email;
domain = domainConfig.domain;
extraDomainNames = [ "*.${domainConfig.domain}" ];
dnsProvider = "cloudflare";
dnsResolver = "1.1.1.1:53";
dnsPropagationCheck = true;
environmentFile = domainConfig.cloudflareApiKeyFile;
};
}) cfg.domainsList
);
# certs."${cfg.domain}" = {
# group = config.services.caddy.group;
# domain = "${cfg.domain}";
# extraDomainNames = [ "*.${cfg.domain}" ];
# dnsProvider = "cloudflare";
# dnsResolver = "1.1.1.1:53";
# dnsPropagationCheck = true;
# environmentFile = cfg.claudflareApiKeyFile;
# };
};
services.caddy = {
enable = true;
globalConfig = ''
admin :2024
servers {
metrics
}
'';
extraConfig = lib.concatStringsSep "\n" (
map (
domainConfig:
let
certPath = config.security.acme.certs."${domainConfig.domain}".directory;
in
''
(cloudflare_${domainConfig.domain}) {
tls ${certPath}/cert.pem ${certPath}/key.pem {
protocols tls1.3
}
}
''
) cfg.domainsList
);
# extraConfig =
# let
# certPath = config.security.acme.certs."${cfg.domain}".directory;
# in
# ''
# (cloudflare) {
# tls ${certPath}/cert.pem ${certPath}/key.pem {
# protocols tls1.3
# }
# }
# '';
};
systemd.services.caddy.serviceConfig = {
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
};
# By default, the module create a custom user but it lacks permission to read caddy files
systemd.services.promtail.serviceConfig = {
Group = lib.mkForce config.services.caddy.group;
User = lib.mkForce config.services.caddy.user;
};
services.promtail = {
enable = true;
configuration = {
server.http_listen_port = 9080;
server.grpc_listen_port = 0;
clients = [ { url = "http://metrics.internal:3100/loki/api/v1/push"; } ];
scrape_configs = [
{
job_name = "journal";
journal = {
max_age = "12h";
labels = {
job = "systemd-journal";
};
};
relabel_configs = [
{
source_labels = [ "__journal__systemd_unit" ];
regex = "(.*)\\.service";
target_label = "service";
}
{
source_labels = [ "__journal__hostname" ];
target_label = "hostname";
}
];
}
{
job_name = "caddy";
static_configs = [
{
targets = [ "localhost" ];
labels = {
job = "caddylogs";
__path__ = "${config.services.caddy.logDir}/*.log";
};
}
];
}
];
};
};
networking.firewall.allowedTCPPorts = [
80
443
2024
];
networking.firewall.allowedUDPPorts = [
80
443
];
};
}