Tailnet Addressing for Lab Services
Lab services are addressed by their Tailscale IP, not by a 192.168.x LAN address. The
tailnet address is the same whether the client is on the lab LAN or remote, and it does not
change when a DHCP lease moves. The docs previously recorded gpu-node-3 as 192.168.1.78
while the router had already moved it to 192.168.1.185, which is the failure mode this
rule exists to prevent.
| Service | Tailnet address | Node |
|---|---|---|
| RustFS S3 API | http://100.118.64.53:9000 | truenas-scale |
| RustFS console UI | http://100.118.64.53:9001 | truenas-scale |
| DuckLake PostgreSQL | 100.118.64.53:5432 | truenas-scale |
| Ray head dashboard | http://100.85.176.38:8265 | gpu-node-3 |
The TrueNAS instance is a VM on the samos host, and both are tailnet members. The services
are published by the VM, so truenas-scale is the address to use; samos (100.69.41.13)
exposes only SSH and is not a service endpoint.
Coexistence with Cloudflare WARP
Development machines run WARP in WarpWithDnsOverHttps mode alongside Tailscale. The two
do not conflict for routing, because the WARP split-tunnel policy is in Exclude mode and
already excludes both the tailnet CGNAT range 100.64.0.0/10 and 192.168.0.0/16. Traffic
to a tailnet address therefore leaves via tailscale0 rather than the WARP tunnel. Confirm
on any host with:
ip route get 100.118.64.53 # expect: dev tailscale0
warp-cli --accept-tos settings # expect 100.64.0.0/10 in the exclude listDocker containers inherit this. A container on a default bridge network reaches
100.118.64.53:9000 and :5432 without extra configuration, because WARP also excludes
172.16.0.0/12 and the host forwards to tailscale0.
MagicDNS
MagicDNS is enabled tailnet-wide with the suffix tail9b840.ts.net, but names do not
resolve on a WARP-managed machine, and they do not resolve inside containers at all. WARP
owns the system resolver and forwards queries to Cloudflare Gateway, which has no knowledge
of ts.net. Tailscale is consequently configured with accept-dns=false so the two do not
fight over /etc/resolv.conf.
This is why configuration files carry tailnet IPs rather than names such as
truenas-scale.tail9b840.ts.net. Do not switch them to names before the following is in
place on every consumer, containers included.
To make names resolve, add a Local Domain Fallback entry in the Cloudflare Zero Trust
dashboard under Settings, then WARP, then Local Domain Fallback: domain ts.net, resolver
100.100.100.100. The WARP settings on these machines are delivered by network policy, so
the change belongs in the dashboard rather than in warp-cli. Then enable the Tailscale
resolver on each host:
tailscale set --accept-dns=trueVerify from the host and from a container before relying on it, since the container path is the one that breaks:
getent hosts truenas-scale.tail9b840.ts.net
docker run --rm busybox nslookup truenas-scale.tail9b840.ts.netShort names are not a substitute. The lab router serves an internal search domain, so a
bare gpu-node-3 resolves to a LAN address rather than a tailnet one.
Subnet routing
No node advertises 192.168.1.0/24, so LAN addresses are unreachable from off-LAN. Adding
a subnet router would make every 192.168.x address work remotely without editing any
configuration, at the cost of depending on one advertising node and on route approval in
the Tailscale admin console. That option remains open, but it is not what the configuration
in this repository relies on.
Verifying an endpoint
tailscale status # peer online
nc -z -w3 100.118.64.53 9000 # port reachable from the host
docker run --rm busybox nc -z -w3 100.118.64.53 9000 # and from a containerAn unauthenticated GET against the S3 API returns 403 Forbidden. That response confirms
RustFS is answering rather than a connection silently succeeding against something else.