From 700bca41c3f6434eba1bca2bf1e52639ce571044 Mon Sep 17 00:00:00 2001 From: = <=> Date: Sun, 19 Jan 2025 15:11:59 +0100 Subject: [PATCH] random test --- hosts/caddy/default.nix | 18 ++++- modules/networking/caddy.nix | 106 +++++++++++++------------ modules/networking/ddclient.nix | 27 +++++++ modules/networking/default.nix | 1 + modules/services/nextcloud.nix | 5 +- packages/caddy.nix | 133 ++++++++++++++++++++++++++++++++ secrets.nix | 1 + secrets/ddclient.age | 14 ++++ 8 files changed, 254 insertions(+), 51 deletions(-) create mode 100644 modules/networking/ddclient.nix create mode 100644 packages/caddy.nix create mode 100644 secrets/ddclient.age diff --git a/hosts/caddy/default.nix b/hosts/caddy/default.nix index b990bae..99cde5b 100644 --- a/hosts/caddy/default.nix +++ b/hosts/caddy/default.nix @@ -25,6 +25,10 @@ in owner = config.services.caddy.user; group = config.services.caddy.group; }; + ddclient = { + file = ../../secrets/ddclient.age; + mode = "400"; + }; }; my = { @@ -40,7 +44,7 @@ in settings = import ./dashy-settings.nix; proxy = { enable = true; - domain = tsDomain; + domain = publicDomain; host = "caddy.internal"; }; }; @@ -110,6 +114,7 @@ in caddy = { enable = true; + configEnvFile = config.age.secrets.cloudflare-pasetto-apiKey.path; domainsList = [ { domain = tsDomain; @@ -122,6 +127,17 @@ in cloudflareApiKeyFile = config.age.secrets.cloudflare-pasetto-apiKey.path; } ]; + dynamicdnsDomains = [ + { + domain = publicDomain; + cloudflareApiEnvName = "CLOUDFLARE_API_TOKEN"; + } + ]; + }; + + ddclient = { + enable = false; + configFile = config.age.secrets.ddclient.path; }; }; diff --git a/modules/networking/caddy.nix b/modules/networking/caddy.nix index 87f13bb..9a54237 100644 --- a/modules/networking/caddy.nix +++ b/modules/networking/caddy.nix @@ -28,29 +28,27 @@ in ]; }; - # claudflareApiKeyFile = lib.mkOption { - # default = ""; - # type = lib.types.str; - # description = '' - # Cloudflare API key file - # ''; - # }; + dynamicdnsDomains = lib.mkOption { + type = lib.types.listOf (lib.types.attrsOf lib.types.str); + description = '' + A list of domains to update with the dynamicdns plugin. + ''; + default = [ + { + domain = "example.com"; + cloudflareApiEnvName = "CLOUDFLARE_API_TOKEN_MY_DOMAIN"; + } + ]; + }; - # 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 - # ''; - # }; + configEnvFile = lib.mkOption { + type = lib.types.path; + description = '' + Path to the environment file that contains the secrets like Cloudflare API key. + In order to use the dynamicdns plugin, you need to set "cloudflareApiEnvName" for each domain in the dynamicdnsDomains list. + ''; + default = ""; + }; }; @@ -79,26 +77,46 @@ in }) 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 - } - ''; + + # Waiting for https://github.com/NixOS/nixpkgs/issues/14671 to be released + package = pkgs.callPackage ../../packages/caddy.nix { + externalPlugins = [ + { + name = "cloudflare"; + repo = "github.com/caddy-dns/cloudflare"; + version = "master"; + } + { + name = "dynamicdns"; + repo = "github.com/mholt/caddy-dynamicdns"; + version = "7c818ab3fc3485a72a346f85c77810725f19f9cf"; + } + ]; + vendorHash = "sha256-AWKokxGG2iCouhet5cPiKTuL9g9RQihkBRReU1nw9jc="; + }; + + globalConfig = + '' + admin :2024 + servers { + metrics + } + '' + + lib.concatStringsSep "\n" ( + map (dynamicdnsDomain: '' + dynamic_dns { + provider cloudflare {env.${dynamicdnsDomain.cloudflareApiEnvName}} + domains { + ${dynamicdnsDomain.domain} @ + } + dynamic_domains + } + '') cfg.dynamicdnsDomains + ); extraConfig = lib.concatStringsSep "\n" ( map ( @@ -116,21 +134,11 @@ in ) 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"; + EnvironmentFile = cfg.configEnvFile; }; # By default, the module create a custom user but it lacks permission to read caddy files diff --git a/modules/networking/ddclient.nix b/modules/networking/ddclient.nix new file mode 100644 index 0000000..794f541 --- /dev/null +++ b/modules/networking/ddclient.nix @@ -0,0 +1,27 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.my.networking.ddclient; +in +{ + options.my.networking.ddclient = { + enable = lib.mkEnableOption "Enable DDClient dynamic DNS client"; + configFile = lib.mkOption { + type = lib.types.path; + default = "/etc/ddclient/ddclient.conf"; + description = "Path to the ddclient configuration file (use agenix path)"; + }; + }; + + config = lib.mkIf cfg.enable { + services.ddclient = { + enable = true; + configFile = cfg.configFile; + }; + }; + +} diff --git a/modules/networking/default.nix b/modules/networking/default.nix index c398ced..802c708 100644 --- a/modules/networking/default.nix +++ b/modules/networking/default.nix @@ -2,6 +2,7 @@ imports = [ ./avahi.nix ./caddy.nix + ./ddclient.nix ./nas-samba-share.nix ./tailscale.nix ]; diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index f7fb43d..e618987 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -74,7 +74,10 @@ in overwriteProtocol = "https"; defaultPhoneRegion = "IT"; trusted_proxies = [ "192.168.1.150" ]; - trusted_domains = [ "cloud.${cfg.proxy.domain}" ]; + trusted_domains = [ + "cloud.${cfg.proxy.domain}" + "nextcloud.internal" + ]; maintenance_window_start = 1; enabledPreviewProviders = [ "OC\\Preview\\BMP" diff --git a/packages/caddy.nix b/packages/caddy.nix new file mode 100644 index 0000000..36ab38b --- /dev/null +++ b/packages/caddy.nix @@ -0,0 +1,133 @@ +{ + lib, + buildGoModule, + fetchFromGitHub, + gnused, + nixosTests, + caddy, + testers, + installShellFiles, + externalPlugins ? [ ], + vendorHash ? "sha256-G7danupoc7BRyJJWzzyRP6CSOShA+oCLcUWMCnrLF2c=", +}: + +let + attrsToModules = + attrs: + builtins.map ( + { + name, + repo, + version, + }: + "${repo}" + ) attrs; + attrsToSources = + attrs: + builtins.map ( + { + name, + repo, + version, + }: + "${repo}@${version}" + ) attrs; +in +buildGoModule rec { + pname = "caddy"; + version = "2.8.4"; + + dist = fetchFromGitHub { + owner = "caddyserver"; + repo = "dist"; + rev = "v${version}"; + hash = "sha256-O4s7PhSUTXoNEIi+zYASx8AgClMC5rs7se863G6w+l0="; + }; + + src = fetchFromGitHub { + owner = "caddyserver"; + repo = "caddy"; + rev = "v${version}"; + hash = "sha256-th0R3Q1nGT0q5PGOygtD1/CpJmrT5TYagrwQR4t/Fvg="; + }; + + inherit vendorHash; + + subPackages = [ "cmd/caddy" ]; + + ldflags = [ + "-s" + "-w" + "-X github.com/caddyserver/caddy/v2.CustomVersion=${version}" + ]; + + nativeBuildInputs = [ + gnused + installShellFiles + ]; + + modBuildPhase = '' + export GOPROXY=https://proxy.golang.org,direct + for module in ${builtins.toString (attrsToModules externalPlugins)}; do + sed -i "/standard/a _ \"$module\"" ./cmd/caddy/main.go + done + for plugin in ${builtins.toString (attrsToSources externalPlugins)}; do + go get $plugin + done + + go mod tidy + go mod vendor + ''; + + modInstallPhase = '' + mv -t vendor go.mod go.sum + cp -r --reflink=auto vendor "$out" + ''; + + preBuild = '' + export GOPROXY=https://proxy.golang.org,direct + chmod -R u+w vendor + [ -f vendor/go.mod ] && mv -t . vendor/go.{mod,sum} + go mod tidy + go mod vendor + + for module in ${builtins.toString (attrsToModules externalPlugins)}; do + sed -i "/standard/a _ \"$module\"" ./cmd/caddy/main.go + done + ''; + + postInstall = '' + install -Dm644 ${dist}/init/caddy.service ${dist}/init/caddy-api.service -t $out/lib/systemd/system + + substituteInPlace $out/lib/systemd/system/caddy.service --replace "/usr/bin/caddy" "$out/bin/caddy" + substituteInPlace $out/lib/systemd/system/caddy-api.service --replace "/usr/bin/caddy" "$out/bin/caddy" + + $out/bin/caddy manpage --directory manpages + installManPage manpages/* + + installShellCompletion --cmd caddy \ + --bash <($out/bin/caddy completion bash) \ + --fish <($out/bin/caddy completion fish) \ + --zsh <($out/bin/caddy completion zsh) + ''; + + passthru.tests = { + inherit (nixosTests) caddy; + version = testers.testVersion { + command = "${caddy}/bin/caddy version"; + package = caddy; + }; + }; + + meta = with lib; { + homepage = "https://caddyserver.com"; + description = "Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS"; + license = licenses.asl20; + mainProgram = "caddy"; + maintainers = with maintainers; [ + Br1ght0ne + emilylange + techknowlogick + ]; + }; +} diff --git a/secrets.nix b/secrets.nix index 097dccb..7e619af 100644 --- a/secrets.nix +++ b/secrets.nix @@ -5,6 +5,7 @@ let tailscale-authKey = keys.tailscale-machine; cloudflare-tegola-apiKey = [ machines.caddy ]; cloudflare-pasetto-apiKey = [ machines.caddy ]; + ddclient = [ machines.caddy ]; prowlarr-apiKey = [ machines.metrics ]; radarr-apiKey = [ machines.metrics ]; sonarr-apiKey = [ machines.metrics ]; diff --git a/secrets/ddclient.age b/secrets/ddclient.age new file mode 100644 index 0000000..0207384 --- /dev/null +++ b/secrets/ddclient.age @@ -0,0 +1,14 @@ +age-encryption.org/v1 +-> ssh-ed25519 BFt3Fg V592tfQs3NGe0RTfuhHMYS6+U+gG2RDlDVnGss74NwE +C6Y9G/1IH+sAvwhk1KqwEndk9FJsryACHxqIxuxZDSc +-> ssh-ed25519 Si3UKw h4D16GDdK9FdxGShnAdLGPg/goYI1KxY/fv2fR3+ZEw +gPrMQMbUVuxUo1Hepfp5v1VelbSq3Ifn1qevbRpyDzw +-> ssh-ed25519 3UG3uw c+M+7Kd543yfm3NepTB8E+bFTDDjnaTpewVWOHpA+G4 +Fd5347c5T6sUPh9FcI8CfUAFuN9lDb3ECxSnY2dTOjM +-> ssh-ed25519 JEhtoQ NFc9817/+yC8kDjVK4pqe1GjVpR//ir1AEOYRdw7JQg +0kuRWYoYQdjMrFfZNwbv84drvhbO87cKR9qGS40Jziw +-> ssh-ed25519 uqg2jw VOVdPXHOr3mlj6G/0FDxhs9vsebyryGBBM8vnZnV5S0 +fXJzimWwQsnfghP1qlKJsC7r7TKR8m1mS420v3H8btg +--- 0M9C1phUBuVyf75w2BKBmiQ77z+I6Jzgv1uoozOpAPI +G7ƭ^42.k ?ofMG{qA}jk+1|I 9<"в{a$Ybh6шoh +bD⥭wKGլ꘥o!X|ǔzM=F(07u95 ihq/gw P]i1XW5k*L v*B \ No newline at end of file