docs: migrate all documentation to Discourse wiki topics
All knowledge docs (architecture, runbooks, references, audits, policies) have been migrated to community.turnsys.com as wiki topics in the VP TechOps category. Discourse is now the canonical source of truth for documentation; git edit history no longer serves as the doc changelog. 37 .md files converted to short pointers linking to their Discourse topics. AGENTS.md updated with new documentation workflow policy. Code (scripts, configs, playbooks) remains authoritative in git.
This commit is contained in:
@@ -1,148 +1,10 @@
|
||||
# Tailscale vs. Managed DNS — Architecture Analysis
|
||||
# docs/server-build/tailscale.md
|
||||
|
||||
> **Status:** **RESOLVED.** The pfv-netinfra-01/02 pair now runs production
|
||||
> Technitium DNS with all `knel.net` records replicated from tailscale-router
|
||||
> via the DNS cluster setup. Both LAN IPs serve authoritative records for
|
||||
> `knel.net` and recurse externally. This document records the original
|
||||
> conflict, how it was resolved, and the recommended client configuration.
|
||||
|
||||
## 1. Executive summary
|
||||
|
||||
Every host in this build runs the Tailscale client, and Tailscale's MagicDNS
|
||||
manages `/etc/resolv.conf` by default (pointing at `100.100.100.100`). This
|
||||
previously conflicted with a managed `resolv.conf` pointing at the LAN
|
||||
resolvers. The root cause was that the LAN Technitium instances did not have
|
||||
the `knel.net` zone populated — **that is now fixed.**
|
||||
|
||||
The pfv-netinfra-01/02 pair now serves identical, authoritative `knel.net`
|
||||
records (replicated from production via [`dns-cluster-setup/`](../dns-cluster-setup/README.md)).
|
||||
Both LAN IPs resolve `knel.net` device names and recurse externally. The
|
||||
managed `resolv.conf` is now safe to deploy.
|
||||
|
||||
**Recommendation:** Deploy the managed `resolv.conf` (`.252`/`.253`) on hosts
|
||||
where you want tunnel-independent DNS. Leave Tailscale managing DNS on hosts
|
||||
where MagicDNS device names must resolve without a LAN path (e.g. laptops off
|
||||
-network). See [§5](#5-recommendation) for details.
|
||||
|
||||
## 2. How name resolution works today (post-cluster-setup)
|
||||
|
||||
Probed from `sectestbed-sandbox` (192.168.3.50) after the DNS cluster was
|
||||
deployed:
|
||||
|
||||
| Query path | External name (`github.com`) | `knel.net` device name (`pfv-netinfra-01.knel.net`) |
|
||||
|---|---|---|
|
||||
| Via Tailscale resolver (`100.100.100.100`) | resolves | resolves → `100.70.181.72` (Tailscale CGNAT) |
|
||||
| Direct `dig @192.168.3.252` (Technitium primary, LAN) | resolves (recurses) | **resolves** → `100.70.181.72` |
|
||||
| Direct `dig @192.168.3.253` (Technitium secondary, LAN) | resolves (recurses) | **resolves** → `100.70.181.72` |
|
||||
|
||||
**Both LAN resolvers now serve `knel.net` records identically.** The
|
||||
Technitium zone is no longer stale — it was replicated from production
|
||||
(tailscale-router) as part of the DNS cluster setup.
|
||||
|
||||
### What changed
|
||||
|
||||
Previously (before the DNS cluster setup), querying the LAN IPs returned
|
||||
NXDOMAIN for `knel.net` device names because the Technitium `knel.net` zone
|
||||
was empty (SOA serial `2025062313`, dated 2025-06-23). After replicating
|
||||
production config to both netinfra hosts, all 124 zones — including
|
||||
`knel.net` with all current device records — are served authoritatively on
|
||||
both `.252` and `.253`.
|
||||
|
||||
## 3. The DNS server pair
|
||||
|
||||
| Host | IP | Role | Services |
|
||||
|------|----|------|----------|
|
||||
| pfv-netinfra-01 | 192.168.3.252 | **Primary** | Technitium (authoritative, port 5300) + Pi-hole (recursive, port 53) |
|
||||
| pfv-netinfra-02 | 192.168.3.253 | **Secondary** | Technitium (replicated via rsync, port 5300) + Pi-hole (recursive, port 53) |
|
||||
|
||||
Zone replication is rsync-based (every 60s via systemd timer) because
|
||||
Technitium's AXFR uses port 53, which is occupied by Pi-hole on these hosts.
|
||||
See [`dns-cluster-setup/README.md`](../dns-cluster-setup/README.md) for
|
||||
full details.
|
||||
|
||||
## 4. NTP (fully resolved)
|
||||
|
||||
NTP is independent of DNS: `provisioning/ConfigFiles/NTP/ntp.conf` points
|
||||
directly at the LAN IPs with no DNS dependency:
|
||||
|
||||
```
|
||||
server 192.168.3.252 iburst
|
||||
server 192.168.3.253 iburst
|
||||
```
|
||||
|
||||
Both servers respond with stratum 2/3. The client config uses `restrict`
|
||||
rules (not `interface listen`) to avoid the loopback-binding bug that
|
||||
prevented sync. This is safe under both Tailscale-managed and LAN-pinned
|
||||
resolver configurations.
|
||||
|
||||
## 5. Recommendation
|
||||
|
||||
### On fixed servers (always on-LAN)
|
||||
|
||||
**Deploy the managed `resolv.conf`** (`provisioning/ConfigFiles/Resolv/`):
|
||||
- Points at `.252`/`.253` with failover
|
||||
- `knel.net` records resolve on both servers
|
||||
- External names recurse on both servers
|
||||
- DNS survives `tailscaled` outages (unlike Tailscale-managed DNS)
|
||||
|
||||
To prevent Tailscale from overwriting the managed file:
|
||||
```bash
|
||||
tailscale up --accept-dns=false
|
||||
```
|
||||
|
||||
### On laptops / roaming hosts
|
||||
|
||||
**Let Tailscale manage DNS** (default `accept-dns=true`):
|
||||
- MagicDNS resolves `knel.net` device names via the tunnel
|
||||
- No dependency on LAN reachability
|
||||
- Accept the `tailscaled` dependency (if the tunnel is down, you're off-network anyway)
|
||||
|
||||
## 6. Subnet router HA (redundant routing)
|
||||
|
||||
> **Redmine:** [#377](https://projects.knownelement.com/issues/377)
|
||||
|
||||
Both DNS nodes advertise the LAN subnet as Tailscale subnet routes AND
|
||||
serve as exit nodes, providing full HA for remote monitoring (Uptime Kuma
|
||||
on the Cloudron VPS), off-site access, and internet egress:
|
||||
|
||||
| Node | Tailscale IP | Advertised routes | Role |
|
||||
|------|-------------|-------------------|------|
|
||||
| pfv-netinfra-01 | 100.70.181.72 | 192.168.0.0/22, 0.0.0.0/0, ::/0 | Primary subnet router + exit node |
|
||||
| pfv-netinfra-02 | 100.71.171.20 | 192.168.0.0/22, 0.0.0.0/0, ::/0 | Secondary subnet router + exit node (failover) |
|
||||
|
||||
To configure on a node (both flags together):
|
||||
```bash
|
||||
sudo tailscale set --advertise-routes=192.168.0.0/22 --advertise-exit-node
|
||||
```
|
||||
|
||||
**All routes must be approved** in the Tailscale admin console
|
||||
(https://login.tailscale.com/admin/machines) for failover to activate.
|
||||
This includes the subnet route (`192.168.0.0/22`) AND the exit node routes
|
||||
(`0.0.0.0/0`, `::/0`) — they appear as separate approvals on each machine.
|
||||
Tailscale uses the primary by default and fails over to the secondary if
|
||||
the primary's tunnel drops.
|
||||
|
||||
### Known instability factors (2026-08-06, [#377])
|
||||
|
||||
- **DERP relay bouncing:** netinfra-01 was observed switching between DERP
|
||||
relays (#9, #12, #13) every ~15 minutes, causing brief tunnel disruptions.
|
||||
- **Docker LinkChange events:** container create/destroy adds/removes bridge
|
||||
interfaces, triggering `LinkChange: major, rebinding` in tailscaled and
|
||||
momentarily dropping all connections.
|
||||
- **resolv.conf immutable flag:** netinfra-01 had the `+i` (immutable)
|
||||
attribute on `/etc/resolv.conf`, preventing tailscaled from updating DNS
|
||||
config after link changes. Fixed by `chattr -i /etc/resolv.conf`.
|
||||
|
||||
## 7. Known items / future work
|
||||
|
||||
1. **Pi-hole upstream configuration.** Pi-hole on both hosts should forward
|
||||
to the local Technitium instance (port 5300) for `knel.net` and to an
|
||||
external resolver for everything else. Verify this is configured on both
|
||||
nodes.
|
||||
2. **Zone transfer via AXFR.** Currently using rsync because Technitium's
|
||||
AXFR expects port 53. If Technitium's listen port can be changed, or
|
||||
Pi-hole can be configured to proxy AXFR, the rsync timer could be
|
||||
replaced with native DNS zone transfer.
|
||||
3. **`accept-dns=false` automation.** The provisioning code should set
|
||||
`--accept-dns=false` on Tailscale during setup (after deploying the
|
||||
managed `resolv.conf`) so Tailscale doesn't overwrite it on reboot.
|
||||
> **Documentation moved to Discourse — the canonical source of truth.**
|
||||
>
|
||||
> **Tailscale vs managed DNS analysis (resolved)**
|
||||
>
|
||||
> **Read it here:** https://community.turnsys.com/t/306
|
||||
>
|
||||
> *Migrated 2026-08-06. This file is kept as a pointer for git-browsing context.
|
||||
> Do not update content here — edit the Discourse wiki topic instead.*
|
||||
|
||||
Reference in New Issue
Block a user