From 64d15d3b5b81452a6066bd4e480ca4b3b5649f4a Mon Sep 17 00:00:00 2001 From: Peter Rice Date: Mon, 16 Feb 2026 15:46:25 -0500 Subject: [PATCH] yggdrasil: dynamic ports and tests for endpoints --- modules/nixos/interface.nix | 8 ++-- modules/nixos/yggdrasil/endpoints.nix | 66 +++++++++++++++++++-------- modules/nixos/yggdrasil/network.nix | 1 - modules/services/miniflux.nix | 8 +++- modules/services/weather.nix | 5 +- 5 files changed, 61 insertions(+), 27 deletions(-) diff --git a/modules/nixos/interface.nix b/modules/nixos/interface.nix index db1eb4d..4f755b8 100644 --- a/modules/nixos/interface.nix +++ b/modules/nixos/interface.nix @@ -1,14 +1,14 @@ -{ lib, ... }: { - flake.modules.nixos.core = - { config, ... }: + { config, lib, ... }: { options.local.ethernetInterface = lib.mkOption { default = let interfaces = - config.networking.interfaces |> builtins.attrNames |> builtins.filter (lib.hasPrefix "enp"); + lib.attrByPath [ "hardware" "network_interface" ] [ ] config.hardware.facter.report + |> map (interface: interface.unix_device_names |> builtins.head) + |> builtins.filter (lib.hasPrefix "enp"); in if interfaces == [ ] then "eth0" else builtins.head interfaces; }; diff --git a/modules/nixos/yggdrasil/endpoints.nix b/modules/nixos/yggdrasil/endpoints.nix index 01f0c8e..a774f9f 100644 --- a/modules/nixos/yggdrasil/endpoints.nix +++ b/modules/nixos/yggdrasil/endpoints.nix @@ -4,23 +4,23 @@ let in { flake.modules.nixos.core = - { config, ... }: + { config, pkgs, ... }: let - inherit (config.local) prefix endpoints; - # from https://wiki.nixos.org/wiki/Yggdrasil#Virtual-hosts - toIpv6Address = - seed: - let - digest = builtins.hashString "sha256" seed; - hextets = builtins.genList (i: builtins.substring (4 * i) 4 digest) 4; - in - builtins.concatStringsSep ":" ([ prefix ] ++ hextets); + cfg = config.local; in { options.local.endpoints = lib.mkOption { type = lib.types.attrsOf ( lib.types.submodule ( { name, ... }: + let + # from https://wiki.nixos.org/wiki/Yggdrasil#Virtual-hosts + digest = builtins.hashString "sha256" name; + hextets = builtins.genList (i: builtins.substring (4 * i) 4 digest) 4; + minPort = 18000; + maxPort = 18999; + inherit (builtins.fromTOML "rand = 0x${builtins.substring 0 8 digest}") rand; + in { options = { public = lib.mkOption { @@ -29,7 +29,11 @@ in }; address = lib.mkOption { type = lib.types.str; - default = toIpv6Address name; + default = builtins.concatStringsSep ":" ([ cfg.prefix ] ++ hextets); + }; + port = lib.mkOption { + type = lib.types.port; + default = minPort + lib.mod rand (maxPort - minPort); }; }; } @@ -38,14 +42,35 @@ in default = { }; }; - config.environment.etc."systemd/network/40-${config.local.ethernetInterface}.network.d/extra-yggdrasil-ips.conf" = - lib.mkIf (endpoints != { }) { - text = - "[Network]\n" - + lib.concatMapStringsSep "\n" (endpoint: "Address=${endpoint.address}/64") ( - lib.attrValues endpoints - ); - }; + config = lib.mkIf (cfg.endpoints != { }) { + networking.firewall.interfaces.${cfg.ethernetInterface}.allowedTCPPorts = + cfg.endpoints |> builtins.attrValues |> map (builtins.getAttr "port"); + + networking.interfaces.${cfg.ethernetInterface}.ipv6.addresses = + cfg.endpoints + |> builtins.attrValues + |> map ( + { address, ... }: + { + inherit address; + prefixLength = 64; + } + ); + + local.testScript = '' + interface = machine.succeed( + "networkctl status --json short | " \ + "${pkgs.jq}/bin/jq -r '.Interfaces[].Name' | " \ + "grep -E '^e(n|th)' | head -1" + ).strip() + endpoints = ${cfg.endpoints |> builtins.attrValues |> builtins.length |> toString} + machine.wait_until_succeeds( + f"networkctl status {interface} --json short | " \ + f"${pkgs.jq}/bin/jq '.Addresses | length' | grep {endpoints + 1}", + timeout=30 + ) + ''; + }; }; flake.modules.nixos.yggdrasilNameServer.networking.hosts = lib.concatMapAttrs ( @@ -61,7 +86,8 @@ in host.config.local.endpoints |> lib.filterAttrs (_: vhost: vhost.public != null) |> lib.mapAttrs' ( - name: vhost: lib.nameValuePair vhost.public "${name}.${host.config.networking.fqdn}:2808" + name: vhost: + lib.nameValuePair vhost.public "${name}.${host.config.networking.fqdn}:${toString vhost.port}" ) ) hosts; diff --git a/modules/nixos/yggdrasil/network.nix b/modules/nixos/yggdrasil/network.nix index db6d686..2f7cd15 100644 --- a/modules/nixos/yggdrasil/network.nix +++ b/modules/nixos/yggdrasil/network.nix @@ -16,7 +16,6 @@ in environment.persistence.nixos.files = [ keyPath ]; networking.firewall.interfaces.ygg0.allowedTCPPorts = [ 22 ]; - networking.firewall.allowedTCPPorts = [ 2808 ]; local.testScript = "machine.wait_for_unit('yggdrasil.service')"; }; diff --git a/modules/services/miniflux.nix b/modules/services/miniflux.nix index a8e4cc4..bb1f1e8 100644 --- a/modules/services/miniflux.nix +++ b/modules/services/miniflux.nix @@ -1,6 +1,10 @@ +{ lib, ... }: { local.desktops.ruan = { config, pkgs, ... }: + let + endpoint = config.local.endpoints.rss; + in { local.endpoints.rss.public = "rss.peterrice.xyz"; @@ -10,11 +14,13 @@ services.miniflux = { enable = true; - config.LISTEN_ADDR = "[${config.local.endpoints.rss.address}]:2808"; + config.LISTEN_ADDR = "[${endpoint.address}]:${toString endpoint.port}"; adminCredentialsFile = config.age.secrets."miniflux-credentials".path; }; services.postgresql.package = pkgs.postgresql_16; environment.persistence.nixos.directories = [ "/var/lib/postgresql" ]; }; + + flake.modules.nixos.test.services.miniflux.enable = lib.mkForce false; } diff --git a/modules/services/weather.nix b/modules/services/weather.nix index 3a7cbc2..9a81140 100644 --- a/modules/services/weather.nix +++ b/modules/services/weather.nix @@ -2,6 +2,9 @@ { local.desktops.ruan = { config, ... }: + let + endpoint = config.local.endpoints.rss; + in { imports = [ inputs.weather.nixosModules.default ]; @@ -9,7 +12,7 @@ services = { weather.enable = true; - weather.bind = "[${config.local.endpoints.weather.address}]:2808"; + weather.bind = "[${endpoint.address}]:${toString endpoint.port}"; }; }; } -- 2.51.2