MCPcopy Index your code
hub / github.com/ClusterM/wg-obfuscator

github.com/ClusterM/wg-obfuscator @v1.5

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.5 ↗ · + Follow
63 symbols 127 edges 12 files 14 documented · 22% updated 3mo agov1.5 · 2025-09-21★ 74318 open issues

Browse by type

Functions 43 Types & classes 20
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

WireGuard Obfuscator

WireGuard Obfuscator is a tool designed to disguise WireGuard traffic as random data or a different protocol, making it much harder for DPI (Deep Packet Inspection) systems to detect and block. This can be extremely useful if your ISP or government attempts to block or throttle WireGuard traffic.

Project Goals: * Compact and dependency-free: The application is designed to be as lightweight as possible, with no external dependencies at all. This makes it suitable even for installation on minimal hardware such as basic home routers. * Independent obfuscator: Instead of maintaining a separate fork of WireGuard, the obfuscator is built to be fully independent of the VPN client/server. This allows seamless integration into an existing network architecture or even running the obfuscator on a separate device if the device running WireGuard is unable to support additional applications. * Preserve bandwidth efficiency: The obfuscator continues to use only UDP and introduces minimal overhead to the size of original packets to ensure maximum throughput.

What it's NOT: * Not a standalone solution: You need to run this tool on both ends of the WireGuard connection. You must deploy the obfuscator on both sides to ensure proper obfuscation and deobfuscation of traffic. Therefore, you cannot use it with third-party VPN servers. If you want to bypass your ISP's restrictions or censorship, you need to run your own VPN server (e.g., hosted on a VPS) and connect to it using WireGuard. * Not a VPN: This is not a VPN service or a WireGuard client/server. It only obfuscates WireGuard traffic.

Table of Contents: - Feature overview - Basic concept - Configuration - Avoiding Routing Loops - Masking - Two-way Mode - How to download, build and install - Linux - Windows - macOS - Android - Running Docker container on Linux - Running Docker container on MikroTik Routers - Caveats and recommendations - Download - Credits - Support the developer and the project

Feature overview

Originally built as a quick personal solution, this project has grown into a fully-featured tool with the following capabilities: * WireGuard-specific design
This obfuscator is purpose-built for the WireGuard protocol: it recognizes WireGuard packet types and actively monitors handshake success to ensure reliable operation. * Key-based obfuscation
Obfuscation is performed using a user-specified key. While this arguably makes it more like encryption, note that providing strong cryptographic guarantees is not the goal here - WireGuard itself already handles secure encryption. The key’s purpose is to make your traffic look unrecognizable, not unbreakable. * Symmetric operation
The tool automatically detects whether packets are obfuscated and processes them accordingly. * Handshake randomization
WireGuard handshake packets are padded with random dummy data, so their obfuscated sizes vary significantly. This makes it difficult for anyone monitoring traffic to spot patterns or reliably fingerprint handshakes. Even data packets can have their size increased by a few random bytes too. * Masking
Starting from version 1.4, the project introduces masking support: the ability to disguise traffic as another protocol. This is especially useful when DPI only allows whitelisted protocols. At the moment, the only available option is STUN emulation. Since STUN is commonly used for video calls, it is rarely blocked. * Very fast and efficient
The obfuscator is designed to be extremely fast, with minimal CPU and memory overhead. It can handle high traffic loads without noticeable performance degradation. * Built-in NAT table
The application features a high-performance, built-in NAT table. This allows hundreds of clients to connect to a single server port while preserving fast, efficient forwarding. Each client’s address and port are mapped to a unique server-side port. * Static (manual) bindings / two-way mode
You can manually define static NAT table entries, which enables "two-way" mode - allowing both WireGuard peers to initiate connections toward each other through the obfuscator. * Multi-section configuration files
Supports both simple configuration files and command-line arguments for quick one-off runs or advanced automation. You can define multiple obfuscator instances within a single configuration file. * Detailed and customizable logging
Verbosity levels range from error-only output to full packet-level traces for advanced troubleshooting and analytics. * Cross-platform and lightweight
Available as binaries for Linux, Windows, and Mac, as well as tiny multi-arch Docker images (amd64, arm64, arm/v7, arm/v6, 386, ppc64le, s390x). The images are extremely small and suitable even for embedded routers like MikroTik. * Very low dependency footprint
No large external libraries or frameworks are required. * Android client
A very simple Android port of the obfuscator is available: https://github.com/ClusterM/wg-obfuscator-android/ - it allows you to obfuscate WireGuard traffic on Android devices, including phones, tablets, and Android TVs.

Basic Concept

┌────────────────┐ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐
| WireGuard peer | | WireGuard peer | | WireGuard peer | | WireGuard peer |
└───────▲────────┘ └───────▲────────┘ └────────▲───────┘ └───────▲────────┘
        |                  |                   └──────┐    ┌─────┘
┌───────▼────────┐ ┌───────▼────────┐           ┌─────▼────▼─────┐
|   Obfuscator   | |   Obfuscator   |           |   Obfuscator   |
└───────▲────────┘ └───────▲────────┘           └────────▲───────┘
        |                  |                             |
┌───────▼──────────────────▼─────────────────────────────▼────────────────┐
|       |                  |     Internet                |                |
└───────▲──────────────────▲─────────────────────────────▲────────────────┘
        |                  |                             |
        |          ┌───────▼────────┐                    |
        └─────────>|   Obfuscator   |<───────────────────┘
                   └───────▲────────┘
                           |
               ┌───────────▼────────────┐
               | WireGuard  server peer |
               └────────────────────────┘

In most cases, the obfuscator is used in a scenario where there is a clear separation between a server (with a static or public IP address) and clients (which may be behind NAT). We’ll focus on this setup here. If both ends have public IPs and can initiate connections to each other, refer to the "Two-way mode" section below.

Usually, the obfuscator is installed on the same device as your WireGuard client or server. In this setup, you configure WireGuard to connect to the obfuscator’s address and port (typically 127.0.0.1 and a custom port), while the real remote address and port are specified in the obfuscator’s configuration.

For example, a standard WireGuard client configuration:

[Peer]
Endpoint = example.com:19999

would become:

[Peer]
Endpoint = 127.0.0.1:3333

And the obfuscator would be launched/configured like this:

source-lport = 3333
target = example.com:19999

On the server side, the WireGuard config:

[Interface]
ListenPort = 19999

would be changed to:

[Interface]
ListenPort = 5555

With the obfuscator running with this config:

source-lport = 19999
target = 127.0.0.1:5555

The application maintains its own internal address mapping table, so a single server-side obfuscator can handle connections from multiple clients - each with their own obfuscator instance - using just one server port. Likewise, on the client side, a single obfuscator can support connections to multiple peers (though this is rarely needed in typical use).

The obfuscator automatically determines the direction (obfuscation or deobfuscation) for each packet, so the configuration files on both the client and server sides look nearly identical. The only thing that matters is that both sides use the same key.

The key is simply a plain text string. Cryptographic strength is not required here: feel free to use any common word or phrase (longer is better, but even four or five characters is usually enough in practice). The main thing is that your key is not the same as everyone else’s!

Configuration

Command line parameters and configuration file

The obfuscator can be run with a command line configuration or using a configuration file. Available command line arguments are: * -? or --help
Show a help message describing all command-line arguments and exit. * -V or --version
Print version information and exit. * -c <filename> or --config=<filename>
Path to the configuration file, can be used instead of the rest arguments. * -i <interface> or --source-if=<interface>
Source interface to listen on. Optional, default is 0.0.0.0, e.g. all interfaces. Can be used to listen only on a specific interface. * -p <port> or --source-lport=<port>
Source port to listen. The source client should connect to this port. Required. * -t <address:port> or --target=<address:port>
Target address and port in address:port format. All obfuscated/deobfuscated data will be forwarded to this address. Required. * -k <key> or --key=<key>
Obfuscation key. Just a string. The longer, the better. Required, must be 1-255 characters long. * -a <type> or --masking=<type>
Protocol masking type to disguise traffic. Optional, default is AUTO. Supported values: STUN, AUTO, NONE. See "Masking" for details. * -b <bindings> or --static-bindings=<bindings>
Comma-separated static bindings for two-way mode, in the format <client_ip>:<client_port>:<forward_port>. See "Two-way mode" for details. * -f <mark> or --fwmark=<mark>
Firewall mark to set on all packets. Can be used to prevent routing loops. Optional, default is 0, (i.e. disabled). Can be 0-65535 or 0x0000-0xFFFF. * -v <level> or --verbose=<level>
Verbosity level. Optional, default is INFO. Accepted values are:
ERRORS (critical errors only)
WARNINGS (important messages)
INFO (informational messages: status messages, connection established, etc.)
DEBUG (detailed debug messages)
TRACE (very detailed debug messages, including packet dumps)

Additional arguments for advanced users: * -m <max_clients> or --max-clients=<max_clients>
Maximum number of clients. This is the maximum number of clients that can be connected to the obfuscator at the same time. If the limit is reached, new clients will be rejected. Optional, default is 1024. * -l <timeout> or --idle-timeout=<timeout>
Maximum idle timeout in seconds. This is the maximum time in seconds that a client can be idle before it is disconnected. If the client does not send any packets for this time, it will be disconnected. Optional, default is 300 seconds (5 minutes). * -d <length> or --max-dummy-length-data=<length>
Maximum dummy length for data packets. This is the maximum length of dummy data in bytes that can be added to data packets. Used to obfuscate traffic and make it harder to detect. The value must be between 0 and 1024. If set to 0, no dummy data will be added. Default is 4. Note: total packet size with dummy bytes will be limited to 1024 bytes.

You can use the --config argument to specify a configuration file, which allows you to set all these parameters in the key=value format. For example:

# Instance name
[main]

source-lport = 13255
target = 10.13.1.100:13255
key = love
static-bindings = 1.2.3.4:12883:6670, 5.6.7.8:12083:6679
verbose = 2

# You can specify multiple instances
[second_server]
source-if = 0.0.0.0
source-lport = 13255
target = 10.13.1.100:13255
key = hate
verbose = 4

As you can see, the configuration file allows you to define settings for multiple obfuscator instances. This makes it easy to run several instances of the obfuscator with different settings, all from a single configuration file.

Be sure to check the Caveats and Recommendations section below for important notes on configuration and usage.

Avoiding Routing Loops

When using WireGuard, especially in combination with tools like WireGuard Obfuscator, it's important to ensure that traffic to the VPN server itself is not accidentally routed through the VPN tunnel. Otherwise, you may encounter a routing loop or complete loss of connection right after the handshake.

Why and When This Happens

WireGuard routes packets based on the AllowedIPs list. Normally, it automatically excludes the server’s IP address (as specified in the Endpoint field) to avoid routing handshake and keepalive packets through the tunnel itself.

However, when you use WireGuard Obfuscator running locally (e.g., on 127.0.0.1), WireGuard only sees the obfuscator's local address, not the actual public IP of the VPN server. It has no awareness of the real server endpoint, which is hidden inside the obfuscator's config.

This becomes a problem especially when the peer is configured with

Core symbols most depended-on inside this repo

Shape

Function 43
Class 20

Languages

C73%
C++27%

Modules by API surface

masking_stun.c16 symbols
masking.c12 symbols
wg-obfuscator.c11 symbols
uthash.h7 symbols
config.c7 symbols
obfuscation.h4 symbols
wg-obfuscator.h2 symbols
mini_argp.h2 symbols
masking.h2 symbols

For agents

$ claude mcp add wg-obfuscator \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page