iroh: Deploy DNS servers and relays

This commit is contained in:
Lorenz Leutgeb
2026-08-03 14:14:18 +02:00
parent 14ed626f61
commit 9d97c48e12
7 changed files with 401 additions and 0 deletions
+5
View File
@@ -226,6 +226,11 @@ D("radicle.network", REG_NONE, DnsProvider(DSP_CLOUDFLARE),
NS("bootstrap", "seed.radicle.dev."),
ALIAS("1.eu.dns.iroh", "iris"),
ALIAS("1.us.dns.iroh", "rosa"),
ALIAS("1.eu.relay.iroh", "iris"),
ALIAS("1.us.relay.iroh", "rosa"),
A("blackhole", "192.0.2.1"),
);
+1
View File
@@ -17,6 +17,7 @@
../../../mixin/users.nix
./i2pd.nix
./iroh.nix
./ssh.nix
./radicle.nix
./tor.nix
+40
View File
@@ -0,0 +1,40 @@
{
imports = [
../../../module/iroh-dns-server.nix
../../../module/iroh-relay.nix
];
networking.firewall = {
allowedTCPPorts = [
53 # dns-server
];
allowedUDPPorts = [
53 # dns-server
7824 # relay
];
};
services.iroh = {
relay = {
enable = true;
domain = "1.eu.relay.iroh.radicle.network";
nginx.enable = true;
};
dns = {
enable = true;
domain = "1.eu.dns.iroh.radicle.network";
nginx.enable = true;
settings = {
http.port = 8053;
dns = {
port = 53;
bind_addr = "::";
default_soa = ". team.radicle.network. 0 10800 3600 604800 3600";
origins = ["."];
};
};
};
};
}
+1
View File
@@ -17,6 +17,7 @@
../../../mixin/users.nix
./i2pd.nix
./iroh.nix
./ssh.nix
./radicle.nix
./tor.nix
+40
View File
@@ -0,0 +1,40 @@
{
imports = [
../../../module/iroh-dns-server.nix
../../../module/iroh-relay.nix
];
networking.firewall = {
allowedTCPPorts = [
53 # dns-server
];
allowedUDPPorts = [
53 # dns-server
7824 # relay
];
};
services.iroh = {
relay = {
enable = true;
domain = "1.us.relay.iroh.radicle.network";
nginx.enable = true;
};
dns = {
enable = true;
domain = "1.us.dns.iroh.radicle.network";
nginx.enable = true;
settings = {
http.port = 8053;
dns = {
port = 53;
bind_addr = "::";
default_soa = ". team.radicle.network. 0 10800 3600 604800 3600";
origins = ["."];
};
};
};
};
}
+148
View File
@@ -0,0 +1,148 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.services.iroh.dns;
settingsFormat = pkgs.formats.toml {};
configFile = settingsFormat.generate "iroh-dns-server.toml" cfg.settings;
in {
options.services.iroh.dns = {
enable = lib.mkEnableOption "iroh DNS Server";
package = lib.mkPackageOption pkgs "iroh-dns-server" {};
user = lib.mkOption {
type = lib.types.str;
default = "iroh";
description = "User under which iroh-dns-server runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = "iroh";
description = "Group under which iroh-dns-server runs.";
};
domain = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "dns.example.org";
description = "Public hostname used for DNS over HTTPS.";
};
settings = lib.mkOption {
type = settingsFormat.type;
default = {};
description = ''
Configuration written to iroh-dns-server.toml. See the upstream
iroh-dns-server configuration for supported values.
'';
};
nginx = {
enable = lib.mkEnableOption "nginx virtual host for iroh DNS over HTTPS";
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
services.iroh.dns.settings = {
pkarr_put_rate_limit = lib.mkDefault "smart";
data_dir = lib.mkDefault "/var/lib/iroh-dns-server";
http = {
bind_addr = lib.mkDefault "::1";
port = lib.mkDefault 8080;
};
dns = {
bind_addr = lib.mkDefault "::";
port = lib.mkDefault 53;
default_ttl = lib.mkDefault 30;
origins = lib.mkDefault ["."];
};
mainline.enabled = lib.mkDefault false;
metrics = {
disabled = lib.mkDefault false;
bind_addr = lib.mkDefault "127.0.0.1:9117";
};
};
users = {
users.${cfg.user} = {
isSystemUser = true;
group = cfg.group;
};
groups.${cfg.group} = {};
};
systemd.services.iroh-dns-server = {
description = "iroh DNS Server";
wantedBy = ["multi-user.target"];
wants = ["network-online.target"];
after = ["network-online.target"];
serviceConfig = {
Type = "simple";
ExecStart = "${lib.getExe cfg.package} --config ${configFile}";
Restart = "on-failure";
RestartSec = 5;
User = cfg.user;
Group = cfg.group;
AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
RuntimeDirectory = "iroh-dns-server";
StateDirectory = "iroh-dns-server";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateIPC = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallErrorNumber = "EPERM";
SystemCallFilter = ["@system-service"];
LimitNOFILE = 65536;
};
};
}
(lib.mkIf cfg.nginx.enable {
assertions = [
{
assertion = cfg.domain != null;
message = "services.iroh.dns.domain must be set when nginx is enabled";
}
];
services.nginx.virtualHosts.${cfg.domain} = {
enableACME = true;
forceSSL = true;
quic = true;
locations."/".proxyPass = "http://[::1]:${builtins.toString cfg.settings.http.port}";
};
})
]);
}
+166
View File
@@ -0,0 +1,166 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.services.iroh.relay;
settingsFormat = pkgs.formats.toml {};
configFile = settingsFormat.generate "iroh-relay.toml" cfg.settings;
in {
options.services.iroh.relay = {
enable = lib.mkEnableOption "iroh Relay";
package = lib.mkPackageOption pkgs "iroh-relay" {};
user = lib.mkOption {
type = lib.types.str;
default = "iroh";
description = "User under which iroh-relay runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = "iroh";
description = "Group under which iroh-relay runs.";
};
domain = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "relay.example.org";
description = "Public hostname of the relay.";
};
settings = lib.mkOption {
type = settingsFormat.type;
default = {};
description = ''
Configuration written to `iroh-relay.toml`. See the upstream
`iroh-relay` configuration for supported values.
'';
};
nginx = {
enable = lib.mkEnableOption "nginx reverse-proxy for iroh-relay";
proxyPass = lib.mkOption {
type = lib.types.str;
default = "http://127.0.0.1:3340";
description = "URL to which nginx proxies relay HTTP and WebSocket traffic.";
};
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
services.iroh.relay.settings = {
http_bind_addr = lib.mkDefault (
if cfg.nginx.enable
then "127.0.0.1:3340"
else "[::]:3340"
);
enable_quic_addr_discovery = lib.mkDefault cfg.nginx.enable;
enable_metrics = lib.mkDefault true;
metrics_bind_addr = lib.mkDefault "127.0.0.1:9091";
};
users = {
users.${cfg.user} = {
isSystemUser = true;
group = cfg.group;
};
groups.${cfg.group} = {};
};
systemd.services.iroh-relay = {
description = "iroh Relay";
wantedBy = ["multi-user.target"];
wants = ["network-online.target"];
after = ["network-online.target"];
serviceConfig = {
Type = "simple";
ExecStart = "${lib.getExe cfg.package} --config-path ${configFile}";
Restart = "on-failure";
RestartSec = 5;
User = cfg.user;
Group = cfg.group;
RuntimeDirectory = "iroh-relay";
StateDirectory = "iroh-relay";
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateIPC = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallErrorNumber = "EPERM";
SystemCallFilter = ["@system-service"];
LimitNOFILE = 65536;
};
};
}
(lib.mkIf cfg.nginx.enable {
assertions = [
{
assertion = cfg.domain != null;
message = "services.iroh.relay.domain must be set when its nginx frontend is enabled";
}
];
services.iroh.relay.settings = {
tls = {
cert_mode = lib.mkDefault "Reloading";
manual_cert_path = lib.mkDefault "/var/lib/acme/${cfg.domain}/fullchain.pem";
manual_key_path = lib.mkDefault "/var/lib/acme/${cfg.domain}/key.pem";
dangerous_http_only = lib.mkDefault true;
quic_bind_addr = lib.mkDefault "[::]:7842";
};
};
users.users.${cfg.user}.extraGroups = [config.services.nginx.group];
systemd.services.iroh-relay = {
requires = ["acme-${cfg.domain}.service"];
after = ["acme-${cfg.domain}.service"];
};
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts.${cfg.domain} = {
enableACME = true;
forceSSL = true;
quic = true;
locations."/" = {
proxyPass = "http://127.0.0.1:3340";
proxyWebsockets = true;
extraConfig = ''
proxy_buffering off;
proxy_request_buffering off;
'';
};
};
};
})
]);
}