Zum Inhalt springen

Tailscale

Overview

Tailscale is a mesh VPN built on WireGuard that connects your devices into a private network called a tailnet. Unlike traditional VPNs, Tailscale uses a peer-to-peer architecture — devices communicate directly when possible (using DERP relay servers as fallback) without traffic flowing through a central gateway. Features include MagicDNS (automatic device.tail123.ts.net hostnames), ACL policies, exit nodes, subnet routing, SSH key management, Funnel (exposing local services publicly), and Tailnet Lock (cryptographic key verification).

Installation

Linux (one-line installer)

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Debian / Ubuntu

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt-get update && sudo apt-get install tailscale
sudo tailscale up

macOS

brew install tailscale
# Or download from https://tailscale.com/download/mac
sudo tailscaled &
tailscale up

Windows

winget install tailscale.tailscale

Docker (subnet router / exit node)

docker run -d \
  --name tailscale \
  --network host \
  --cap-add=NET_ADMIN \
  --cap-add=NET_RAW \
  -v /var/lib/tailscale:/var/lib/tailscale \
  -e TS_AUTHKEY=tskey-auth-xxx \
  -e TS_HOSTNAME=my-container \
  tailscale/tailscale:latest

Verify

tailscale version
tailscale status

Configuration

Initial login and options

# Basic login (opens browser)
sudo tailscale up

# Login with auth key (headless/server)
sudo tailscale up --authkey tskey-auth-xxxxxxxxxx

# Login with reusable auth key
sudo tailscale up --authkey tskey-auth-xxx?ephemeral=false

# Login with all features enabled
sudo tailscale up \
  --accept-routes \
  --accept-dns \
  --advertise-exit-node \
  --ssh \
  --hostname my-server

Admin Console (web UI)

Access at https://login.tailscale.com/admin/ to manage:

  • Devices (approve, disable, remove)
  • ACL policies (JSON-based firewall rules)
  • DNS settings (MagicDNS, nameservers)
  • Auth keys (ephemeral, reusable, pre-authorized)
  • Users and roles
  • Tailnet settings

ACL policy (admin console)

{
  "acls": [
    {
      "action": "accept",
      "src": ["tag:developer"],
      "dst": ["tag:server:22,80,443"]
    },
    {
      "action": "accept",
      "src": ["autogroup:admin"],
      "dst": ["*:*"]
    }
  ],
  "tagOwners": {
    "tag:server": ["autogroup:admin"],
    "tag:developer": ["autogroup:member"]
  },
  "grants": [
    {
      "src": ["tag:developer"],
      "dst": ["tag:server"],
      "app": {
        "tailscale.com/cap/ssh": [{"action": "check"}]
      }
    }
  ]
}

Core Commands

CommandDescription
tailscale upConnect to tailnet
tailscale downDisconnect (keeps daemon running)
tailscale logoutLog out and remove node from tailnet
tailscale statusShow connected devices and IPs
tailscale status --jsonJSON status output
tailscale ping hostnamePing a tailnet device
tailscale ipShow your tailnet IP address
tailscale ip -4Show IPv4 tailnet address only
tailscale netcheckCheck NAT traversal and relay latency
tailscale ssh user@deviceSSH to a tailnet device
tailscale serve 8080Serve local port 8080 on tailnet
tailscale serve https / proxy http://localhost:3000HTTPS proxy on tailnet
tailscale funnel 8080Expose port publicly via Funnel
tailscale funnel offDisable Funnel
tailscale whois 100.x.y.zLook up a tailnet IP
tailscale dns statusShow DNS configuration
tailscale lock initInitialize Tailnet Lock
tailscale lock add keyTrust a signing key
tailscale set --sshEnable Tailscale SSH on device
tailscale set --advertise-exit-nodeMake device an exit node
tailscale set --advertise-routes 10.0.0.0/24Advertise subnet routes

Advanced Usage

Exit nodes

# On the device that will be the exit node:
sudo tailscale up --advertise-exit-node

# In admin console: approve the exit node under Machines tab

# On client: use the exit node
tailscale set --exit-node=server-hostname
tailscale set --exit-node-allow-lan-access=true  # Keep LAN access

# Remove exit node
tailscale set --exit-node=

# Verify exit node is active
curl https://ifconfig.me  # Should show exit node's IP

Subnet routing

# On the subnet router (connected to internal network):
sudo tailscale up --advertise-routes=10.0.0.0/24,192.168.1.0/24

# In admin console: approve the subnet routes

# On clients: enable accepting advertised routes
sudo tailscale up --accept-routes

# Verify route is accessible
tailscale status | grep subnets
ping 10.0.0.1  # Internal IP via subnet router

Tailscale SSH

# Enable Tailscale SSH on the server (replaces key management)
sudo tailscale up --ssh

# Connect from any device (no keys needed, uses Tailscale identity)
tailscale ssh ubuntu@my-server

# Or regular SSH via MagicDNS
ssh ubuntu@my-server.tail123.ts.net

Funnel (public HTTPS access)

# Expose a local web server publicly
tailscale funnel 3000

# Expose with a specific path
tailscale serve /api proxy http://localhost:8080/api
tailscale funnel 443

# Check current serve/funnel config
tailscale serve status

# Reset all serve config
tailscale serve reset

# Funnel creates a URL like: https://my-device.tail123.ts.net

Auth keys for automation

# Generate auth key in Admin Console > Settings > Keys
# Types:
#   - One-time use (expires after first auth)
#   - Reusable (can auth multiple devices)
#   - Ephemeral (device removed when offline)
#   - Pre-authorized (no approval needed)

# Use in CI/Docker/cloud-init
sudo tailscale up --authkey tskey-auth-xxxxxxxxxx \
  --hostname ci-runner-01 \
  --accept-routes

# Ephemeral key (auto-cleanup when agent stops)
sudo tailscale up --authkey tskey-auth-xxx?ephemeral=true

Device tags and ACL enforcement

# Apply tags at enrollment
sudo tailscale up --authkey tskey-auth-xxx \
  --advertise-tags tag:server,tag:production

# Verify tags
tailscale status --json | jq '.Self.Tags'

MagicDNS and nameservers

# Enable MagicDNS in admin console under DNS tab
# Devices get hostnames: hostname.tail1234.ts.net

# Add split DNS (route company.internal to internal nameserver)
# In admin console DNS tab: add nameserver for specific domain

# Check DNS resolution
tailscale dns status
dig myserver.tail1234.ts.net
nslookup myserver

Tailnet Lock (advanced security)

# Initialize Tailnet Lock (cryptographic device verification)
tailscale lock init

# Generate a node key to sign
tailscale lock tskey

# Add a trusted key
tailscale lock add nlpub:xxxxxx

# Sign a node
tailscale lock sign <nodekey>

# View trusted keys
tailscale lock status

Tailscale feature comparison

FeatureFreePersonal ProEnterprise
Devices100100Unlimited
Users31Unlimited
Subnet routersYesYesYes
Exit nodesYesYesYes
Tailscale SSHYesYesYes
FunnelYesYesYes
Custom domainsNoNoYes
SAML/SSONoNoYes
Priority supportNoNoYes

Common Workflows

Remote development server

# Server setup
sudo tailscale up --ssh --hostname dev-server

# VS Code Remote SSH via Tailscale
# In ~/.ssh/config:
# Host dev-server
#   HostName dev-server.tail1234.ts.net
#   User ubuntu

code --remote ssh-remote+dev-server /home/ubuntu/project

Kubernetes cluster access via subnet router

# On a node inside the cluster network
sudo tailscale up \
  --advertise-routes=10.96.0.0/12,10.244.0.0/16 \
  --accept-routes

# Approve routes in admin console

# On developer machine
sudo tailscale up --accept-routes
kubectl --server=https://10.96.0.1 get pods

GitHub Actions with Tailscale

name: Deploy
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: tailscale/github-action@v2
        with:
          oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
          oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
          tags: tag:ci

      - name: Deploy to internal server
        run: ssh ubuntu@my-internal-server.tail1234.ts.net 'make deploy'

Docker Compose internal network

# docker-compose.yml
services:
  tailscale:
    image: tailscale/tailscale:latest
    network_mode: host
    cap_add: [NET_ADMIN, NET_RAW]
    environment:
      TS_AUTHKEY: ${TS_AUTHKEY}
      TS_HOSTNAME: my-compose-app
      TS_EXTRA_ARGS: --advertise-tags=tag:compose
    volumes:
      - tailscale-data:/var/lib/tailscale

  app:
    image: myapp:latest
    network_mode: "service:tailscale"  # Share tailscale network namespace

volumes:
  tailscale-data:

Tips and Best Practices

Use ephemeral keys for CI and short-lived containers. Ephemeral nodes are automatically removed from your tailnet when the device goes offline, keeping your device list clean without manual cleanup.

Enable MagicDNS and use hostnames everywhere. Tailscale IPs can change when re-enrolling a device. Hostnames via MagicDNS are stable and far more readable in config files and scripts.

Apply tags via auth keys, not post-enrollment. Tags set through --advertise-tags during tailscale up are locked to the auth key’s tag owner and cannot be self-modified, providing stronger access control guarantees.

Use subnet routers instead of installing Tailscale on every host. For large internal networks or cloud VPCs, deploy one subnet router per network segment rather than requiring Tailscale on every VM.

Restrict ACLs to minimum necessary access. The default policy allows all traffic between all devices. Replace it with explicit rules based on tags and roles. Use autogroup:admin only for admin devices.

Enable Tailscale SSH for passwordless, key-free SSH. Tailscale SSH replaces SSH key management with identity-based access tied to your SSO provider. Combined with ACL grants and device posture checks, it is more secure than traditional key files.

Use Funnel for temporary public access instead of opening firewall ports. Expose a local development server or webhook endpoint via Funnel rather than punching holes in your firewall or setting up an nginx reverse proxy.

Monitor device expiry. By default, devices require re-authentication every 180 days. Set key expiry policies in the admin console and configure pre-expiry notifications to avoid losing access to remote servers.

Use tailscale netcheck to diagnose connectivity issues. This command reports DERP relay latency, NAT type, and UDP availability — essential for debugging slow connections or failed peer-to-peer establishment.

Combine Tailscale SSH with device posture checks. Configure grants with "action": "check" rather than "accept" to require devices to meet security posture requirements (OS version, patch status) before SSH is allowed.