From 91d8f8fab145f3ffdce339d86dfed80f12087270 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Mon, 20 Jul 2026 12:54:45 +0000 Subject: [PATCH] Add lxc-tor-relay build type with nyx monitoring New tor-relay build type (currently lxc-only) running a plain Tor middle relay via modules/tor/enable-relay.nix, plus nyx for interactive monitoring over the relay's control socket. Co-Authored-By: Claude Sonnet 5 --- AGENTS.md | 2 +- CLAUDE.md | 12 ++++++----- README.md | 7 ++++--- docs/auto-installer.md | 2 +- flake.nix | 2 ++ hosts/tor-relay/host.nix | 12 +++++++++++ modules/build-types/tor-relay.nix | 7 +++++++ modules/tor/enable-relay.nix | 35 +++++++++++++++++++++++++++++++ variables.nix | 8 +++++++ 9 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 hosts/tor-relay/host.nix create mode 100644 modules/build-types/tor-relay.nix create mode 100644 modules/tor/enable-relay.nix diff --git a/AGENTS.md b/AGENTS.md index f5f49b0..871437e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ servers and workstation. The flake exposes NixOS configurations named `-` (platforms: `linode`, `proxmox`, `lxc`; build types: `minimal`, `nix-cache`, -`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`), generated from `modules/platforms/*` +`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`, `tor-relay`), generated from `modules/platforms/*` and `modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not every combination is built — `pxe-boot` has no `linode` variant. See `README.md` for the full current target list; treat `flake.nix` as the diff --git a/CLAUDE.md b/CLAUDE.md index 46ab45e..8921f0c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -160,9 +160,10 @@ nixosSystem { ``` Platforms: `linode`, `proxmox`, `lxc`. Build types: `minimal`, `nix-cache`, -`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`. Not every -combination is built — e.g. `pxe-boot` has no `linode` variant (PXE/DHCP/TFTP -need LAN L2 adjacency a Linode VPS doesn't have). Treat `flake.nix`'s +`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`, `tor-relay`. Not +every combination is built — e.g. `pxe-boot` has no `linode` variant +(PXE/DHCP/TFTP need LAN L2 adjacency a Linode VPS doesn't have), and +`tor-relay` currently only exists as `lxc-tor-relay`. Treat `flake.nix`'s `generatedTargets` as the source of truth for which hosts exist — `README.md`, `AGENTS.md`, `docs/flake-lock-automation.md`, and the CI eval workflows @@ -190,7 +191,7 @@ removing a host. `vzdump` backup-archive metadata this doesn't have), no install step — see `docs/auto-installer.md`. - `modules/build-types/*.nix` — what a system is for: - minimal/server/docker/gui/pxe-boot/nix-cache/tailscale-exit-node. + minimal/server/docker/gui/pxe-boot/nix-cache/tailscale-exit-node/tor-relay. - `modules/common/configuration.nix` — base NixOS config imported by every host: locale, users, nix settings, git. - `modules/common/home.nix` / `hosts/nixos/home.nix` — Home Manager config for @@ -225,7 +226,8 @@ removing a host. and `environmentFile`; used by `hosts/server/host.nix` and `hosts/nix-cache/host.nix` to avoid duplicating that boilerplate. - `modules/tailscale/`, `modules/docker/`, `modules/networking/`, - `modules/traefik/`, `modules/services/*` — single-purpose, single-host + `modules/traefik/`, `modules/tor/`, `modules/services/*` — single-purpose, + single-host feature modules (e.g. `docker/enable-service.nix`, `services/zfs/enable-service.nix`). Grep `modules/build-types/*.nix` for each build type's `imports` list to see which modules apply where. diff --git a/README.md b/README.md index a262d6c..ae9fb91 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ pieces composed in `flake.nix`: - **Platforms** (what it runs on): `linode`, `proxmox`, `lxc` - **Build types** (what it's for): `minimal`, `nix-cache`, `server`, `docker`, - `gui`, `pxe-boot`, `tailscale-exit-node` + `gui`, `pxe-boot`, `tailscale-exit-node`, `tor-relay` Not every combination exists — `pxe-boot` has no `linode` variant, since -PXE/DHCP/TFTP need LAN L2 adjacency that a Linode VPS doesn't have. The full -list: +PXE/DHCP/TFTP need LAN L2 adjacency that a Linode VPS doesn't have, and +`tor-relay` currently only exists as `lxc-tor-relay`. The full list: | Target | Purpose | | --- | --- | @@ -27,6 +27,7 @@ list: | `linode-gui` / `proxmox-gui` / `lxc-gui` | Cinnamon desktop workstation — previously the flat `nixos` target | | `proxmox-pxe-boot` / `lxc-pxe-boot` | HTTP/iPXE boot asset host — previously the flat `pxe-boot` target | | `linode-tailscale-exit-node` / `proxmox-tailscale-exit-node` / `lxc-tailscale-exit-node` | Tailscale exit node | +| `lxc-tor-relay` | Tor middle relay | Which variant of a given buildtype is actually deployed isn't tracked anywhere in this repo — that's live infrastructure state, not something a diff --git a/docs/auto-installer.md b/docs/auto-installer.md index d33ee95..7eba4b9 100644 --- a/docs/auto-installer.md +++ b/docs/auto-installer.md @@ -19,7 +19,7 @@ see "LXC hosts" immediately below for why those are different.** ## LXC hosts `lxc-*` targets (`lxc-minimal`, `lxc-nix-cache`, `lxc-server`, `lxc-docker`, -`lxc-gui`, `lxc-pxe-boot`, `lxc-tailscale-exit-node`) are **not** installed via `auto-install.sh` — the +`lxc-gui`, `lxc-pxe-boot`, `lxc-tailscale-exit-node`, `lxc-tor-relay`) are **not** installed via `auto-install.sh` — the interactive menu deliberately excludes them. Don't try to select one there; `nixos-install` would bind-mount `/` onto `/mnt` (LXC containers have no raw disk to partition) and then refuse to touch the filesystem it's currently diff --git a/flake.nix b/flake.nix index e2f36d7..8e2587c 100644 --- a/flake.nix +++ b/flake.nix @@ -98,6 +98,8 @@ linode-tailscale-exit-node = mkTarget { platform = "linode"; buildType = "tailscale-exit-node"; hostPath = ./hosts/tailscale-exit-node/host.nix; }; proxmox-tailscale-exit-node = mkTarget { platform = "proxmox"; buildType = "tailscale-exit-node"; hostPath = ./hosts/tailscale-exit-node/host.nix; }; lxc-tailscale-exit-node = mkTarget { platform = "lxc"; buildType = "tailscale-exit-node"; hostPath = ./hosts/tailscale-exit-node/host.nix; }; + + lxc-tor-relay = mkTarget { platform = "lxc"; buildType = "tor-relay"; hostPath = ./hosts/tor-relay/host.nix; }; }; # Auto-install environments (migrated from the former nix-auto-installer diff --git a/hosts/tor-relay/host.nix b/hosts/tor-relay/host.nix new file mode 100644 index 0000000..2c0f1ae --- /dev/null +++ b/hosts/tor-relay/host.nix @@ -0,0 +1,12 @@ +_: + +{ + networking.hostName = "tor-relay"; + + # No networking.hostId: only ZFS-touching hosts (server, docker) need one + # for pool-import safety, and this host does neither. + + # A genuinely new host (not a pre-refactor carry-over), so it tracks the + # flake's current nixpkgs release rather than being pinned to an older one. + system.stateVersion = "26.05"; +} diff --git a/modules/build-types/tor-relay.nix b/modules/build-types/tor-relay.nix new file mode 100644 index 0000000..3d1afe9 --- /dev/null +++ b/modules/build-types/tor-relay.nix @@ -0,0 +1,7 @@ +{ ... }: + +{ + imports = [ + ../tor/enable-relay.nix + ]; +} diff --git a/modules/tor/enable-relay.nix b/modules/tor/enable-relay.nix new file mode 100644 index 0000000..c1438ed --- /dev/null +++ b/modules/tor/enable-relay.nix @@ -0,0 +1,35 @@ +{ pkgs, vars, ... }: + +{ + services.tor = { + enable = true; + + # Opens settings.ORPort (and DirPort, unset here) in the firewall — + # see the nixpkgs tor module's own networking.firewall.mkIf block. + openFirewall = true; + + relay = { + enable = true; + # Plain middle/guard relay, not "exit" — relays onion traffic between + # other Tor nodes without ever making requests to the public internet + # on a user's behalf, avoiding the abuse complaints and legal exposure + # an exit node invites. + role = "relay"; + }; + + settings.ORPort = vars.ports.torRelayOrPort; + + # Unix control socket at /run/tor/control (GroupWritable, group "tor") + # -- what nyx below actually monitors the relay through. Nyx's own + # default control-socket path (/var/run/tor/control) resolves to the + # same place, so no extra nyx config is needed. + controlSocket.enable = true; + }; + + # Lets the primary user's shell session read/write the control socket + # above without being root -- otherwise nyx fails to authenticate against + # it at all. + users.users.${vars.primaryUser}.extraGroups = [ "tor" ]; + + environment.systemPackages = [ pkgs.nyx ]; +} diff --git a/variables.nix b/variables.nix index f86b81c..c7b6c5c 100644 --- a/variables.nix +++ b/variables.nix @@ -137,6 +137,14 @@ # shortcuts on the gui build type (hosts/nixos/home.nix). pveWeb = 8006; pbsWeb = 8007; + + # Tor relay's ORPort — the port other Tor relays connect to for onion + # routing traffic (modules/tor/enable-relay.nix). Tor's own conventional + # default; opened via services.tor.openFirewall rather than + # networking.firewall.allowedTCPPorts directly, but kept here anyway so + # it's not a bare literal duplicated between the relay's settings and + # anything else that ever needs to reference it. + torRelayOrPort = 9001; }; # .raw disk image size for every proxmox-* host's standalone Disko image