diff --git a/machines/control/configuration.nix b/machines/control/configuration.nix index 0d995a8..6f72146 100644 --- a/machines/control/configuration.nix +++ b/machines/control/configuration.nix @@ -1,10 +1,17 @@ { imports = [ ../../modules/hetzner-firewall.nix + ../../modules/static-ipv6.nix ]; clan.core.sops.defaultGroups = [ "admins" ]; + # Public IPv6; SLAAC doesn't bring it up here. + cnx.staticIPv6 = { + enable = true; + address = "2a01:4f9:c013:e6d0::1"; + }; + time.timeZone = "Etc/GMT-3"; # UTC+3 (fixed offset, no DST) services.timesyncd.enable = true; diff --git a/machines/ns1/configuration.nix b/machines/ns1/configuration.nix index b653d96..a304ceb 100644 --- a/machines/ns1/configuration.nix +++ b/machines/ns1/configuration.nix @@ -5,10 +5,17 @@ in { imports = [ ../../modules/dns/authoritative.nix + ../../modules/static-ipv6.nix ]; clan.core.sops.defaultGroups = [ "admins" ]; + # Public IPv6 (matches the ns1 AAAA glue); SLAAC doesn't bring it up here. + cnx.staticIPv6 = { + enable = true; + address = "2a01:4f8:c014:b5c5::1"; + }; + time.timeZone = "Etc/GMT-1"; # UTC+1 (fixed offset, no DST) services.timesyncd.enable = true; diff --git a/machines/ns2/configuration.nix b/machines/ns2/configuration.nix index 4b583b2..0277a31 100644 --- a/machines/ns2/configuration.nix +++ b/machines/ns2/configuration.nix @@ -5,10 +5,17 @@ in { imports = [ ../../modules/dns/authoritative.nix + ../../modules/static-ipv6.nix ]; clan.core.sops.defaultGroups = [ "admins" ]; + # Public IPv6 (matches the ns2 AAAA glue); SLAAC doesn't bring it up here. + cnx.staticIPv6 = { + enable = true; + address = "2a01:4f9:c014:6d87::1"; + }; + time.timeZone = "Etc/GMT-3"; # UTC+3 (fixed offset, no DST) services.timesyncd.enable = true; diff --git a/modules/static-ipv6.nix b/modules/static-ipv6.nix new file mode 100644 index 0000000..882e6da --- /dev/null +++ b/modules/static-ipv6.nix @@ -0,0 +1,48 @@ +# Static public IPv6 for hosts where SLAAC/RA doesn't bring up a global +# address (e.g. Hetzner, which allocates a /64 but expects you to pick one +# address yourself and route via the link-local gateway fe80::1). +{ lib, config, ... }: +let + cfg = config.cnx.staticIPv6; +in +{ + options.cnx.staticIPv6 = { + enable = lib.mkEnableOption "static public IPv6 on the primary interface"; + + address = lib.mkOption { + type = lib.types.str; + example = "2a01:4f8:c014:b5c5::1"; + description = "Public IPv6 address (no prefix length)."; + }; + + prefixLength = lib.mkOption { + type = lib.types.int; + default = 64; + description = "Prefix length of the allocated block."; + }; + + interface = lib.mkOption { + type = lib.types.str; + default = "enp1s0"; + description = "Interface to assign the address to."; + }; + + gateway = lib.mkOption { + type = lib.types.str; + default = "fe80::1"; + description = "IPv6 default gateway (Hetzner uses the link-local fe80::1)."; + }; + }; + + config = lib.mkIf cfg.enable { + networking.interfaces.${cfg.interface}.ipv6.addresses = [ + { + inherit (cfg) address prefixLength; + } + ]; + networking.defaultGateway6 = { + address = cfg.gateway; + interface = cfg.interface; + }; + }; +}