feat(fw,web-arm): replace cyberghost germany exit with a wireguard tunnel via web-arm #151

Closed
opened 2026-06-12 22:49:54 +02:00 by dominik.polakovics · 1 comment

This was generated by AI during triage.

Context

PR #149 + #150 added a toggleable CyberGhost Germany exit on fw (OpenVPN, cyberghost-de.target) that policy-routes the Apple TV (10.42.99.15) for geo-unblocking ARTE/ARD/ZDF/Joyn. It works, but CyberGhost throughput is too low for streaming. Replace the transport with a self-hosted WireGuard tunnel terminating on web-arm (Hetzner, German IPv4), keeping the toggle UX identical.

Agent Brief

Category: enhancement
Summary: web-arm becomes a WireGuard exit node; fw's German-exit toggle routes the Apple TV through it instead of CyberGhost, which gets removed.

Current behavior:
fw runs an OpenVPN client (CyberGhost DE) plus a policy-routing unit, both hanging off a systemd target. The routing unit installs, for each client IP (currently only the Apple TV), an ip rule pair: local 10.42.96.0/20 → main (priority 90), everything else → table vpn-de/101 (priority 100). The table holds a tunnel default route (metric 50, managed by OpenVPN up/down hooks) and an unreachable default (metric 100) as kill switch. nftables has an rpfilter exemption, a multimedia→tunnel forward accept, and masquerade for the tunnel interface. Target off at boot; start = German, stop = Austrian. CyberGhost is too slow.

Desired behavior:

  • web-arm runs a WireGuard "exit" interface: one peer (fw), a UDP listen port opened in its firewall, IPv4 forwarding + masquerade so peer traffic egresses via its public German IPv4. The existing wg_cloonar client interface and the ADR-0010 IPv6 arrangement must remain untouched; the new tunnel is IPv4-only inside.
  • Transfer subnet constraint: web-arm's wg_cloonar peer claims allowedIPs 10.42.0.0/16, and other fw tunnels claim 10.43.0.0/16, 10.50.x, 10.14.x. The new tunnel's transfer net must be outside all of these (e.g. something in 10.44.x.x/30) or web-arm/fw will route replies into the wrong tunnel.
  • fw replaces the OpenVPN client with a WireGuard interface: peer = web-arm's public endpoint (web-arm.cloonar.com:<port>), allowedIPs 0.0.0.0/0 but without installing routes into the main table (allowedIPsAsRoutes = false or equivalent) — it must not hijack fw's default route.
  • The WireGuard interface may be up permanently; the target only toggles the policy-routing unit. Toggle UX unchanged: start = Apple TV German, stop = Austrian, off after every boot. The routing unit now also installs the tunnel default route (metric 50) statically, since WireGuard has no up/down connection events.
  • Kill semantics preserved: target on + web-arm unreachable → WireGuard blackholes the traffic (no Austrian IP leak); interface absent → the unreachable route catches it. Target off → normal Austrian egress.
  • Local invariant preserved: Jellyfin (hairpin DNAT to the web VM) and all LAN/cross-VLAN traffic keep working in every state via the priority-90 local-/20 rule; client DNS stays on fw's dnsmasq.
  • CyberGhost removal: the OpenVPN unit, its module, and all tun-cg-de nftables references go away (replaced by the wg interface name). The cyberghost-auth/-ca/-cert/-key entries in fw's secrets are no longer referenced; flag them for maintainer removal — do not edit secrets files.
  • Rename the target/module to transport-neutral de-exit (semantics identical); keep table name vpn-de/101 and the client-list structure.

Key interfaces:

  • systemd target de-exit.target (successor of cyberghost-de.target) — same start/stop/boot semantics
  • the policy-routing oneshot unit — same rule priorities (90/100), table vpn-de 101, per-client list with 10.42.99.15 as sole member
  • networking.wireguard.interfaces on both hosts; fw side must disable allowedIPs-derived routes
  • sops secret wg_de_exit_key (private key) in each host's secrets store; public keys live in the Nix config
  • web-arm firewall: new UDP listen port; NAT/forwarding for the transfer subnet

Prerequisites (maintainer, before an AFK run):

  • Generate two WireGuard keypairs (wg genkey | tee ... | wg pubkey)
  • Add each private key as wg_de_exit_key to fw's and web-arm's encrypted secrets
  • Comment both public keys on this issue (fw-pub / web-arm-pub) and the chosen UDP port

Acceptance criteria:

  • systemctl start de-exit.target on fw → Apple TV egresses with web-arm's German IPv4; an ARD/ZDF live stream actually plays (validates the Hetzner datacenter range isn't geo-blocked)
  • systemctl stop de-exit.target → Apple TV egresses Austrian again, immediately
  • After fw reboot the target is off and the Apple TV is Austrian
  • Target on + web-arm down → Apple TV has no WAN egress at all (no Austrian leak); Jellyfin and LAN still work
  • Jellyfin reachable from the Apple TV in all three states (on / off / tunnel-dead)
  • No OpenVPN/CyberGhost config remains on fw; unused CG secret keys listed in the PR description for maintainer cleanup
  • Pre-commit dry-builds pass for fw and web-arm
  • web-arm's wg_cloonar, v6 egress (ADR 0010), and public web services unaffected

Out of scope:

  • Routing additional devices (structure stays a list, but only the Apple TV is enabled)
  • IPv6 inside the tunnel
  • A Home Assistant or other UI toggle
  • The nas CyberGhost (Austria) connection and the CyberGhost account itself
> *This was generated by AI during triage.* ## Context PR #149 + #150 added a toggleable CyberGhost Germany exit on fw (OpenVPN, `cyberghost-de.target`) that policy-routes the Apple TV (`10.42.99.15`) for geo-unblocking ARTE/ARD/ZDF/Joyn. It works, but CyberGhost throughput is too low for streaming. Replace the transport with a self-hosted WireGuard tunnel terminating on web-arm (Hetzner, German IPv4), keeping the toggle UX identical. ## Agent Brief **Category:** enhancement **Summary:** web-arm becomes a WireGuard exit node; fw's German-exit toggle routes the Apple TV through it instead of CyberGhost, which gets removed. **Current behavior:** fw runs an OpenVPN client (CyberGhost DE) plus a policy-routing unit, both hanging off a systemd target. The routing unit installs, for each client IP (currently only the Apple TV), an ip rule pair: local `10.42.96.0/20` → main (priority 90), everything else → table `vpn-de`/101 (priority 100). The table holds a tunnel default route (metric 50, managed by OpenVPN up/down hooks) and an `unreachable default` (metric 100) as kill switch. nftables has an rpfilter exemption, a multimedia→tunnel forward accept, and masquerade for the tunnel interface. Target off at boot; start = German, stop = Austrian. CyberGhost is too slow. **Desired behavior:** - **web-arm** runs a WireGuard "exit" interface: one peer (fw), a UDP listen port opened in its firewall, IPv4 forwarding + masquerade so peer traffic egresses via its public German IPv4. The existing `wg_cloonar` client interface and the ADR-0010 IPv6 arrangement must remain untouched; the new tunnel is IPv4-only inside. - **Transfer subnet constraint:** web-arm's `wg_cloonar` peer claims `allowedIPs 10.42.0.0/16`, and other fw tunnels claim `10.43.0.0/16`, `10.50.x`, `10.14.x`. The new tunnel's transfer net must be outside all of these (e.g. something in `10.44.x.x/30`) or web-arm/fw will route replies into the wrong tunnel. - **fw** replaces the OpenVPN client with a WireGuard interface: peer = web-arm's public endpoint (`web-arm.cloonar.com:<port>`), `allowedIPs 0.0.0.0/0` but **without** installing routes into the main table (`allowedIPsAsRoutes = false` or equivalent) — it must not hijack fw's default route. - The WireGuard interface may be up permanently; the **target only toggles the policy-routing unit**. Toggle UX unchanged: start = Apple TV German, stop = Austrian, off after every boot. The routing unit now also installs the tunnel default route (metric 50) statically, since WireGuard has no up/down connection events. - **Kill semantics preserved:** target on + web-arm unreachable → WireGuard blackholes the traffic (no Austrian IP leak); interface absent → the unreachable route catches it. Target off → normal Austrian egress. - **Local invariant preserved:** Jellyfin (hairpin DNAT to the web VM) and all LAN/cross-VLAN traffic keep working in every state via the priority-90 local-/20 rule; client DNS stays on fw's dnsmasq. - **CyberGhost removal:** the OpenVPN unit, its module, and all `tun-cg-de` nftables references go away (replaced by the wg interface name). The `cyberghost-auth/-ca/-cert/-key` entries in fw's secrets are no longer referenced; flag them for maintainer removal — do not edit secrets files. - Rename the target/module to transport-neutral `de-exit` (semantics identical); keep table name `vpn-de`/101 and the client-list structure. **Key interfaces:** - systemd target `de-exit.target` (successor of `cyberghost-de.target`) — same start/stop/boot semantics - the policy-routing oneshot unit — same rule priorities (90/100), table `vpn-de` 101, per-client list with `10.42.99.15` as sole member - `networking.wireguard.interfaces` on both hosts; fw side must disable allowedIPs-derived routes - sops secret `wg_de_exit_key` (private key) in each host's secrets store; public keys live in the Nix config - web-arm firewall: new UDP listen port; NAT/forwarding for the transfer subnet **Prerequisites (maintainer, before an AFK run):** - [ ] Generate two WireGuard keypairs (`wg genkey | tee ... | wg pubkey`) - [ ] Add each private key as `wg_de_exit_key` to fw's and web-arm's encrypted secrets - [ ] Comment both **public** keys on this issue (fw-pub / web-arm-pub) and the chosen UDP port **Acceptance criteria:** - [ ] `systemctl start de-exit.target` on fw → Apple TV egresses with web-arm's German IPv4; an ARD/ZDF live stream actually plays (validates the Hetzner datacenter range isn't geo-blocked) - [ ] `systemctl stop de-exit.target` → Apple TV egresses Austrian again, immediately - [ ] After fw reboot the target is off and the Apple TV is Austrian - [ ] Target on + web-arm down → Apple TV has no WAN egress at all (no Austrian leak); Jellyfin and LAN still work - [ ] Jellyfin reachable from the Apple TV in all three states (on / off / tunnel-dead) - [ ] No OpenVPN/CyberGhost config remains on fw; unused CG secret keys listed in the PR description for maintainer cleanup - [ ] Pre-commit dry-builds pass for fw and web-arm - [ ] web-arm's `wg_cloonar`, v6 egress (ADR 0010), and public web services unaffected **Out of scope:** - Routing additional devices (structure stays a list, but only the Apple TV is enabled) - IPv6 inside the tunnel - A Home Assistant or other UI toggle - The nas CyberGhost (Austria) connection and the CyberGhost account itself
Author
Owner

This was generated by AI during triage.

Maintainer-supplied WireGuard parameters for the de-exit tunnel:

  • fw public key: gXWzhBsMImSX2++S9lNlqyLgcUaBSYUo3mJ4JJRkkiM=
  • web-arm public key: MFQNf2IHykuSis0yKMx8W4w/601o596kTd52rfXiyzQ=
  • web-arm listen port: UDP 51820
  • Private keys go into each host's secrets as wg_de_exit_key (maintainer-managed).
> *This was generated by AI during triage.* Maintainer-supplied WireGuard parameters for the de-exit tunnel: - **fw public key:** `gXWzhBsMImSX2++S9lNlqyLgcUaBSYUo3mJ4JJRkkiM=` - **web-arm public key:** `MFQNf2IHykuSis0yKMx8W4w/601o596kTd52rfXiyzQ=` - **web-arm listen port:** UDP `51820` - Private keys go into each host's secrets as `wg_de_exit_key` (maintainer-managed).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/nixos#151
No description provided.