Single-binary TCP bridge between Windows and WSL. Zero-config, no dependencies, no installation. Statically linked Go binary.
WSL2 has its own virtual network. TCP services on localhost inside WSL are not always reachable from Windows (and vice versa) - depends on WSL version, distro state, and corporate proxies. The Windows tooling (netsh interface portproxy, wsl --list) requires admin, gets out of sync, and breaks on reboot.
wslink is a single Go binary that runs on either side and proxies TCP traffic:
flowchart TD
A[User runs wslink forward 8000] --> B{Which OS?}
B -->|Windows| C[wsl.exe --list --running]
C --> D[hostname -I inside distro]
D --> E[Target: WSL IP + port]
B -->|WSL/Linux| F["/etc/resolv.conf"]
F --> G[Parse nameserver = Windows host IP]
G --> H[Target: Windows IP + port]
E --> I[Listen on 127.0.0.1:8000]
H --> I
I --> J[Accept TCP connections]
J --> K[Bidirectional io.Copy proxy]
Direct TCP proxy - no netsh, no iptables, no admin, no leftover state. Press Ctrl-C and it's gone.
Windows
irm https://raw.githubusercontent.com/pyrofast/wslink/main/install.ps1 | iexLinux
curl -fsSL https://raw.githubusercontent.com/pyrofast/wslink/main/install.sh | bashGrab a binary from the latest release:
| OS | Arch | Binary |
|---|---|---|
| Windows | amd64 | wslink-windows-amd64.zip |
| Windows | arm64 | wslink-windows-arm64.zip |
| Linux | amd64 | wslink-linux-amd64.tar.gz |
| Linux | arm64 | wslink-linux-arm64.tar.gz |
You run wslink on the side where the client connects. It forwards the port to the other side.
Your app runs in WSL, you want to hit it from Windows:
# WSL side: start your service (example)
python3 -m http.server 8000
# Windows side: run wslink to bridge
wslink forward 8000
# Now you can open http://127.0.0.1:8000 in Windows browserIf you have multiple WSL distros, pick one:
wslink forward 8000 --wsl-name UbuntuYour app runs on Windows, you want to hit it from WSL:
# Windows side: start your service (example)
python -m http.server 8000
# WSL side: run wslink to bridge
wslink forward 8000
# Now you can open http://127.0.0.1:8000 inside WSLIf auto-detect fails, specify the Windows IP:
wslink forward 8000 --windows-host 172.20.0.1# Skip auto-detect: target host:port directly
wslink forward 8000 --connect 192.168.1.5:8000
# Expose to LAN (not just localhost)
wslink forward 8000 --listen 0.0.0.0wslink forward <port> [flags]
--connect <host:port> Target directly (skip auto-detect)
--listen <addr> Listen address (default 127.0.0.1)
--wsl-name <distro> WSL distro name (Windows only)
--windows-host <ip> Windows host IP (WSL only)
| Requirement | Details |
|---|---|
| OS | Windows 10/11 with WSL2, or WSL2/Linux |
| Runtime | Static binary, no dependencies |
| Elevation | None (raw TCP, no kernel hooks) |
wslink (Go, statically linked)
|-- Auto-detect target
| Windows -> wsl.exe --list + hostname -I
| WSL -> /etc/resolv.conf nameserver
|-- TCP listener (net.Listen)
|-- Per-connection goroutine
|-- io.Copy bidirectional proxy
One goroutine per connection, two io.Copy goroutines for the bidirectional pipe. Releases are 1-2 MB statically linked binaries - no runtime, no CGO, no libc.