A lightweight DERP-like UDP relay server designed to connect multiple WireGuard peers across NAT, dynamic IPs, or different IP protocol versions (IPv4/IPv6).
It functions as a stateless middleman, allowing peers to establish a direct-feeling connection without the overhead of tunnel-in-tunnel encapsulation.
- No Tunnel-in-Tunnel Overhead: Packets are forwarded at the UDP layer, maintaining maximum performance.
- End-to-End Encrypted: The bridge only sees encrypted WireGuard packets. It does not possess any private keys.
- NAT & Dynamic IP Friendly: Solves connectivity issues where both peers are behind restrictive NAT or use changing IPs.
- Protocol Agnostic: Seamlessly bridges IPv4 and IPv6 traffic.
- Simple Authorization: Uses WireGuard's
mac1field and public keys for secure peer validation.
Use at your own risk. This implementation is a functional prototype. While the forwarded data remains secure due to WireGuard's design, the bridge itself might be unreliable or exhibit edge-case bugs in high-load scenarios.
The bridge listens on a UDP socket and observes WireGuard handshakes to learn which peer indices belong to which public keys.
- Handshake Observation: When an initiation packet arrives, the bridge verifies the
mac1field against a list of allowed public keys. - Peer Discovery: Since the exact destination might be unknown at the start, the bridge forwards the initiation to all potential peers in the same "key group".
- Session Tracking: Once the handshake response is seen, the bridge maps the session indices and forwards subsequent transport packets directly between the two verified endpoints.
- Python 3.x
- No external libraries required (uses standard library modules like
socket,hashlib, etc.)
Run the script by providing one or more comma-separated lists of public keys that are allowed to communicate with each other.
# Example: Create a group of 3 peers allowed to talk to each other
python3 wg-bridge.py --keys "PubKey1...,PubKey2...,PubKey3..."
# Example: Multiple isolated groups
python3 wg-bridge.py \
--keys "GroupA_Key1...,GroupA_Key2..." \
--keys "GroupB_Key1...,GroupB_Key2..."Parameters:
--port, -p: UDP port to listen on (Default:51820).--keys, -k: Comma-separated list of public keys. Can be used multiple times.
You can use the provided Dockerfile or example.docker-compose.yml.
docker-compose up -d- Copy
wg-bridge.pyto/opt/wg-bridge/. - Edit
example.wg-bridge.servicewith your actual keys and path. - Install the service:
cp example.wg-bridge.service /etc/systemd/system/wg-bridge.service
systemctl daemon-reload
systemctl enable --now wg-bridgeTo use the bridge, adjust your local WireGuard configuration (/etc/wireguard/wg0.conf or mobile app):
- Endpoint: Set the
Endpointof all relevant peers to the IP/Domain and Port of your Bridge server.- Note: WireGuard allows using the same Endpoint for multiple peers.
- Persistent Keepalive: Highly recommended to keep NAT mappings alive.
[Peer] PublicKey = <Remote_Peer_Public_Key> Endpoint = bridge.yourserver.com:51820 PersistentKeepalive = 25 AllowedIPs = 10.0.0.x/32
This project is provided "as-is". Check the source code for details.