refactor(nixos): model route protocols explicitly

This commit is contained in:
2026-10-04 23:50:19 -04:00
parent a7db0b745c
commit b55508276a
4 changed files with 68 additions and 50 deletions

View File

@@ -78,7 +78,8 @@
enable = true; enable = true;
route = { route = {
domain = "valheim.alexion.dev"; domain = "valheim.alexion.dev";
udp.ports = [ protocol = "udp";
ports = [
config.guests.valheim.port config.guests.valheim.port
(config.guests.valheim.port + 1) (config.guests.valheim.port + 1)
]; ];
@@ -101,7 +102,8 @@
enable = true; enable = true;
route = { route = {
domain = "palworld.alexion.dev"; domain = "palworld.alexion.dev";
udp.ports = [ config.guests.palworld.port ]; protocol = "udp";
ports = [ config.guests.palworld.port ];
}; };
}; };
}; };
@@ -116,6 +118,7 @@
enable = true; enable = true;
route = { route = {
domain = "budget.alexion.dev"; domain = "budget.alexion.dev";
protocol = "https";
port = 5006; port = 5006;
}; };
}; };
@@ -132,6 +135,7 @@
enable = true; enable = true;
route = { route = {
domain = "music.alexion.dev"; domain = "music.alexion.dev";
protocol = "https";
port = 4533; port = 4533;
}; };
}; };
@@ -152,7 +156,8 @@
enable = true; enable = true;
route = { route = {
domain = "home"; domain = "home";
http.port = 8082; protocol = "http";
port = 8082;
}; };
}; };
}; };
@@ -167,6 +172,7 @@
enable = true; enable = true;
route = { route = {
domain = "files.alexion.dev"; domain = "files.alexion.dev";
protocol = "https";
port = 3923; port = 3923;
}; };
trustedSources = [ "${registry.address.${config.networking.hostName}."reverse-proxy"}/32" ]; trustedSources = [ "${registry.address.${config.networking.hostName}."reverse-proxy"}/32" ];

View File

@@ -71,12 +71,12 @@ let
if item.homepage.href != null then if item.homepage.href != null then
item.homepage.href item.homepage.href
else if (item.composite.route or null) != null then else if (item.composite.route or null) != null then
if item.composite.route.port != null then if item.composite.route.protocol == "https" then
"https://${item.composite.route.domain}" "https://${item.composite.route.domain}"
else if item.composite.route.http.port != null then else if item.composite.route.protocol == "http" then
"http://${item.composite.route.domain}" "http://${item.composite.route.domain}"
else else
throw "${mkRegistryPath "homepage" item.host item.entry} needs href or a matching TCP route entry" throw "${mkRegistryPath "homepage" item.host item.entry} needs href or a matching HTTP route entry"
else else
throw "${mkRegistryPath "homepage" item.host item.entry} needs href or a matching route entry"; throw "${mkRegistryPath "homepage" item.host item.entry} needs href or a matching route entry";

View File

@@ -11,7 +11,9 @@ let
lib.mapAttrsToList ( lib.mapAttrsToList (
host: routes: host: routes:
lib.concatLists ( lib.concatLists (
lib.mapAttrsToList (entry: route: map (mkUdpStream host entry) route.udp.ports) routes lib.mapAttrsToList (
entry: route: lib.optionals (route.protocol == "udp") (map (mkUdpStream host entry) route.ports)
) routes
) )
) registry.route ) registry.route
); );
@@ -75,7 +77,7 @@ let
lib.mapAttrsToList ( lib.mapAttrsToList (
host: routes: host: routes:
lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "https") ( lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "https") (
lib.filterAttrs (_entry: route: route.port != null) routes lib.filterAttrs (_entry: route: route.protocol == "https") routes
) )
) registry.route ) registry.route
); );
@@ -89,7 +91,7 @@ let
or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}"); or (throw "no matching entry in registry.address for ${mkRegistryPath "route" host entry}");
compositeEntry = registry.join host entry; compositeEntry = registry.join host entry;
inherit (compositeEntry) route; inherit (compositeEntry) route;
port = if isHttp then route.http.port else route.port; inherit (route) port;
in in
{ {
inherit host entry; inherit host entry;
@@ -108,7 +110,7 @@ let
lib.mapAttrsToList ( lib.mapAttrsToList (
host: routes: host: routes:
lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "http") ( lib.mapAttrsToList (entry: _route: mkVirtualHost host entry "http") (
lib.filterAttrs (_entry: route: route.http.port != null) routes lib.filterAttrs (_entry: route: route.protocol == "http") routes
) )
) registry.route ) registry.route
); );

View File

@@ -1,4 +1,48 @@
{ lib, util, ... }: { lib, util, ... }:
let
webRoute =
routeType
[
"http"
"https"
]
{
port = lib.mkOption {
type = lib.types.port;
example = 3923;
description = "HTTP backend port for this route.";
};
};
routeType =
protocols: options:
lib.types.submodule {
options = {
domain = lib.mkOption {
type = lib.types.str;
example = "files.alexion.dev";
description = "Public domain for this route.";
};
protocol = lib.mkOption {
type = lib.types.enum protocols;
description = "Public protocol for this route.";
};
}
// options;
};
udpRoute = routeType [ "udp" ] {
ports = lib.mkOption {
type = lib.types.nonEmptyListOf lib.types.port;
example = [
2456
2457
];
description = "UDP ports for this route.";
};
};
in
{ {
checks = [ checks = [
{ {
@@ -8,49 +52,15 @@
{ {
assertion = assertion =
entries: entries:
util.registry.predicates.uniqueValue (entry: entry.value) ( util.registry.predicates.uniqueValue lib.id (
lib.concatMap (entry: map (port: entry // { value = port; }) entry.value.udp.ports) entries lib.concatMap (entry: entry.value.ports) (lib.filter (entry: entry.value.protocol == "udp") entries)
); );
message = "Route UDP ports must be unique."; message = "Route UDP ports must be unique.";
} }
{
assertion =
entries: lib.all (entry: entry.value.port == null || entry.value.http.port == null) entries;
message = "Route entries must not set both port and http.port.";
}
]; ];
type = lib.types.submodule { type = lib.types.oneOf [
options = { webRoute
domain = lib.mkOption { udpRoute
type = lib.types.str; ];
example = "files.alexion.dev";
description = "Domain served by this route entry.";
};
port = lib.mkOption {
type = lib.types.nullOr lib.types.port;
default = null;
example = 3923;
description = "HTTPS backend TCP port served by the matching address registry entry.";
};
http.port = lib.mkOption {
type = lib.types.nullOr lib.types.port;
default = null;
example = 8082;
description = "HTTP backend TCP port served by the matching address registry entry.";
};
udp.ports = lib.mkOption {
type = lib.types.listOf lib.types.port;
default = [ ];
example = [
2456
2457
];
description = "UDP ports served by the matching address registry entry.";
};
};
};
} }