Update the home-manager new hash.

Added dynamic public IPv4 address updater to traefik.
This commit is contained in:
Root User 2026-03-03 10:42:04 +01:00
parent 6d11b57c61
commit 140935c120
Signed by: root
GPG key ID: 087F0A95E5766D72
2 changed files with 143 additions and 1 deletions

View file

@ -6,7 +6,7 @@
}: let
home-manager = builtins.fetchTarball {
url = "https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz";
sha256 = "1kqxy6r4ahnbazmpa4pncdp62najdikdaw8hvrv8nl6qxvbmf9fy";
sha256 = "8C+y46xA9bxcchj9GeDPJaRUDApaA3sy2fhJr1bTbUw=";
};
cfg = config.services.forgejo;
srv = cfg.settings.server;

View file

@ -5,6 +5,39 @@
...
}: let
choose = paths: builtins.head (builtins.filter (p: builtins.pathExists p) paths);
# Package the upstream cloudflare-ddns-updater from GitHub into the Nix store
upstreamOwner = "K0p1-Git";
upstreamRepo = "cloudflare-ddns-updater";
upstreamRev = "e9906c3aa0b73c26e3473618ad7a69db853e669d";
upstreamSrc = pkgs.fetchFromGitHub {
owner = upstreamOwner;
repo = upstreamRepo;
rev = upstreamRev;
sha256 = "0j1pv57hk9rhr1kxqqjxg71y0d2d1hi3b4yiq908x5kcv3abbina";
};
cloudflare-ddns-pkg = pkgs.stdenv.mkDerivation {
pname = "cloudflare-ddns-updater";
version = upstreamRev;
src = upstreamSrc;
# no build required for a script-only repo
buildPhase = '': '';
installPhase = ''
mkdir -p $out/bin $out/lib/cloudflare-ddns
cp -r $src/* $out/lib/cloudflare-ddns/ || true
if [ -x "$out/lib/cloudflare-ddns/update.sh" ]; then
cp "$out/lib/cloudflare-ddns/update.sh" $out/bin/cloudflare-ddns
chmod +x $out/bin/cloudflare-ddns
else
# If upstream layout changes, keep the repo contents available under $out/lib
true
fi
'';
meta = with pkgs.lib; {
description = "Cloudflare DDNS updater";
license = licenses.mit;
};
};
in {
options.local = {
hostname = lib.mkOption {
@ -562,6 +595,115 @@ in {
};
};
# PRG Cloudflare DDNS updater
environment.etc."cloudflare-ddns/update.sh" = {
text = let
domain = "prg-radio.org";
records = ["git" "grafana" "anubis" "wavelog" "partdb" "mail" "mailadmin" "@"];
recordsStr = lib.concatStringsSep " " records;
zoneId = "9fde8d0fa53502f2d1b7e0b1d3765d49";
envFile = "/home/traefikprg/cloudflare/cloudflare.env";
in ''
#!/usr/bin/env bash
set -euuo pipefail
# Load environment variables (must contain CLOUDFLARE_API_TOKEN)
if [ -f "${envFile}" ]; then
# shellcheck disable=SC1090
source "${envFile}"
fi
if [ -z "$CLOUDFLARE_API_TOKEN" ]; then
echo "CLOUDFLARE_API_TOKEN is not set in ${envFile}, aborting" >&2
exit 2
fi
API_BASE="https://api.cloudflare.com/client/v4"
# get current public IPv4
CURRENT_IP=$(curl -4 -sS https://ipv4.icanhazip.com | tr -d '\n') || true
if [ -z "$CURRENT_IP" ]; then
echo "Failed to detect public IPv4 address" >&2
exit 3
fi
jq=${pkgs.jq}/bin/jq
update_or_create() {
local fqdn="$1"
# Query existing A records for fqdn
res=$(curl -sS -X GET "$API_BASE/zones/${zoneId}/dns_records?type=A&name=$fqdn" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json")
ok=$(echo "$res" | $jq -r '.success')
if [ "$ok" != "true" ]; then
echo "Cloudflare API query failed for $fqdn: $res" >&2
return 1
fi
existing_ip=$(echo "$res" | $jq -r '.result[0].content // empty')
record_id=$(echo "$res" | $jq -r '.result[0].id // empty')
if [ -n "$existing_ip" ] && [ "$existing_ip" = "$CURRENT_IP" ]; then
echo "$fqdn is already set to $CURRENT_IP, skipping"
return 0
fi
payload=$(cat <<JSON
{"type":"A","name":"$fqdn","content":"$CURRENT_IP","ttl":1,"proxied":false}
JSON
)
if [ -n "$record_id" ]; then
echo "Updating $fqdn ($record_id) -> $CURRENT_IP"
curl -sS -X PUT "$API_BASE/zones/${zoneId}/dns_records/$record_id" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data "$payload" | $jq -r '.'
else
echo "Creating record $fqdn -> $CURRENT_IP"
curl -sS -X POST "$API_BASE/zones/${zoneId}/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data "$payload" | $jq -r '.'
fi
}
echo "Starting PRG Cloudflare DDNS updater: setting IP=$CURRENT_IP"
for r in ${recordsStr}; do
if [ "$r" = "@" ]; then
fqdn="${domain}"
else
fqdn="$r.${domain}"
fi
update_or_create "$fqdn" || true
done
'';
mode = "0755";
group = "root";
};
systemd.services."prg-cloudflare-ddns-updater" = {
description = "PRG Cloudflare DDNS updater";
wantedBy = ["multi-user.target"];
serviceConfig = {
Type = "oneshot";
EnvironmentFile = "/home/traefikprg/cloudflare/cloudflare.env";
ExecStart = "${pkgs.bash}/bin/bash /etc/cloudflare-ddns/update.sh";
};
};
systemd.timers."prg-cloudflare-ddns-updater" = {
description = "Run PRG Cloudflare DDNS updater periodically";
wantedBy = ["timers.target"];
timerConfig = {
OnBootSec = "1m";
OnUnitActiveSec = "10m";
Persistent = true;
};
};
# Enable Tailscale for remote access to Traefik dashboard and configuration
services.tailscale.enable = true;