Proxy WireGuard UDP connections over HTTP(S)
  • Go 81.2%
  • Shell 15.8%
  • Makefile 3%
Find a file
Jeroen Wijenbergh 4c455b7d31
All checks were successful
/ tests (push) Successful in 47s
CI: Use Codeberg runner
2025-10-29 09:04:21 +01:00
.forgejo/workflows CI: Use Codeberg runner 2025-10-29 09:04:21 +01:00
cmd CMD: Fix revive linter errors 2025-08-14 11:23:43 +02:00
contrib fix vpn_setup.sh script with new proxyguard-client 2025-02-13 10:30:30 +01:00
systemd Client: Cleanup options to be consistent and the minimal necessary 2024-10-28 15:55:05 +00:00
.gitignore .gitignore: update 2024-01-29 16:31:41 +01:00
CHANGES.md Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
client.go Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
deploy.md Deploy doc: proxy_http is enabled on Fedora 2024-04-29 10:28:20 +02:00
go.mod go.mod: Require go 1.24 2025-10-10 13:30:29 +02:00
go.sum Proxy over HTTP (#17) 2024-02-12 13:25:03 +00:00
LICENSE Initial commit 2023-07-05 17:53:33 +02:00
log.go Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
Makefile Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
mark_default.go Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
mark_linux.go Client: Re-use source port if it is set and only Linux 2024-03-07 12:14:28 +01:00
prepare_release.sh Prepare release: Fix unstaged changes check 2024-02-13 16:02:39 +01:00
reader.go Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
README.md Client: Cleanup options to be consistent and the minimal necessary 2024-10-28 15:55:05 +00:00
restart.go Client: Refactor to wait for traffic to handshake 2024-10-28 15:55:05 +00:00
restart_test.go Client: Refactor to wait for traffic to handshake 2024-10-28 15:55:05 +00:00
server.go Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
technical.md Initial technical and deploy docs 2024-04-25 16:58:29 +02:00
tunnel.go Lint: use staticcheck instead of stylecheck 2025-08-14 11:01:49 +02:00
upgrade.go Upgrade: Set UpgradeProto to UoTLV/1 2024-04-04 17:58:29 +02:00
upload_release.sh Upload Release: use v{VERSION} tags 2025-08-14 12:06:01 +02:00
version.go Version: Post-release version bump 2025-08-14 12:05:57 +02:00

ProxyGuard

Proxy UDP connections over HTTP(s). The main use case is to proxy WireGuard packets.

Goal

The goal of this project is NOT to work around intentional state/organizational network blocks/censorship. We developed ProxyGuard to work on networks that are misconfigured. For example on networks where UDP is blocked, or there is an issue with the MTU. Therefore, ProxyGuard currently does not do any advanced anti-censorship tricks, it is merely a proxy for UDP traffic. This keeps the codebase simple.

Dependencies

  • Go (target: >= 1.19)

Building

Run: make

NOTE: You can build static binaries with CGO_ENABLED=0 make

Installing

Run:

$ sudo make install

This will install the daemons under /usr/local and add the systemd service files. Do not forget to run systemctl daemon-reload. After that you can start the proxyguard-server and proxyguard-client services.

To configure them, use e.g. systemctl edit proxyguard-server and override the variables you see there with your own values as needed, for example if WireGuard is listening on port 443, you can add the following:

[Service]
Environment=TO=127.0.0.1:443

DEB/RPM packages

Currently there are DEB/RPM packages available in eduVPN's server repository, follow the eduVPN docs to add the repo.

And then install ProxyGuard using: sudo apt -y install proxyguard-client or sudo dnf -y install proxyguard-client

Running

This tool is focused on a client-server model. This proxy thus needs to run for every client and for a server. The server mode accepts multiple clients.

Client example

This example listens on local UDP port 51821, expects packets from UDP port 51820 (WireGuard listen port) and forwards TCP packets (with a HTTP Upgrade handshake) to vpn.example.com

proxyguard-client --to http://vpn.example.com

NOTE: If you test the client on Linux, you might also need to add --fwmark 51820 (or some other number that the WG connection configures) to mark that the packets going out of this proxy are encrypted, preventing a routing loop. 51820 is the default for WireGuard. Note that this needs root or the binary needs CAP_NET_ADMIN.

NOTE: In case HTTPS is used, the client only allows servers with TLS >= 1.3

To then use this with WireGuard, you need to change the endpoint in the WireGuard config and make sure the listen port is set

[Interface]
PrivateKey = ...
Address = ...
DNS = ...
ListenPort = 51820

[Peer]
PublicKey = ...
AllowedIPs = ...
Endpoint = 127.0.0.1:51821

Server example

This example starts a HTTP server on TCP port 51821 and forwards UDP packets to localhost 51820, the WireGuard port.

proxyguard-server --listen 0.0.0.0:51821 --to 127.0.0.1:51820

Deployment

For details on deployment, see here.

Technical docs

For technical docs, see here.

Acknowledgements & Thanks

The following projects gave me an idea how I could implement this best, most notably how to do the UDP <-> TCP conversion with a custom header. This project started with a UDP to TCP approach, but later moved to HTTP for use behind a reverse proxy and improved obfuscation.

License

MIT