Skip to main content

wg-bridge

Tunnel WireGuard's UDP traffic over a TCP connection (an SSH tunnel), for networks that block or throttle UDP but allow TCP/SSH.

How it works

WireGuard client -> UDP -> wg-bridge --client -> TCP -> SSH tunnel -> TCP -> wg-bridge --server -> UDP -> WireGuard server
  • Client side runs next to your local WireGuard client. It binds the UDP port your WireGuard client talks to, and forwards everything over a TCP connection into an SSH tunnel.
  • Server side runs near the actual WireGuard server. It listens for the TCP connection coming out of the SSH tunnel and forwards packets to the real WireGuard UDP endpoint.

You are responsible for setting up the SSH tunnel itself (e.g. ssh -L <tcp-port>:localhost:<tcp-port> user@server or a remote forward, depending on your topology) — wg-bridge only handles the UDP↔TCP relay on each end.

Each UDP datagram is sent over the TCP stream with a 2-byte length prefix, so datagram boundaries survive the byte-stream relay even when several packets arrive back-to-back (bursty traffic like a VNC/RDP session, not just isolated pings). This is a wire-format change — the client and server sides must run the same wg-bridge version; an old client cannot talk to a new server or vice versa.

Install

From PyPI

pip install wg-bridge

Or, to install it as an isolated global command-line tool rather than into a project environment (recommended for a CLI-only package like this):

pipx install wg-bridge
# or, using uv:
uv tool install wg-bridge

From GitHub (without cloning)

Installs the latest code on the default branch directly from the repository:

pip install git+https://github.com/liuweiseu/wg-bridge.git
# or:
pipx install git+https://github.com/liuweiseu/wg-bridge.git
# or:
uv tool install git+https://github.com/liuweiseu/wg-bridge.git

Pin a specific released version by appending @vX.Y.Z (see the releases page), e.g. git+https://github.com/liuweiseu/wg-bridge.git@v1.0.3.

From source

git clone https://github.com/liuweiseu/wg-bridge.git
cd wg-bridge
uv sync

Every wg-bridge ... command shown below becomes uv run wg-bridge ... when run this way (unless you've activated the project's .venv yourself).

Shell tab-completion

Once installed by any of the methods above, enable shell tab-completion (bash/zsh/fish/PowerShell) by running once from an interactive shell and restarting your terminal:

wg-bridge --install-completion

Usage

By default --server and --client detach into the background and hand control of the terminal straight back to you — no & or nohup needed. Output goes through Python's logging module to a wg-bridge.log file (the first line logged is always the working mode); use --status to check on it and --stop to stop it.

On the machine near the WireGuard server:

wg-bridge --server --wg-host <wireguard-server-ip> --tcp-port <port> [--wg-port 51820] [--log-file <path>]
$ wg-bridge --server --wg-host 192.168.88.199 --tcp-port 5980
[INFO] wg-bridge server started in background (PID 39195).
[INFO] listening on TCP 0.0.0.0:5980 -> forwarding to UDP 192.168.88.199:51820
[INFO] logs: /path/to/cwd/wg-bridge.log
$ cat wg-bridge.log
2026-09-09 23:18:47 [INFO] Working mode: server
2026-09-09 23:18:47 [INFO] Server bridge started: TCP:5980 -> UDP 192.168.88.199:51820

--log-file sets the path (directory + filename) of the log file; it defaults to ./wg-bridge.log in the current directory (its parent directory is created if it doesn't exist yet).

On the machine running the local WireGuard client:

wg-bridge --client --tcp-port <port> [--wg-port 51820] [--log-file <path>]

Add --foreground to either command to run it attached to the terminal instead (useful for debugging) — Ctrl-C stops it. In foreground mode, log lines are also echoed to the console in addition to the log file.

To stop whichever bridge process is currently running on that machine:

wg-bridge --stop

To check whether a bridge process is currently running on that machine:

wg-bridge --status
$ wg-bridge --status
[INFO] wg-bridge is running (PID 39195, mode=server)
[INFO] listening on TCP 0.0.0.0:5980 -> forwarding to UDP 192.168.88.199:51820
[INFO] logs: /path/to/cwd/wg-bridge.log
Flag Mode Default Description
--server Run in server mode (near the WireGuard server).
--client Run in client mode (next to the local WireGuard client).
--stop Stop the wg-bridge process currently running on this machine.
--status Show whether wg-bridge is running on this machine, and its bound host/port info if so.
--foreground server/client only Run attached to the terminal instead of detaching into the background.
--log-file server/client only ./wg-bridge.log Path (directory + filename) of the log file.
--version Print the wg-bridge version and exit.
--help / -h Show this help and exit.
--install-completion Install shell tab-completion for the detected shell.
--show-completion Print the completion script for the detected shell, without installing it.
--wg-host server only localhost WireGuard server address.
--wg-port both 51820 WireGuard UDP port.
--tcp-port server/client only (required) TCP tunnel port; must match the SSH tunnel endpoint and be the same value on both sides.

Exactly one of --server, --client, --stop, or --status is required.

Notes

  • Each side assumes a single active WireGuard peer/session at a time; it does not multiplex multiple peers through one bridge process.
  • Both sides retry automatically if the TCP connection drops.
  • Starting --server or --client records the running process's PID, its host/port settings, and its log file path in a state file under the system temp directory; starting a second instance while one is already tracked as running is refused until you --stop it. --stop sends the tracked process a termination signal and clears the state file; --status reports it (or reports not running, cleaning up the state file first if it points at a process that's already gone — e.g. after a crash).
  • In the default background mode, if the process fails immediately (e.g. the TCP port is already in use), the command reports the failure and prints the last lines of wg-bridge.log instead of claiming success.
  • wg-bridge.log is appended to, not truncated, across restarts — each run's own first line is always Working mode: server/Working mode: client.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wg_bridge-1.0.3.tar.gz (7.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wg_bridge-1.0.3-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file wg_bridge-1.0.3.tar.gz.

File metadata

  • Download URL: wg_bridge-1.0.3.tar.gz
  • Upload date:
  • Size: 7.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wg_bridge-1.0.3.tar.gz
Algorithm Hash digest
SHA256 375129282e54d3adb79e41b6585d21d459ae7f28c6876041edd50d0155874e99
MD5 9780b794286e9d7270ea4cce95db8984
BLAKE2b-256 8589c321a5174d63203b0d9945c7727c82e9a01892ef52dfce6f58511729284f

See more details on using hashes here.

File details

Details for the file wg_bridge-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: wg_bridge-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wg_bridge-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 92c1185e5b7ad22d2123902630e16f73db7552833a427369ec2160ebdb8a1f16
MD5 75fc9bd4fcd8b8ba48a9ea31368dfd77
BLAKE2b-256 3d828c76dd96f9372734e434dd84baeff3e02a2e9526e563d6c9dc55c0f0da85

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page