From 78fdf3d94cc2616779bdb4045c97b8313bb658f1 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Thu, 30 Jul 2026 07:10:03 +1000 Subject: [PATCH] Update network topology: Tailscale routing and DNS proxy, remove Pi-hole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Document bidirectional LAN ↔ Tailscale routing via tailscale-router (static route on router for 100.64.0.0/10, subnet advertisement into Tailnet) - Document DNS proxy chain: FreeIPA conditional forwarder for *.ts.net → tailscale-router → MagicDNS; reverse for *.sweet.home from Tailscale clients - Remove stale pihole.sweet.home from IP table (decommissioned) - Fix freeipa role: remove Pi-hole IP from ipa_dns_forwarder, document ts.net conditional forwarder as a post-install step - Fix inventory: remove Pi-hole forwarder IP, add ts.net forwarder note Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01UvNjoxTWEDkhXsd1Dq2ETP --- ansible/inventory/hosts.yml | 4 +- ansible/roles/freeipa/defaults/main.yml | 7 +++- docs/internal/architecture.md | 15 +++++++ docs/internal/network-topology.md | 52 +++++++++++++++++++------ 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/ansible/inventory/hosts.yml b/ansible/inventory/hosts.yml index b41776b..9b4795b 100644 --- a/ansible/inventory/hosts.yml +++ b/ansible/inventory/hosts.yml @@ -33,7 +33,9 @@ all: ipa_domain: "sweet.home" ipa_hostname: "domain-controller.sweet.home" ipa_ip: "192.168.2.253" - ipa_dns_forwarder: "192.168.2.138" # Pi-hole + # ipa_dns_forwarder: set to router gateway IP before running freeipa role + # Post-install: add ts.net conditional forwarder manually: + # ipa dnsforwardzone-add tail13f623.ts.net --forwarder=192.168.2.222 ansible_python_interpreter: /usr/bin/python3 # ── Edge / monitoring ───────────────────────────────────────────────────── diff --git a/ansible/roles/freeipa/defaults/main.yml b/ansible/roles/freeipa/defaults/main.yml index dc555d3..0307fdd 100644 --- a/ansible/roles/freeipa/defaults/main.yml +++ b/ansible/roles/freeipa/defaults/main.yml @@ -8,7 +8,12 @@ ipa_domain: "sweet.home" # Set these per-host in inventory/hosts.yml: # ipa_hostname: "domain-controller.sweet.home" # ipa_ip: "192.168.2.253" -# ipa_dns_forwarder: "192.168.2.138" +# ipa_dns_forwarder: "" # upstream resolver for non-sweet.home queries +# +# Note: the conditional forwarder for *.ts.net → tailscale-router (192.168.2.222) +# is configured post-install via `ipa dnsforwardzone-add tail13f623.ts.net --forwarder=192.168.2.222`. +# This is what allows LAN clients to resolve Tailscale hostnames through FreeIPA. +# The NixOS tailscale-router build type configures the other direction automatically. # Swap file created if no swap exists (FreeIPA needs headroom during install) ipa_swap_size_mb: 2048 diff --git a/docs/internal/architecture.md b/docs/internal/architecture.md index 769d4dd..f7a8fac 100644 --- a/docs/internal/architecture.md +++ b/docs/internal/architecture.md @@ -52,6 +52,7 @@ FreeIPA (`SWEET.HOME` realm) provides: - Kerberos SSO for all IPA-enrolled hosts - LDAP user/group directory (`admins`, `docker-access` groups) - Authoritative DNS for the entire LAN (Pi-hole decommissioned; FreeIPA is the sole resolver) +- Conditional forwarder: `*.ts.net` → `tailscale-router` (192.168.2.222) → Tailscale MagicDNS - Certificate authority for internal TLS All hosts (Proxmox nodes, Raspberry Pi, Docker host) are IPA-enrolled via SSSD. @@ -60,6 +61,20 @@ The `docker-access` group (GID 50010) grants Docker socket access on Docker host DHCP is handled by the router. PXE-specific DHCP options are served by the `pxe-boot` LXC. +## Tailscale ↔ LAN bridge + +`tailscale-router.sweet.home` (192.168.2.222) is a NixOS LXC running the `tailscale-router` +build type. It provides full bidirectional connectivity between the LAN and the Tailnet: + +- **LAN → Tailscale:** Router has a static route for `100.64.0.0/10` (Tailscale CGNAT) → 192.168.2.222. + DNS for `*.ts.net` flows through FreeIPA's conditional forwarder → tailscale-router → MagicDNS. +- **Tailscale → LAN:** tailscale-router advertises `192.168.2.0/24` as a subnet route. + Tailscale clients use tailscale-router as a split-horizon DNS forwarder for `sweet.home`, + which proxies those queries to FreeIPA. + +This means any Tailscale-connected device can resolve and reach `*.sweet.home` hosts, and +any LAN host can resolve and reach `*.ts.net` hosts — without needing a Tailscale client installed. + ## Monitoring stack ``` diff --git a/docs/internal/network-topology.md b/docs/internal/network-topology.md index 4cb3de3..6d63313 100644 --- a/docs/internal/network-topology.md +++ b/docs/internal/network-topology.md @@ -12,39 +12,67 @@ | Host | IP | Role | |------|----|------| -| `pve1.sweet.home` | (assigned by router) | Proxmox hypervisor | -| `domain-controller.sweet.home` | `192.168.2.253` | FreeIPA server | -| `pihole.sweet.home` | see Pi-hole admin | DNS/DHCP server | +| `pve1.sweet.home` | (router DHCP / static lease) | Proxmox hypervisor | +| `domain-controller.sweet.home` | `192.168.2.253` | FreeIPA (DNS + auth) | | `docker.sweet.home` | `192.168.2.225` | Docker app stack host | | `nix-cache.sweet.home` | `192.168.2.224` | Nix binary cache | | `pxe-boot.sweet.home` | `192.168.2.223` | PXE/TFTP/HTTP boot server | -| `tailscale-router.sweet.home` | `192.168.2.222` | Tailscale subnet router | +| `tailscale-router.sweet.home` | `192.168.2.222` | Tailscale subnet router + DNS proxy | | `tor-relay.sweet.home` | `192.168.2.221` | Tor middle relay | | `ha-server-1.sweet.home` | `192.168.2.228` | HA cluster node 1 | | `ha-server-2.sweet.home` | `192.168.2.227` | HA cluster node 2 | | HA LAN VIP (Pacemaker) | `192.168.2.229` | Floating NFS/service VIP | | HA storage VIP (Pacemaker) | `192.168.20.229` | Docker iSCSI/NFS floating VIP | -| `raspberrypi.tail13f623.ts.net` | Tailscale | Raspberry Pi (reachable via Tailnet) | +| `raspberrypi.tail13f623.ts.net` | Tailscale | Raspberry Pi edge node | ## DNS architecture -Pi-hole has been decommissioned. FreeIPA is now the sole DNS server for the LAN. +FreeIPA is the sole DNS server for all LAN clients (Pi-hole decommissioned). +Tailscale name resolution is handled by a conditional forwarder in FreeIPA pointing at +the `tailscale-router` LXC, which proxies those queries into Tailscale MagicDNS. ``` -All LAN clients → FreeIPA (domain-controller.sweet.home — 192.168.2.253) +LAN client → FreeIPA (192.168.2.253) │ - ├── *.sweet.home → IPA integrated DNS (authoritative) - └── Everything else → upstream resolvers (forwarded by FreeIPA) + ├── *.sweet.home → IPA integrated DNS (authoritative) + ├── *.ts.net → conditional forwarder → tailscale-router (192.168.2.222) + │ │ + │ └── Tailscale MagicDNS (100.100.100.100) + └── everything else → upstream resolvers (via FreeIPA forwarders) + +Tailscale client → tailscale-router (MagicDNS split-horizon) + │ + ├── *.sweet.home → forwarded to FreeIPA (192.168.2.253) + └── *.ts.net → Tailscale MagicDNS (local) ``` -PXE DHCP is handled by the `pxe-boot` LXC (dnsmasq in proxy mode for PXE chainloading only). +PXE DHCP options are served by the `pxe-boot` LXC (dnsmasq proxy mode for PXE chainloading only). General DHCP is handled by the router. +## Tailscale + LAN routing + +The `tailscale-router` LXC at `192.168.2.222` bridges the Tailscale network and the LAN +in both directions: + +**LAN → Tailscale:** +- Router has a static route: Tailscale CGNAT range (`100.64.0.0/10`) → `192.168.2.222` +- LAN hosts reach Tailscale peers (e.g. `raspberrypi.tail13f623.ts.net`) via this route +- DNS resolution for `*.ts.net` goes through FreeIPA → tailscale-router → MagicDNS (see above) + +**Tailscale → LAN:** +- `tailscale-router` advertises `192.168.2.0/24` as a subnet route into the Tailnet +- Tailscale peers can reach any `192.168.2.x` host by routing through `tailscale-router` +- DNS: Tailscale peers use `tailscale-router` as a split-horizon forwarder for `sweet.home` + +**Result:** From any Tailscale-connected device, `docker.sweet.home` resolves and routes +correctly without being physically on the LAN. From any LAN host, +`raspberrypi.tail13f623.ts.net` resolves and routes without a Tailscale client. + ## External access - Domain: `*.lan.ddnsgeek.com` → Dynamic DNS via Dynu → home WAN IP -- TLS: LetsEncrypt via Traefik ACME (HTTP challenge) -- Tailscale VPN: subnet router at `192.168.2.222` bridges Tailnet to LAN +- TLS: LetsEncrypt via Traefik ACME (HTTP challenge on port 80) +- Tailscale: subnet router at `192.168.2.222` (see above) ## Proxmox firewall