# Check node status and connected peerstailscalestatus
# Test connectivity to a specific tailscale nodetailscaleping<hostname-or-ip>
# Show current IP and hostnametailscaleip
tailscaleip-4# IPv4 onlytailscaleip-6# IPv6 only# Full status with peer detailstailscalestatus--json|jq.
# Check if tailscale is uptailscalestatus--json|jq'.BackendState'# List all peers and their online statustailscalestatus--json|jq-r'.Peer[] | "\(.HostName)\t\(.TailscaleIPs[0])\t\(.Online)"'# Show currently active exit nodetailscalestatus--json|jq'.ExitNodeStatus'# Debug network connectivity issuestailscalenetcheck
>**One-liner:**`tailscalenetcheck`isyourfirstdiagnostic.IttestsDERPrelayconnectivity,NATtype,andUDPavailabilityinonecommand.If`MappingVariesByDestIP:true`,youhavesymmetricNATanddirectconnectionswon't work — traffic will always relay through DERP.# Check key expirytailscale status --json | jq -r '.Peer[]|select(.KeyExpiry!=null)|"\(.HostName): expires \(.KeyExpiry)"'# Show Tailscale routes (subnet routes)tailscale status --json | jq -r '.Peer[]|select(.PrimaryRoutes!=null)|"\(.HostName): \(.PrimaryRoutes[])"'
# Bring tailscale up with specific optionstailscaleup--authkey=<key>
# Bring up with subnet routingtailscaleup--advertise-routes=10.0.0.0/8,192.168.1.0/24
# Bring up as exit nodetailscaleup--advertise-exit-node
# Bring up with hostname overridetailscaleup--hostname=my-server-prod
# Bring up with tags (for ACL matching)tailscaleup--advertise-tags=tag:server,tag:prod
# Bring up with custom DNStailscaleup--accept-dns=true# Disconnect temporarily (keeps config)tailscaledown
# Logout and remove node from networktailscalelogout
# Send a file to a tailscale peertailscalefilecp./report.pdfmy-laptop:
# Receive filestailscalefileget~/Downloads/
# Check file transfer statustailscalefilestatus
# Connect to a node via Tailscale SSHsshuser@hostname.tail-domain.ts.net
# or by tailscale IPsshuser@100.x.x.x
# Use tailscale funnel to expose local port (HTTPS, publicly accessible)tailscalefunnel8080# Check funnel statustailscalefunnelstatus
Scenario 1: Node shows offline but machine is running¶
# On the unreachable node, check daemon statussystemctlstatustailscaled
journalctl-utailscaled-n50# Check if daemon is listeningtailscalestatus
# If daemon died, restart itsystemctlrestarttailscaled
# Check for key expirytailscalestatus--json|jq'.Self.KeyExpiry'# If key is expired, reauthenticatetailscaleup# prompts for new auth# Run netcheck to verify relay connectivitytailscalenetcheck
# Check if the node can reach DERP relaystailscaledebugderp-map|jq'.Regions[].Nodes[] | {hostname, ipv4}'
Scenario 2: Subnet router not working — devices on the subnet unreachable¶
# Verify the router node is advertising routestailscalestatus--json|jq'.Self.AdvertisedRoutes'# Routes must also be APPROVED in the admin console# Check if routes are approved (enabled):tailscalestatus--json|jq'.Self.PrimaryRoutes'# PrimaryRoutes shows what's actually active; AdvertisedRoutes shows what's offered>**Defaulttrap:**Advertisingasubnetrouteisnotenough—routesmustbeexplicitlyapprovedintheTailscaleadminconsole.Andontheclientside,`--accept-routes`mustbepassedto`tailscaleup`.Threeseparatestepsthatallmustbecorrect:advertise,approve,accept.
# On the client side, check accepted routestailscalestatus--json|jq'.Peer[] | select(.HostName=="my-router") | .PrimaryRoutes'# Enable route acceptance on clienttailscaleup--accept-routes
# Verify IP forwarding is on the subnet routercat/proc/sys/net/ipv4/ip_forward# must be 1sysctl-wnet.ipv4.ip_forward=1# Make permanent:echo"net.ipv4.ip_forward = 1">>/etc/sysctl.d/99-tailscale.conf
# Test from client — can you ping a device behind the subnet router?tailscaleping192.168.1.50# direct test through tailscale
# Check if traffic is being blocked (ACL issue shows as timeout, not refused)tailscaleping<peer># if this works, layer 3 is fine# Try the actual port:curl-vhttp://<tailscale-ip>:8080/# if this hangs, ACL is blocking# Debug ACL enforcementtailscaledebugaccess<dst-ip><port><proto>
# Example:tailscaledebugaccess100.64.1.580tcp
# MagicDNS not resolving? Checktailscalestatus--json|jq'.MagicDNSSuffix'# Test resolution:dig@100.100.100.100my-server.tail-xyz.ts.net
# Split DNS: check which DNS servers are assigned for which domainstailscalestatus--json|jq'.DNS'
Scenario 4: Slow performance — forcing direct connection instead of relay¶
# Check if connection is direct or relayed (DERP)tailscalestatus--json|jq-r'.Peer[] | "\(.HostName): \(.Relay) \(if .CurAddr != "" then "DIRECT:" + .CurAddr else "RELAYED" end)"'# Force a re-probe for direct pathtailscaleping--until-direct<peer>
# Check what's blocking direct: firewall, NAT typetailscalenetcheck
# Look for: "MappingVariesByDestIP: true" (symmetric NAT, will use relay)# Look for: "HairPinning: false" (devices on same network can't talk directly)# Check latency via relay vs expected directtailscaleping--count10<peer>
# If stuck on relay, check UDP 41641 is open outbound on both sides# Tailscale uses UDP 41641 for direct connections by default>**Debugclue:**If`tailscaleping--until-direct<peer>`nevertransitionsfrom"via DERP"toadirectaddress,bothsideslikelyhaverestrictiveNATorafirewallblockingUDP41641outbound.Corporatefirewallsarethemostcommoncause—TailscaleworksoverDERPrelayinthiscase,butlatencywillbehigher.
1.Ontheexitnode:
tailscaleup--advertise-exit-node
2.Approveinadminconsole:
Machines->selectnode->Editroutesettings->enable"Use as exit node"3.Onclienttousetheexitnode:
tailscaleup--exit-node=<hostname-or-ip>
# or via GUI4.Verify:
curlhttps://ifconfig.me# should show exit node's public IP5.Tostopusingexitnode:
tailscaleup--exit-node=
1. Check which nodes have expiring keys:
tailscale status --json | jq -r '.Peer[] | select(.KeyExpiry != null) | "\(.HostName): \(.KeyExpiry)"'
2. For servers that must stay connected, disable key expiry in admin console:
Machines -> select node -> Disable key expiry
3. For service accounts, use auth keys with long TTL or disable expiry:
# In admin console: Settings -> Keys -> Generate auth key
# Check "Reusable" and "No expiry" for long-lived service nodes
4. To reauthenticate an expired node:
tailscale up # prompts for login if key expired
# or with auth key:
tailscale up --authkey=<new-key>
1.AlwaystestACLchangesinastagingtailnetfirst.
2.Format:HuJSON(JSONwithcomments)Keyblocks:hosts,groups,tagOwners,acls,ssh,tests
3.Validatebeforesaving:
-Usethe"Test"buttoninadminconsole
-OrusetailscaledebugaccesstotestfromCLI
4.CommonACLpatterns:
# Allow all access within a group:{"action":"accept","src":["group:devs"],"dst":["*:*"]}# Allow only specific ports to tagged servers:{"action":"accept","src":["group:devs"],"dst":["tag:prod:22,80,443"]}5.Denyisimplicit—everythingnotallowedisdenied.
Ifyoucannotconnect,checkACLsbeforeanythingelse.
>**Gotcha:**ACLchangestakeeffectimmediatelyacrosstheentiretailnet—thereisnostagingorgradualrollout.AsyntaxerrorinyourACLfilecaninstantlylockeverynodeoutofeveryothernode.Alwaysusethe"Test"buttonintheadminconsolebeforesaving,andkeepabrowsertabopentotheadminconsolesoyoucanrevertifneeded.