{ config, pkgs, lib, ... }: with lib; let cfg = config.my.networking.caddy; in { options.my.networking.caddy = { enable = lib.mkEnableOption "Enable caddy as reverse proxy"; 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 { age.secrets = { cloudflare-tegola-apiKey = { file = ../../secrets/cloudflare-tegola-apiKey.age; owner = config.services.caddy.user; group = config.services.caddy.group; }; }; # 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; defaults.email = cfg.email; # TESTING ONLY! # defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory"; 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 = config.age.secrets.cloudflare-tegola-apiKey.path; }; }; services.caddy = { enable = true; globalConfig = '' admin :2024 servers { metrics } ''; 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 ]; }; }