tsnet_flutter 0.3.0
tsnet_flutter: ^0.3.0 copied to clipboard
Embed Tailscale's tsnet in Flutter apps. Provides a userspace WireGuard tunnel with a localhost TCP proxy — no VPN entitlement needed on iOS.
tsnet_flutter #
Embed Tailscale's tsnet in Flutter apps. Provides a userspace WireGuard tunnel with a localhost TCP proxy — no VPN entitlement needed on iOS.
How it works #
Flutter App (Dart)
└── tsnet_flutter plugin
├── iOS/macOS: Swift MethodChannel → C bridge → Go static library (.a)
└── Android/Linux: Dart FFI → Go shared library (.so)
↓
Go tsnet (WireGuard + userspace netstack)
↓
localhost TCP proxy (127.0.0.1:PORT)
↓
WireGuard tunnel → remote device (100.x.x.x)
Your app connects to localhost:PORT. Traffic is forwarded through a WireGuard tunnel to the target device's Tailscale IP. Your app doesn't know about Tailscale — it just sees a localhost port.
Usage #
import 'package:tsnet_flutter/tsnet_flutter.dart';
final tsnet = TsnetFlutter();
// Join the Tailnet
await tsnet.start(authKey: 'tskey-auth-...');
// Create a local proxy to the remote device
final localPort = await tsnet.startProxy('100.64.0.5', port: 5050);
// Connect your client to the proxy
yourClient.connect('127.0.0.1', port: localPort);
// Clean up
await tsnet.stopProxy();
await tsnet.stop();
API #
| Method | Description |
|---|---|
start(authKey, hostname) |
Join a Tailnet with an auth key. Idempotent — safe to call multiple times. |
startProxy(ip, port) |
Create a localhost TCP proxy to a remote Tailscale IP. Returns the local port. |
stopProxy() |
Stop the localhost proxy. |
stop() |
Disconnect from the Tailnet. |
status() |
Get the current Tailscale connection status (state, peers, IPs). |
tailscaleIP() |
Get this device's Tailscale IPv4 address (100.x.x.x). |
Platform support #
| Platform | Tailscale tunnel | Binary type | Architectures |
|---|---|---|---|
| iOS | Supported | c-archive (.a in xcframework) | arm64 device + arm64 simulator |
| macOS | Supported | c-archive (.a in xcframework) | arm64 + x86_64 universal |
| Linux | Supported | c-shared (.so) | amd64 |
| Android | Local only (WIP) | c-shared (.so in jniLibs) | arm64-v8a + x86_64 |
Android note: Local TCP connections work. Tailscale tunnel is blocked by Go's net.Interfaces() requiring CAP_NET_ADMIN on Android. Full tunnel support will require libtailscale integration from tailscale-android.
Platform setup #
iOS #
No special entitlements or permissions needed. No VPN entitlement required.
macOS #
macOS apps run sandboxed. Add these entitlements to both DebugProfile.entitlements and Release.entitlements:
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
network.client allows the app to connect to the localhost proxy and external networks.
network.server allows the Go layer to open a localhost listener for the proxy.
Android #
Add the INTERNET permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Linux #
No special setup needed. The shared library is bundled automatically.
Requirements #
- Tailscale auth key — generate at login.tailscale.com/admin/settings/keys
- Auth keys can be reusable and tag-scoped for ACL isolation
Building from source #
The pre-built binaries are included in the package. To rebuild from Go source:
# Prerequisites: Go 1.23+, Xcode (for Apple platforms), Android NDK (for Android)
./build_go.sh # build all platforms
./build_go.sh ios # iOS only
./build_go.sh macos # macOS only
./build_go.sh android # Android only (requires NDK)
./build_go.sh linux # Linux only (uses Docker on macOS)
./build_go.sh apple # iOS + macOS
Binary sizes #
| Platform | Size | Notes |
|---|---|---|
| iOS (device) | ~23 MB | After App Store compression: ~14 MB |
| iOS (simulator) | ~23 MB | Development only |
| macOS (universal) | ~49 MB | arm64 + x86_64 |
| Android (arm64) | ~20 MB | |
| Android (x86_64) | ~22 MB | Emulator only |
| Linux (amd64) | ~24 MB |
Size is dominated by WireGuard + gVisor netstack + Go runtime. Feature tags strip ~35 unused Tailscale subsystems (SSH, Drive, Serve, etc.).
License #
BSD-3-Clause — compatible with Tailscale's license. See LICENSE.