p1.1: dynamic self-IP deny (DDNS/trace, keep previous, atomic swap)

Discover WAN via ddns:<host> then trace:<url> before listen. Persist to
self_ip.json. Previous addresses stay denied for keep_previous. Failure
keeps the last known set. /healthz reports age and source.
This commit is contained in:
2026-09-22 22:59:08 -07:00
parent dca635fb62
commit 447842f860
8 changed files with 767 additions and 20 deletions
+31 -1
View File
@@ -40,6 +40,27 @@ in
'';
};
selfIP = {
sources = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "trace:https://1.1.1.1/cdn-cgi/trace" ];
description = ''
Discovery sources in order: ddns:<hostname> and/or
trace:<url>. Results that are not global unicast are ignored.
'';
};
interval = lib.mkOption {
type = lib.types.str;
default = "10m";
description = "How often to re-discover the WAN address.";
};
keepPrevious = lib.mkOption {
type = lib.types.str;
default = "24h";
description = "How long to keep a previous WAN address in the deny set.";
};
};
settings = lib.mkOption {
type = settingsFormat.type;
default = { };
@@ -63,7 +84,16 @@ in
users.groups.sift = { };
environment.etc."sift/config.toml".source = settingsFormat.generate "sift.toml" (
{ listen = cfg.listen; } // cfg.settings
{
listen = cfg.listen;
self_ip = {
sources = cfg.selfIP.sources;
interval = cfg.selfIP.interval;
keep_previous = cfg.selfIP.keepPrevious;
path = "/var/lib/sift/self_ip.json";
};
}
// cfg.settings
);
# Keys and env secrets are created on-box, never in the store.