Metadata-Version: 2.3
Name: wg-bridge
Version: 1.0.3
Summary: Tunnel WireGuard UDP traffic over a TCP/SSH connection for networks that block UDP
Author: Wei Liu
Author-email: Wei Liu <liuwei_berkeley@berkeley.edu>
Requires-Dist: typer>=0.12.0
Requires-Python: >=3.14
Description-Content-Type: text/markdown

# 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

```bash
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):

```bash
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:

```bash
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](https://github.com/liuweiseu/wg-bridge/releases)), e.g. `git+https://github.com/liuweiseu/wg-bridge.git@v1.0.3`.

### From source

```bash
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:

```bash
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:

```bash
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:

```bash
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:

```bash
wg-bridge --stop
```

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

```bash
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`.
