This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / configs / iroh-relay / default.nix
4.9 kB 130 lines
1let 2 domain = "relay.lassul.us"; 3 # Plain HTTP/WS on loopback only; nginx terminates TLS in front of it. 4 httpPort = 3340; 5 # QUIC address discovery. Public UDP, and the one part nginx cannot proxy, 6 # so the relay reads the ACME cert itself. 7842 is iroh's 7 # DEFAULT_RELAY_QUIC_PORT -- clients derive it from the relay url and expect 8 # it there, so do not move it without telling every client. 9 quicPort = 7842; 10 certGroup = "irohrelaycert"; 11 12 configFile = ( 13 pkgs: 14 pkgs.writeText "iroh-relay.toml" '' 15 enable_relay = true 16 http_bind_addr = "127.0.0.1:${toString httpPort}" 17 18 # The whole reason to run our own relay: QAD tells an endpoint its own NAT 19 # mapping, which is what makes hole punching work. Without it this is just 20 # a data relay and peers never upgrade to direct. Requires TLS. 21 enable_quic_addr_discovery = true 22 23 enable_metrics = true 24 metrics_bind_addr = "127.0.0.1:9096" 25 26 [tls] 27 hostname = "${domain}" 28 quic_bind_addr = "[::]:${toString quicPort}" 29 30 # `Reloading` re-reads the cert from disk periodically, so ACME renewals are 31 # picked up without a restart. `LetsEncrypt` is not usable here: it wants to 32 # own port 80 for the challenge, which nginx already has. 33 cert_mode = "Reloading" 34 manual_cert_path = "/var/lib/acme/${domain}/fullchain.pem" 35 manual_key_path = "/var/lib/acme/${domain}/key.pem" 36 37 # Serve the relay's HTTP/WS side as plain HTTP so nginx can reverse-proxy 38 # it; the cert above is then used only by the QUIC listener. "dangerous" 39 # overstates it here: the plaintext hop is loopback, nginx does real TLS on 40 # 443, and relayed payloads are already end-to-end encrypted between iroh 41 # endpoints -- the relay only ever sees ciphertext. 42 dangerous_http_only = true 43 '' 44 ); 45in 46{ 47 pkgs, 48 ... 49}: 50{ 51 # Self-hosted iroh relay. 52 # 53 # A relay supplies the two things a relay-free iroh endpoint cannot get for 54 # itself: QUIC address discovery (learning its own NAT mapping) and a 55 # signalling path to coordinate hole punching. Measured from a double-NATed 56 # host, relayed configs hole-punched to direct in ~80ms with 0 failures over 57 # 30 runs, while the relay-free config failed 100% of the time. 58 # 59 # Running our own also fixes the throughput floor: n0's public relays 60 # rate-limit to ~0.9 Mbps, which is fine for keystrokes and miserable for 61 # anything larger when hole punching fails. 62 # 63 # Clients opt in with `RelayMode::Custom`, e.g. 64 # iroh-bench --config dht-selfrelay --relay-url https://relay.lassul.us 65 # dumbpipe listen-tcp --relay-url https://relay.lassul.us (patched build) 66 67 # nginx owns 80/443 and the ACME challenge, so it fetches the cert and the 68 # relay only reads it. A dedicated group keeps that read as narrow as 69 # possible; nginx must be a member to serve the vhost. Same pattern as 70 # mailserver.nix's `lasscert`. 71 security.acme.certs.${domain}.group = certGroup; 72 users.groups.${certGroup}.members = [ "nginx" ]; 73 74 services.nginx.virtualHosts.${domain} = { 75 enableACME = true; 76 forceSSL = true; 77 # One location covers every route the relay serves: `/relay` (the websocket 78 # clients ride), `/ping` and `/generate_204` (net_report latency probes, 79 # which is how a client picks its nearest relay out of a map). 80 locations."/" = { 81 proxyPass = "http://127.0.0.1:${toString httpPort}"; 82 proxyWebsockets = true; 83 # Relay connections are long-lived and idle whenever a pair has upgraded 84 # to a direct path; nginx's default 60s read timeout would tear them down 85 # and force clients back through a reconnect. 86 extraConfig = '' 87 proxy_read_timeout 1d; 88 proxy_send_timeout 1d; 89 ''; 90 }; 91 }; 92 93 systemd.services.iroh-relay = { 94 description = "iroh relay (${domain})"; 95 wantedBy = [ "multi-user.target" ]; 96 after = [ 97 "network-online.target" 98 "nginx.service" 99 ]; 100 wants = [ "network-online.target" ]; 101 102 serviceConfig = { 103 ExecStart = "${pkgs.iroh-relay}/bin/iroh-relay --config-path ${configFile pkgs}"; 104 Restart = "always"; 105 RestartSec = 5; 106 107 DynamicUser = true; 108 # Read access to /var/lib/acme/${domain}. Works with DynamicUser: systemd 109 # adds the transient user to the group at start. 110 SupplementaryGroups = [ certGroup ]; 111 112 # ProtectSystem=strict only remounts read-only, so reading the cert is 113 # still fine. 114 ProtectSystem = "strict"; 115 ProtectHome = true; 116 PrivateTmp = true; 117 NoNewPrivileges = true; 118 ProtectKernelTunables = true; 119 ProtectControlGroups = true; 120 RestrictAddressFamilies = [ 121 "AF_INET" 122 "AF_INET6" 123 ]; 124 }; 125 }; 126 127 # Only the QAD listener needs a hole punched; the relay's HTTP side is 128 # reached through nginx on 443, which is already open. 129 networking.firewall.allowedUDPPorts = [ quicPort ]; 130}