fix(tailscale-router): masquerade LAN traffic into Tailscale
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m31s

Without SNAT on tailscale0, Tailscale drops forwarded packets from LAN
source IPs (192.168.2.x) because they are not recognised Tailscale
addresses.  With networking.nat.externalInterface = "tailscale0", all
traffic leaving through the Tailscale tunnel is masqueraded to the
router's own Tailscale IP (100.x.x.x), making it indistinguishable from
locally-originated traffic.  Conntrack handles the return path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 09:45:07 +10:00
co-authored by Claude Sonnet 4.6
parent 6c1cc821a0
commit cda2132d6a
+14 -1
View File
@@ -1,4 +1,4 @@
{ ... }: { vars, ... }:
{ {
imports = [ imports = [
@@ -12,8 +12,21 @@
# own setting) so the intent is clear at the build-type level. # own setting) so the intent is clear at the build-type level.
services.tailscale.useRoutingFeatures = "server"; services.tailscale.useRoutingFeatures = "server";
# Advertise the LAN subnet so Tailscale peers can route back to LAN machines.
# Must also be approved in the Tailscale admin console (Machines → Edit route settings).
services.tailscale.extraUpFlags = [ "--advertise-routes=${vars.lanCidr}" ];
# Forwarded subnet-router traffic arrives on tailscale0 already # Forwarded subnet-router traffic arrives on tailscale0 already
# tailscale-authenticated -- the firewall's normal per-port allow-list # tailscale-authenticated -- the firewall's normal per-port allow-list
# would otherwise drop it. Standard NixOS/Tailscale subnet-router guidance. # would otherwise drop it. Standard NixOS/Tailscale subnet-router guidance.
networking.firewall.trustedInterfaces = [ "tailscale0" ]; networking.firewall.trustedInterfaces = [ "tailscale0" ];
# SNAT traffic from LAN machines going out through Tailscale so the remote
# peer sees it sourced from this router's Tailscale IP (100.x.x.x) rather
# than a raw LAN IP. Without this, Tailscale drops the forwarded packets
# because the source is not a recognised Tailscale address.
networking.nat = {
enable = true;
externalInterface = "tailscale0";
};
} }