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.

Metadata

Release files for wg-bridge 1.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wg-bridge 1.0.3
File Size Uploaded Provenance Actions
wg_bridge-1.0.3.tar.gz 7.5 kB Without provenance Details for wg_bridge-1.0.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for wg-bridge 1.0.3
File Interpreter ABI Platform Actions
wg_bridge-1.0.3-py3-none-any.whl Python 3 none any Details for wg_bridge-1.0.3-py3-none-any.whl

Total release size: 18.0 kB

Release files / wg_bridge-1.0.3.tar.gz

Download URL wg_bridge-1.0.3.tar.gz
Size 7.5 kB
Tags Source
SHA-256 checksum
How to use checksums
375129282e54d3adb79e41b6585d21d459ae7f28c6876041edd50d0155874e99
BLAKE2b-256 checksum
How to use checksums
8589c321a5174d63203b0d9945c7727c82e9a01892ef52dfce6f58511729284f
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / wg_bridge-1.0.3-py3-none-any.whl

Download URL wg_bridge-1.0.3-py3-none-any.whl
Size 10.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
92c1185e5b7ad22d2123902630e16f73db7552833a427369ec2160ebdb8a1f16
BLAKE2b-256 checksum
How to use checksums
3d828c76dd96f9372734e434dd84baeff3e02a2e9526e563d6c9dc55c0f0da85
Upload date
Uploaded using Trusted Publishing?
What is 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}

Security for wg-bridge 1.0.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 release files No provenance

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