elide tun up
Create a TUN device, authenticate with the Tailscale coordination server, establish WireGuard tunnels to all peers, and route traffic through the mesh.
elide tun up --auth-key tskey-auth-k1234567890abcdefElide connects to the coordination server via TS2021 (Noise IK handshake), fetches your network map, creates a kernel TUN device, installs peer routes, and starts the WireGuard data plane. The command runs in the foreground until SIGINT (Ctrl+C) or SIGTERM.
CAP_NET_ADMIN capability. On Linux you can grant the capability without running as root:
> sudo setcap cap_net_admin+ep $(which elide)
>---
Prerequisites
- Root or CAP_NET_ADMIN -- required for TUN device creation
- Tailscale pre-auth key -- generate one in the Tailscale admin console or your Headscale instance
---
CLI flags
elide tun up [OPTIONS]| Flag | Default | Description |
|---|---|---|
—auth-key | none | Tailscale pre-authentication key (tskey-auth-...). Required. Without this flag, tun up prints an error and exits |
—control-url | https://controlplane.tailscale.com | Tailscale coordination server URL. Set this to your Headscale instance URL for self-hosted coordination |
—dev | elide0 (Linux), auto (macOS) | TUN device name. On macOS, the kernel assigns a utun device automatically regardless of this flag |
—mtu | 1280 | MTU for the TUN interface. 1280 is the minimum for IPv6 and works across all network paths. Raise to 1420 on networks without encapsulation overhead |
—accept-routes | false | Accept routes advertised by other nodes (subnet routing). Peers advertising subnets via —advertise-routes will have those routes installed locally |
—exit-node | false | Advertise this node as an exit node, routing all peer traffic through it |
—use-exit-node | none | Route all traffic through a specific peer acting as an exit node (peer name or IP) |
—advertise-routes | none | Comma-separated CIDRs to advertise to the tailnet (e.g., 10.0.0.0/24,192.168.1.0/24). Peers with —accept-routes will route these subnets through this node |
—self-signed | false | Generate a self-signed TLS certificate for the node (ECDSA P-256, cached to disk, auto-regenerated after 30 days) |
—serve | none | Also start an HTTP server on the tunnel, listening on the given port. Combines tun up with serve in a single process |
—foreground | true | Run in the foreground (do not daemonize). Currently always true; daemon mode is not yet implemented |
—verbose | false | Enable verbose logging for debugging connectivity issues |
—json | false | Output tunnel status as JSON after startup. The JSON object includes status, device, addresses, domain, peers, and mtu |
Examples
Basic tunnel
Connect to your tailnet with a pre-auth key:
elide tun up --auth-key tskey-auth-k1234567890abcdefConnecting to control server...
Fetching network map...
Node ready: example.tail1234.ts.net (3 peers, 2 addresses)
Creating TUN device elide0...
TUN device elide0 created (mtu=1280)
Tailscale IP: 100.64.0.1
Tailscale IP: fd7a:115c:a1e0::1
Tunnel is up. Press Ctrl+C to stop.Custom device name and MTU
Use a named TUN device with a higher MTU for local networks:
elide tun up --auth-key tskey-auth-... --dev wg-prod --mtu 1420Headscale (self-hosted coordination)
Point at your own Headscale server:
elide tun up \
--auth-key your-headscale-preauth-key \
--control-url https://headscale.example.comSubnet router
Advertise a local network to the rest of the tailnet:
elide tun up \
--auth-key tskey-auth-... \
--advertise-routes 10.0.0.0/24,192.168.1.0/24Other nodes running with --accept-routes will route traffic for those subnets through this node.
Exit node
Advertise this node as an exit node (all peer traffic routes through it):
elide tun up --auth-key tskey-auth-... --exit -nodeOr route all your traffic through a specific peer:
elide tun up --auth-key tskey-auth-... --use-exit -node my-serverTunnel with HTTP server
Bring up the tunnel and serve files on the Tailscale network in one command:
elide tun up --auth-key tskey-auth-... --serve 8080JSON output for scripting
Get machine-readable startup status:
elide tun up --auth-key tskey-auth-... --json{
"status": "up",
"device": "elide0",
"addresses": ["100.64.0.1", "fd7a:115c:a1e0::1"],
"domain": "example.tail1234.ts.net",
"peers": 3,
"mtu": 1280
}---
Lifecycle
Startup sequence
1. Require --auth-key (exit 1 if not provided)
2. Connect to the coordination server with default machine keys
3. Authenticate with the pre-auth key
4. Fetch the network map
5. Install MagicDNS entries for all tailnet peers
6. Extract Tailscale IP addresses from the network map (both IPv4 and IPv6)
7. Build a WireGuard configuration from the network map
8. Create TUN device, assign addresses, and bring the interface up
9. Add kernel routes for all peer AllowedIPs
10. Spawn the data plane on a dedicated thread with the TUN device
11. Spawn a background thread for continuous map polling
12. Print status (Tailscale IPs, JSON if requested)
13. Block until SIGINT or SIGTERM
Background control thread
After startup, a dedicated background thread continuously polls the coordination server for network map changes. On each successful poll that is not a keep-alive:
- MagicDNS hostname-to-IP mappings are refreshed
- WireGuard peer configurations are recalculated
- DISCO peer info (node key, disco key, DERP region, endpoints) is sent to the data plane
- STUN endpoint discovery runs every 30 seconds, querying STUN servers in DERP regions and sending discovered endpoints to the data plane
On map poll error, the thread logs a warning, sleeps 5 seconds, and attempts to reconnect. If reconnection fails, the control thread exits.
Shutdown
On SIGINT (Ctrl+C) or SIGTERM:
1. The shutdown flag is set 2. The control thread observes the flag and exits its poll loop 3. The data plane is stopped and its thread is joined 4. The TUN device is removed, which closes the file descriptor and removes the kernel interface and routes
---
Status and down
tun status
Query the local Tailscale daemon (tailscaled) for tunnel state:
elide tun statusTailscale status: Running
Hostname: my-node.tail1234.ts.net
IP: 100.64.0.1
IP: fd7a:115c:a1e0::1Show peers and routes:
elide tun status --peers --routesShow DERP relay connections:
elide tun status --derpJSON output:
elide tun status --json{
"status": "Running",
"hostname": "my-node.tail1234.ts.net",
"ips": ["100.64.0.1", "fd7a:115c:a1e0::1"],
"peers": 3
}tun status queries the local Tailscale daemon (tailscaled) via its local API transport — a Unix domain socket at /var/run/tailscale/tailscaled.sock on Linux/macOS, or a named pipe at \\.\pipe\ProtectedPrefix\Administrators\Tailscale\tailscaled on Windows. It reports on the system-wide Tailscale state, not just Elide's tunnel process. If no Tailscale daemon is running, it reports disconnected.tun down
elide tun downIn the current release, tun up runs in the foreground. The primary way to stop the tunnel is Ctrl+C. tun down prints a message explaining this and exits cleanly. Daemon mode is not yet implemented.
---
Networking details
WireGuard
Elide uses boringtun for WireGuard -- a userspace implementation. The WireGuard engine manages per-peer state machines and handles:
- Encapsulation: Takes a plaintext IP packet and produces an encrypted WireGuard packet for the peer's UDP endpoint
- Decapsulation: Takes an encrypted packet from a peer and produces the plaintext IP packet
- Handshake rotation: Noise IK handshakes, key rotation, and cookie challenges are handled automatically
- Timer ticks: Every 250ms, keepalives, handshake retries, and connection health checks are driven
Key material is scrubbed from memory on cleanup.
DISCO
DISCO (Discovery) is Tailscale's peer-to-peer connectivity protocol. It uses NaCl-box-encrypted UDP packets with a TS + emoji magic header to exchange connectivity probes:
- Ping/Pong -- Bidirectional reachability probes. A pong proves a direct UDP path exists between two peers.
- CallMeMaybe -- One peer tells another "try to reach me at these candidate endpoints," triggering the other side to send pings to each candidate.
The DISCO manager runs inside the data plane thread. When STUN discovers public endpoints, those are forwarded to the DISCO manager, which distributes CallMeMaybe messages and upgrades peer paths from relay to direct once a direct ping/pong succeeds.
STUN endpoint discovery
STUN (Session Traversal Utilities for NAT) discovers the node's public IP and port as seen by external servers. Elide's endpoint discovery:
1. Binds a local UDP socket (0.0.0.0:0)
2. Sends RFC 8489 Binding Requests to STUN servers in each DERP region (default port 3478)
3. Parses Binding Responses to extract the reflexive mapped_address
4. Reports discovered endpoints (with RTT and DERP region) to the coordination server and data plane
Discovery runs every 30 seconds, ensuring endpoints stay fresh as NAT mappings change.
MagicDNS
When the tunnel is up, Elide populates the in-process DNS resolver with entries built from the network map. Both FQDNs and short names work:
ping my-server.tail1234.ts.net
ssh my-server
curl http://my-server.tail1234.ts.net:8080MagicDNS entries refresh automatically when the network map changes. The search domain from the DNS config is used for short-name resolution.
curl and ssh cannot resolve tailnet names unless a local DNS forwarder is configured separately. A built-in DNS forwarder is planned.Peer path selection
Each peer starts with a relay path through the nearest DERP region. The connection manager tracks per-peer path state and switches between:
- Relay -- Packets relayed through a DERP server. Always works, but adds a round trip through the relay.
- Direct -- Packets go directly over UDP to the peer's endpoint. Lower latency, no relay dependency.
DISCO automatically upgrades to direct paths when possible and falls back to relay when direct connectivity is lost.
---