Lightweight userspace tailscale networking without having to install system level VPN configuration
Swift
0
10 commits
updated Sep 26, 2026
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.
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:
localhost:3000) securely to your private tailnet via HTTPS with auto TLS.remote-nas.ts.net:80) to local ports (e.g. localhost:8080) via the built-in SOCKS5 forwarder with optional native TLS termination (--tls).LSUIElement = true).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 │
└────────────────────────────────────────────────────────────────────────┘
⌘C).⌘L) to automatically open Tailscale's authorization page in your default browser.●) and displays your node name, Tailscale IP, and MagicDNS domain.proxy remove, proxy add) are detected immediately on disk, refreshing the menu and forwarders the instant you click the icon.config.json in your default code editor.👉 For complete walkthroughs, submenus, and dialog options, see the Menu Bar Application Usage Guide.
The companion tail-userspace CLI allows complete terminal management and headless automation:
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
| 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 |
-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.
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.
TailUserspace-macOS.zip from GitHub Releases or Actions Artifacts.TailUserspace.app to your Applications folder:
unzip TailUserspace-macOS.zip
mv TailUserspace.app /Applications/
xattr -cr /Applications/TailUserspace.app
mkdir -p ~/.local/bin && cp tail-userspace-cli ~/.local/bin/tail-userspace
open /Applications/TailUserspace.app
👉 To compile from source instead, see Building from Source (Method B).
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.
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.
make test) and packaging (make dist).MIT License. See LICENSE for details.
Swift
98.9%
Lightweight userspace tailscale networking without having to install system level VPN configuration
Swift
0
10 commits
updated Sep 26, 2026
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.
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:
localhost:3000) securely to your private tailnet via HTTPS with auto TLS.remote-nas.ts.net:80) to local ports (e.g. localhost:8080) via the built-in SOCKS5 forwarder with optional native TLS termination (--tls).LSUIElement = true).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 │
└────────────────────────────────────────────────────────────────────────┘
⌘C).⌘L) to automatically open Tailscale's authorization page in your default browser.●) and displays your node name, Tailscale IP, and MagicDNS domain.proxy remove, proxy add) are detected immediately on disk, refreshing the menu and forwarders the instant you click the icon.config.json in your default code editor.👉 For complete walkthroughs, submenus, and dialog options, see the Menu Bar Application Usage Guide.
The companion tail-userspace CLI allows complete terminal management and headless automation:
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
| 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 |
-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.
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.
TailUserspace-macOS.zip from GitHub Releases or Actions Artifacts.TailUserspace.app to your Applications folder:
unzip TailUserspace-macOS.zip
mv TailUserspace.app /Applications/
xattr -cr /Applications/TailUserspace.app
mkdir -p ~/.local/bin && cp tail-userspace-cli ~/.local/bin/tail-userspace
open /Applications/TailUserspace.app
👉 To compile from source instead, see Building from Source (Method B).
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.
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.
make test) and packaging (make dist).MIT License. See LICENSE for details.
Swift
98.9%