Isolate Tailscale to specific interfaces using Linux network namespaces.
Creates virtual interface with its own MAC on the physical NIC. Simpler, no NAT. Best for bare metal where you control the network.
ip netns add tsns
ip link add ts-mgmt link eth0 type macvlan mode bridge
ip link set ts-mgmt netns tsns
ip netns exec tsns ip addr add 192.168.1.100/24 dev ts-mgmt
ip netns exec tsns ip link set ts-mgmt up
ip netns exec tsns ip route add default via 192.168.1.1Pros: No NAT, gets real IP on LAN Cons: Blocked in cloud (EC2 source/dest check), host can't directly reach namespace
Virtual ethernet pair between host and namespace. Works everywhere.
ip netns add tsns
# Create veth pair
ip link add veth-host type veth peer name veth-ns
ip link set veth-ns netns tsns
# Configure host side
ip addr add 192.168.100.1/24 dev veth-host
ip link set veth-host up
# Configure namespace side
ip netns exec tsns ip addr add 192.168.100.2/24 dev veth-ns
ip netns exec tsns ip link set veth-ns up
ip netns exec tsns ip link set lo up
ip netns exec tsns ip route add default via 192.168.100.1
# NAT namespace traffic to physical interface
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0 -j MASQUERADE
iptables -A FORWARD -i veth-host -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o veth-host -j ACCEPTReplace eth0 with your physical interface.
ip netns exec tsns tailscaled \
--state=/var/lib/tailscale-ns/tailscaled.state \
--socket=/var/run/tailscale-ns/tailscaled.sock &
ip netns exec tsns tailscale \
--socket=/var/run/tailscale-ns/tailscaled.sock \
up --accept-routesip netns exec tsns my-app
ip netns exec tsns curl http://100.x.x.xAllow host apps to reach Tailscale IPs via the namespace:
# Route Tailscale CGNAT range through namespace
ip route add 100.64.0.0/10 via 192.168.100.2
# Enable forwarding in namespace
ip netns exec tsns sysctl -w net.ipv4.ip_forward=1
ip netns exec tsns iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o tailscale0 -j MASQUERADE
ip netns exec tsns iptables -A FORWARD -i veth-ns -o tailscale0 -j ACCEPT
ip netns exec tsns iptables -A FORWARD -i tailscale0 -o veth-ns -j ACCEPTNow host apps can reach Tailscale IPs:
ping 100.x.x.x # works from host
curl http://peer:8080 # works from host# /etc/systemd/system/tailscaled-ns.service
[Unit]
Description=Tailscale in Network Namespace
After=network.target
[Service]
ExecStartPre=/usr/local/bin/setup-tsns.sh
ExecStart=/usr/sbin/ip netns exec tsns /usr/sbin/tailscaled \
--state=/var/lib/tailscale-ns/tailscaled.state \
--socket=/var/run/tailscale-ns/tailscaled.sock
Restart=on-failure
[Install]
WantedBy=multi-user.targetFor systems with timing-sensitive interfaces (motor control, PCIe fabrics, sensor networks):
# Create namespace with only management interface
ip netns add tsns
ip link add ts-mgmt link eth0 type macvlan mode bridge # eth0 is management
ip link set ts-mgmt netns tsns
# ... configure IP
# Tailscale runs in tsns, sees only ts-mgmt
# Real-time interfaces (eth_rt0, pcie0) stay in root namespace
# Tailscale cannot touch themTailscale's MagicDNS won't automatically work since systemd-resolved runs in the host namespace. Configure DNS before creating the namespace:
# Create resolv.conf BEFORE namespace setup
mkdir -p /etc/netns/tsns
cat > /etc/netns/tsns/resolv.conf << 'EOF'
nameserver 100.100.100.100
search your-tailnet.ts.net
EOFThe /etc/netns/<name>/resolv.conf is automatically bind-mounted into the namespace on each ip netns exec.
Important: The file must exist before you run ip netns exec. If you create it after, it won't apply until the next ip netns exec call.
Verify:
ip netns exec tsns cat /etc/resolv.conf
ip netns exec tsns nslookup peer-hostname
ip netns exec tsns ping peer-hostname- Tailscale in namespace cannot see or use interfaces outside
- All traffic (STUN, DERP, WireGuard) confined to namespace interfaces
- Subnet routes work with
--accept-routes - DNS requires explicit configuration (see above)