krishnakumar4a4/tail-userspace: Lightweight userspace tailscale networking without having to install system level VPN configuration

github.com · 2026-10-02 · by Long Nguyen ·github
Lightweight userspace tailscale networking without having to install system level VPN configuration - krishnakumar4a4/tail-userspace

krishnakumar4a4/tail-userspace

Lightweight userspace tailscale networking without having to install system level VPN configuration - krishnakumar4a4/tail-userspace

0 stars · 0 forks

README

TailUserspace for macOS

A lightweight, unprivileged macOS menu bar application and shell CLI for Tailscale in Userspace Networking Mode (tailscaled --tun=userspace-networking). Designed with UX ideas inspired by Trayscale, built natively in Swift for macOS without any Linux GTK4 or Libadwaita dependencies.

Why TailUserspace? Standard Tailscale on macOS requires root/admin permissions, installs a system-wide Network Extension (VPN profile), and routes all device traffic through a virtual utun adapter. TailUserspace runs 100% in user space without sudo:

Zero Root / No Admin Rights: Runs unprivileged with isolated state in your user Library. No System VPN Profile: Does not touch your Mac's system network settings, DNS, or VPN profiles. Bidirectional Port Forwarding:

Inbound (Serve): Expose local ports (e.g. localhost:3000) securely to your private tailnet via HTTPS with auto TLS. Outbound (Proxy): Map remote tailnet services (e.g. remote-nas.ts.net:80) to local ports (e.g. localhost:8080) via the built-in SOCKS5 forwarder with optional native TLS termination (--tls).

Coexists with Tailscale Desktop: Can run simultaneously alongside the official Tailscale Desktop app as an isolated secondary node on your tailnet. Native & Featherweight: ~398 KB bundle, <15 MB RAM, instant startup, zero Dock clutter (LSUIElement = true).

Menu Bar Application TailUserspace lives quietly in your macOS menu bar, providing real-time status and interactive controls: ┌────────────────────────────────────────────────────────────────────────┐ │ ● Tailscale: my-mac │ │ IP: 100.64.0.1 (Click to copy IP) │ │ Domain: my-mac.tailnet-xyz.ts.net (Click to copy domain) │ ├────────────────────────────────────────────────────────────────────────┤ │ Disconnect ⌘D │ │ Re-authenticate... │ ├────────────────────────────────────────────────────────────────────────┤ │ INBOUND SERVE (LOCAL ➔ TAILNET) │ │ ● localhost:8787 ➔ https://:443/ ▶ [ Submenu: │ │ • Active / Pause │ │ • Open in Browser │ │ • Copy Tailnet URL │ │ • Copy Local URL │ │ • Edit Route... │ │ • Delete Route... ] │ │ [+] Add Serve Route... │ ├────────────────────────────────────────────────────────────────────────┤ │ OUTBOUND REMOTE PROXIES (TAILNET ➔ LOCAL) │ │ ● localhost:9443 ➔ remote-node.ts.net:443 [TLS] ▶ [ Submenu: │ │ • Active / Pause │ │ • Open Local Endpoint │ │ • Copy Local / Remote URL │ │ • Edit Proxy... │ │ • Delete Proxy... ] │ │ [+] Add Outbound Proxy... │ ├────────────────────────────────────────────────────────────────────────┤ │ USERSPACE PROXIES & SHELL ENVIRONMENT │ │ SOCKS5 Proxy: 127.0.0.1:1055 (Click to copy address) │ │ HTTP Proxy: 127.0.0.1:1056 (Click to copy address) │ │ Copy Shell Export (ALL_PROXY) │ ├────────────────────────────────────────────────────────────────────────┤ │ CONFIGURATION & DIAGNOSTICS │ │ Open Configuration File (config.json) │ │ View Configuration in App... │ │ Reveal Data Directory in Finder │ │ View Daemon Logs (tailscaled.log) │ │ Reset Tailscale Serve... │ ├────────────────────────────────────────────────────────────────────────┤ │ Tailscale Userspace v1.0 (Darwin) │ │ Quit TailUserspace ⌘Q │ └────────────────────────────────────────────────────────────────────────┘

Authenticating via Menu Bar

Click the status bar icon and choose Connect (or press ⌘C). If login is required, the menu highlights ▲ Tailscale: Login Required. Click Log In with Browser... (or press ⌘L) to automatically open Tailscale's authorization page in your default browser. Once authenticated, the menu bar icon turns green (●) and displays your node name, Tailscale IP, and MagicDNS domain.

Key Menu Bar Features

Instant CLI ↔ GUI Sync: CLI changes (e.g. proxy remove, proxy add) are detected immediately on disk, refreshing the menu and forwarders the instant you click the icon. Interactive Route Management: Every Inbound Serve route and Outbound Remote Proxy includes options to Pause / Resume, Edit Route/Proxy, and Delete. Configuration Viewer: Inspect raw JSON directly using "View Configuration in App..." or open config.json in your default code editor.

👉 For complete walkthroughs, submenus, and dialog options, see the Menu Bar Application Usage Guide.

Command-Line Interface (CLI) The companion tail-userspace CLI allows complete terminal management and headless automation: Authenticating via CLI Running tail-userspace up connects to the tailnet. If authorization is needed, it extracts the login URL, automatically launches your browser, and waits for authentication to complete: tail-userspace up Connecting to Tailscale network... ============================================================================ Tailscale Authentication Required 👉 https://login.tailscale.com/a/0123456789abcdef ============================================================================ Opening URL in your default browser... Waiting for authentication in browser... (Press Ctrl+C to cancel)

✓ Connected to Tailscale network! Node DNS: my-mac.tailnet-xyz.ts.net Tailnet IP: 100.64.0.1

Core CLI Commands

Command Description

tail-userspace up Connects to tailnet with automated browser login flow

tail-userspace down Disconnects from tailnet

tail-userspace status Displays daemon PID, connection state, IPs, and routes

tail-userspace start Starts unprivileged daemon in background

tail-userspace stop Shuts down daemon and all proxy listeners

eval $(tail-userspace env) Exports ALL_PROXY variables to your current shell session

tail-userspace serve add <port> Exposes local port to tailnet via HTTPS (port 443)

tail-userspace serve list Lists all configured inbound serve routes

tail-userspace serve remove <port> Removes an inbound serve route

tail-userspace proxy add <local> <target> [--tls] Forwards local port to remote tailnet service (with optional TLS termination)

tail-userspace proxy list Lists all active outbound remote proxies

tail-userspace proxy remove <local> Removes an outbound proxy and frees the local port

tail-userspace logs Prints absolute path to tailscaled.log

Verbosity Flags (-v and -vv) Pass -v (verbose diagnostics) or -vv (full debug trace with raw JSON dumps and process standard I/O) to any command: tail-userspace status -v tail-userspace up -vv 👉 For complete command syntax, advanced flags, and scripting examples, see the CLI Reference & Usage Guide.

Installation & Setup Prerequisites TailUserspace utilizes the official open-source Tailscale engine in userspace mode. On any fresh Mac, ensure Tailscale is installed:

Install Tailscale engine via Homebrew

brew install tailscale

Note: You do not need to run sudo brew services start tailscale. TailUserspace supervises its own unprivileged child daemon process automatically.

Recommended: Install Pre-Built Release

Download TailUserspace-macOS.zip from GitHub Releases or Actions Artifacts. Extract and move TailUserspace.app to your Applications folder: unzip TailUserspace-macOS.zip mv TailUserspace.app /Applications/

Clear Gatekeeper Quarantine Flag: Since the binary is ad-hoc signed, remove the macOS browser quarantine flag: xattr -cr /Applications/TailUserspace.app

(Optional) Install the CLI globally: mkdir -p ~/.local/bin && cp tail-userspace-cli ~/.local/bin/tail-userspace

Launch the Menu Bar App: open /Applications/TailUserspace.app

👉 To compile from source instead, see Building from Source (Method B).

Configuration & Persistence All routes, forwarders, and settings are saved atomically to: ~/Library/Application Support/TailUserspace/config.json { "autoStart": true, "socks5Port": 1055, "httpProxyPort": 1056, "serveRoutes": [ { "id": "A6973C99-C6E9-4849-B208-9250740B3B3D", "localPort": 8787, "servePort": 443, "proto": "https", "path": "/", "enabled": true } ], "remoteProxies": [ { "id": "B1234D56-E789-0123-F456-7890ABCDEF12", "localPort": 9443, "remoteHost": "remote-node.tailnet.ts.net", "remotePort": 443, "terminateTLS": true, "enabled": true } ] } Whenever the daemon starts or reconnects, all enabled routes are automatically restored and re-applied.

Architecture TailUserspace operates with an unprivileged process model that isolates WireGuard tunnels, state files, and UNIX sockets inside your user session without root permissions. 👉 For detailed architecture diagrams, bidirectional traffic flows, TLS termination mechanics, and cache coherency design, see TailUserspace Architecture.

Maintenance & Development

How to Update: Upgrade steps preserving your tailnet credentials and routes. Clean Uninstallation: Complete removal of binaries, sockets, and configuration. Development & Testing: Running the test suite (make test) and packaging (make dist).

License MIT License. See LICENSE for details.

source

github.com · 5 images · 106 links

Comments (0)

No comments yet