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
- How to download, build and install
- Caveats and recommendations
- Download
- Credits
- Support the developer and the project
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.
┌────────────────┐ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐
| 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!
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 is0.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 inaddress: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 isAUTO
. 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 is0
, (i.e. disabled). Can be0
-65535
or0x0000
-0xFFFF
.-v <level>
or--verbose=<level>
Verbosity level. Optional, default isINFO
. 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 is1024
.-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 is300
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 between0
and1024
. If set to0
, no dummy data will be added. Default is4
. 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.
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.
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:
AllowedIPs = 0.0.0.0/0
i.e., when all traffic is routed through the VPN tunnel. In this case, if the real server IP is not explicitly excluded, WireGuard Obfuscator may try to send its own traffic to the VPN server through the tunnel, leading to a routing loop or connection loss.
WireGuard does not support negation syntax (e.g., !203.0.113.45
). To avoid routing traffic to the server through the tunnel, you can manually split 0.0.0.0/0
into a set of smaller CIDR blocks that exclude the server's IP.
For example, if your server’s public IP is 203.0.113.45
, then instead of:
AllowedIPs = 0.0.0.0/0
You would use:
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, 224.0.0.0/3, 208.0.0.0/4, 192.0.0.0/5,
204.0.0.0/6, 200.0.0.0/7, 202.0.0.0/8, 203.128.0.0/9, 203.64.0.0/10,
203.32.0.0/11, 203.16.0.0/12, 203.8.0.0/13, 203.4.0.0/14, 203.2.0.0/15,
203.1.0.0/16, 203.0.128.0/17, 203.0.0.0/18, 203.0.64.0/19, 203.0.96.0/20,
203.0.120.0/21, 203.0.116.0/22, 203.0.114.0/23, 203.0.112.0/24,
203.0.113.128/25, 203.0.113.64/26, 203.0.113.0/27, 203.0.113.48/28,
203.0.113.32/29, 203.0.113.40/30, 203.0.113.46/31, 203.0.113.44/32
This long list routes all traffic through the tunnel except for the server's IP (203.0.113.45
), which stays outside the tunnel and avoids the loop.
You can use the following script to calculate the subnet list automatically: https://colab.research.google.com/drive/1spIsqkB4YOsctmZV83aG1HKISFFxxMCZ
On Linux, there's a cleaner approach (since version 1.4): use the FwMark
option in the WireGuard config. This is useful only when AllowedIPs = 0.0.0.0/0
, as it allows the system to distinguish between traffic going through the tunnel and traffic required to establish or maintain the tunnel (e.g., handshake packets).
Example WireGuard config:
[Interface]
FwMark = 0xdead
Then, in WireGuard Obfuscator, specify the same mark:
-
In the config file:
fwmark = 0xdead
-
Or via command-line:
--fwmark 0xdead
Note: Using
fwmark
requires root privileges. Make sure to run WireGuard Obfuscator as root when using this option.
As of version 1.4, masking support is available - the ability to disguise traffic as another protocol. This is especially useful when DPI only allows whitelisted protocols. You can set masking mode using the masking
option in the config file or the --masking
parameter on the command line.
At the moment, the only available option is STUN emulation. Since STUN is commonly used for video calls, it is rarely blocked. So, currently supported values are:
NONE
No masking at all. The obfuscator will not mask outgoing traffic and will not recognize or process any incoming masked traffic.AUTO
The obfuscator will not mask outgoing traffic by default. However, if the first packet from the client (on the 'source-lport' side) is masked, the server will autodetect the masking type and switch to it, allowing the client to choose the masking mode independently.STUN
Forces the use of the STUN protocol for outgoing traffic and only accepts incoming traffic that is STUN-masked.
(for advanced users)
In some setups, both WireGuard peers have public IP addresses and can each initiate connections. In this scenario, you need both ends to accept and send connections through the obfuscator. This is where two-way mode comes in.
A static binding tells the obfuscator, right from startup, which peer IPs and ports should be mapped to which local ports. This allows the obfuscator to know exactly how to route packets from the server to the correct local WireGuard instance - even if that peer hasn’t sent any packets yet. Without static bindings, the obfuscator only learns how to forward packets after seeing traffic from a client.
Suppose you have two peers:
- Peer A: Public IP
1.2.3.4
, runs WireGuard locally on port1111
- Peer B: Public IP
5.6.7.8
, runs WireGuard locally on port6666
We can set up the obfuscator on both peers:
- Peer A: Obfuscator listens for local WireGuard traffic on port
2222
and listens for incoming obfuscated handshakes from Peer A on port3333
. - Peer B: Obfuscator listens for incoming obfuscated handshakes from Peer B on port
4444
and listens for local WireGuard traffic on port5555
.
Peer A WireGuard config (1.2.3.4
):
[Interface]
PrivateKey = <A's private key>
ListenPort = 1111
[Peer]
PublicKey = <B's public key>
Endpoint = 127.0.0.1:2222
Peer A Obfuscator config (1.2.3.4
):
source-lport = 2222
target = 5.6.7.8:4444
static-bindings = 127.0.0.1:1111:3333
key = your_secret_key
Peer B Obfuscator config (5.6.7.8
):
source-lport = 4444
target = 127.0.0.1:6666
static-bindings = 1.2.3.4:3333:5555
key = your_secret_key
Peer B WireGuard config (5.6.7.8
):
[Interface]
PrivateKey = <B's private key>
ListenPort = 6666
[Peer]
PublicKey = <A's public key>
Endpoint = 127.0.0.1:5555
In this example the line:
static-bindings = 1.2.3.4:1111:3333
Visually, it looks like this:
┌───────────────────────────┐ ┌───────────────────────────┐
│ Peer A (1.2.3.4) │ │ Peer B (5.6.7.8) │
│ ┌─────────────────┐ | │ ┌─────────────────┐ |
│ │ WireGuard │ | │ │ WireGuard │ |
│ │ ListenPort=1111 | | │ │ ListenPort=6666 | |
│ └─────▲───────────┘ | │ └─────▲───────────┘ |
│ │ │ │ │ │
│ ┌─────▼───────────────┐ │ │ ┌─────▼───────────────┐ │
│ │ source-lport=2222 | │ │ │ local port=5555 │ │
│ │ | │ │ │ │ │
│ │ Obfuscator | │ │ │ Obfuscator | │
│ │ static-bind | │ │ │ static-bind | │
│ │ 127.0.0.1:1111:3333 | │ │ │ 1.2.3.4:3333:5555 | │
│ │ | │ │ │ │ │
│ │ local port=3333 │ | │ │ source-lport=4444 | │
│ └─────▼───────────────┘ │ │ └─────▼───────────────┘ │
│ │ │ │ │ │
└────────┼──────────────────┘ └────────┼──────────────────┘
│ │
│ UDP/obfuscated traffic │
│<--------------------------------------->│
When Peer A initiates a handshake with Peer B:
- WireGuard on Peer A sends a non-obfuscated handshake UDP packet from port
1111
to the local obfuscator on port2222
. - The obfuscator on Peer A obfuscates the packet using the key and sends it to Peer B’s obfuscator on port
4444
, using3333
as the source port.Without static bindings, the obfuscator dynamically selects the source port and creates a mapping in its NAT table.
With the static binding127.0.0.1:1111:3333
, it knows to always use port3333
as the source port for packets from127.0.0.1:1111
. - Peer B’s obfuscator receives the packet, deobfuscates it, and forwards it to Peer B’s local WireGuard instance on port
6666
, using5555
as the source port.Without static bindings, the obfuscator dynamically selects the source port and creates a mapping.
With the static binding1.2.3.4:3333:5555
, it knows to use port5555
as the source port for packets from1.2.3.4:3333
. - Peer B’s WireGuard processes the handshake and sends a response from port
6666
to the obfuscator on port5555
. - Peer B’s obfuscator obfuscates the response and sends it back to Peer A’s obfuscator on port
3333
, using4444
as the source port.With static bindings, the necessary mappings already exist.
- Peer A’s obfuscator deobfuscates the response and forwards it from port
2222
to Peer A’s WireGuard on port1111
.With static bindings, the necessary mappings already exist.
- Peer A’s WireGuard processes the response, completing the handshake.
When Peer B initiates a handshake with Peer A, the process is the same but in reverse:
- WireGuard on Peer B sends a non-obfuscated handshake UDP packet from port
6666
to the local obfuscator on port5555
. - The obfuscator on Peer B obfuscates the packet and sends it to Peer A’s obfuscator on port
3333
, using4444
as the source port.Without static bindings, reverse connections would not work because the obfuscator would not know how to forward packets.
With the static binding1.2.3.4:3333:5555
, the mapping already exists, so it knows to forward packets to1.2.3.4:3333
. - Peer A’s obfuscator receives the packet, deobfuscates it, and forwards it to Peer A’s WireGuard on port
1111
, using2222
as the source port.Without static bindings, reverse connections would not work because the obfuscator would not know how to forward packets.
With the static binding127.0.0.1:1111:3333
, the mapping already exists, so it knows to forward packets to127.0.0.1:1111
. - Peer A’s WireGuard processes the handshake and sends a response from port
1111
to the obfuscator on port2222
. - Peer A’s obfuscator obfuscates the response and sends it to Peer B’s obfuscator on port
4444
, using3333
as the source port. - Peer B’s obfuscator deobfuscates the packet and forwards it to Peer B’s WireGuard on port
6666
, using5555
as the source port. - Peer B’s WireGuard processes the response, completing the handshake.
With static bindings, each obfuscator knows in advance how to forward packets between the server and local WireGuard, regardless of which peer initiates the connection. This enables fully bidirectional, peer-to-peer WireGuard tunnels - even if both sides can initiate connections at any time.
See Download section below for download links.
On Linux, the obfuscator can be installed as a systemd service for automatic startup and management.
To build and install on Linux from the source code, simply run:
make
sudo make install
This will install the obfuscator as a systemd service.
You can start it with:
sudo systemctl start wg-obfuscator
The configuration file is located at:
/etc/wg-obfuscator.conf
ALT Linux
apt-rpm package in Sisyphus
You can download ready-to-run binaries with all required DLL libraries.
If you want to build this tool for Windows from the source code, you need MSYS2 and the following packages:
base-devel
gcc
git
Install the required packages, then run:
make
Note: On Windows, the obfuscator is only available as a command-line application. You need to run it from the terminal and manage startup yourself, so it's required to use some additional tools if you want to install it as a system service.
You can download ready-to-run binaries for both x64 and ARM versions of macOS.
To build Obfuscator from the source code just type:
make
Note: On macOS, the obfuscator is only available as a command-line application. You need to run it from the terminal and manage startup yourself.
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.
WireGuard Obfuscator is available as a multi-architecture Docker image: clustermeerkat/wg-obfuscator on Docker Hub
Supported tags:
latest
- always points to the most recent stable release.nightly
- built automatically from the current main branch; may be unstable. Use only for testing new features.- Version tags (e.g.
1.0
,1.1
) - for specific releases.
Architectures available:
linux/amd64
linux/arm64
linux/arm/v7
linux/arm/v6
linux/arm/v5
linux/386
linux/ppc64le
linux/s390x
Note: Make sure to match the exposed port (
13255
in the example below) with thesource-lport
value in your configuration file.
version: '3.8'
services:
wg-obfuscator:
image: clustermeerkat/wg-obfuscator:latest
volumes:
- ./.wg-obfuscator.conf:/etc/wg-obfuscator/wg-obfuscator.conf
ports:
- "13255:13255/udp"
container_name: wg-obfuscator-container
restart: unless-stopped
image
can be changed to use a specific tag (e.g.,clustermeerkat/wg-obfuscator:1.1
).- Place your config as
.wg-obfuscator.conf
in the same directory asdocker-compose.yml
, or adjust the volume path. - Port mapping (
13255:13255/udp
) must correspond to your obfuscator’s listen port.
You can also run the container directly:
docker run -d \
--name wg-obfuscator \
-v $PWD/.wg-obfuscator.conf:/etc/wg-obfuscator/wg-obfuscator.conf \
-p 13255:13255/udp \
clustermeerkat/wg-obfuscator:latest
WireGuard Obfuscator can run as a container on MikroTik devices with RouterOS 7.4+ (ARM64/x86_64). Update to the latest RouterOS version to ensure you have all the latest container features and fixes.
- Download the latest Extra Packages for your RouterOS version and platform from mikrotik.com/download
- Extract and upload
container-*.npk
to the router - Reboot the router
/system/device-mode/update container=yes
- Confirm when prompted: – For most models, press the physical reset button – On x86, do a full power-off (cold reboot)
/container/config/set registry-url=https://registry-1.docker.io tmpdir=temp
First of all, you need to enable logging for the container subsystem. This is required to see container logs in the RouterOS log using the /log
command.
/system logging add topics=container
/interface/veth/add name=veth-wg-ob address=172.17.13.2/24 gateway=172.17.13.1
Note: in this example, we use IP address
172.17.13.2
for the container and172.17.13.1
for the host. You can choose any other IP addresses as long as they are in the same subnet.
/ip address add address=172.17.13.1/24 interface=veth-wg-ob
Note: This IP address is used by the host to communicate with the container. It must match the gateway set in the veth interface.
In case if your obfuscator is configured to accept incoming connections from a server outside of the NAT, you need to forward the UDP port to the container. For client side obfuscator without two-way mode (static bindings), you can skip this step.
/ip firewall nat add chain=dstnat action=dst-nat protocol=udp dst-port=13255 to-addresses=172.17.13.2 to-ports=13255
Note: This IP address is used by the container, it must match the
address
in the veth interface.
Note: Port number
13255
is just an example. It must port you are using for incoming connections in your obfuscator configuration file (i.e.source-lport
or port from static bindings).
/container/mounts/add dst=/etc/wg-obfuscator name=wg-obfuscator-config src=/wg-obfuscator
Add the container using the container/add
command. This will download the latest image from Docker Hub and create a container with the specified settings.
/container/add \
interface=veth-wg-ob \
logging=yes \
mounts=wg-obfuscator-config \
name=wg-obfuscator \
root-dir=wg-obfuscator-data \
start-on-boot=yes \
remote-image=clustermeerkat/wg-obfuscator:latest
/log print where topics~"container"
You should see import successful
message.
After the container is added, you can start it using the following command:
/container/start [/container/find where name="wg-obfuscator"]
/log print where topics~"container"
You should see logs indicating the container has started successfully.
- After the first launch, a default example config file will appear at
/wg-obfuscator/wg-obfuscator.conf
on your router. - Edit this file to match your actual WireGuard and obfuscator settings.
You can use WinBox, WebFig, or the
/file edit
command in the MikroTik terminal.
/container/stop [/container/find where name="wg-obfuscator"]
/container/start [/container/find where name="wg-obfuscator"]
/log print where topics~"container"
You should see logs indicating the container has started successfully and is ready to process WireGuard traffic.
Notes:
container
package and device-mode are only needed once per router.- No external disk is required; image is small and uses internal storage.
- See MikroTik Containers Docs for advanced usage.
- Don't forget to change WireGuard's
Endpoint
to point to the obfuscator's IP and port. - Don't forget about the Caveats and Recommendations section below, especially regarding endpoint exclusion and routing loops.
- Endpoint Exclusion and Routing Loops:
See the "Avoiding Routing Loops" section above for details on how to prevent routing loops. It's important to ensure that traffic to the VPN server itself is not routed through the VPN tunnel. - PersistentKeepalive:
To maintain a stable connection - especially when clients are behind NAT or firewalls - it is recommended to use WireGuard’sPersistentKeepalive
option. A value of25
seconds is usually sufficient. - Initial Handshake Requirement:
After starting the obfuscator, no traffic will flow between WireGuard peers until a successful handshake has been established. If you restart the obfuscator without restarting WireGuard itself, it may take some time for the peers to re-establish the handshake and resume traffic. You can speed this up by briefly toggling the WireGuard interface. - MTU Settings:
If you experience issues with packet loss (you can seerecv
orrecvfrom
errors in DEBUG level logs), ensure that your WireGuard configuration has appropriate MTU settings. Especially when using masking (it adds extra bytes to each packet), you may need to reduce the MTU. A common setting isMTU = 1420
, but you may need to reduce it based on your network conditions. - IPv6 Support:
The obfuscator does not currently support IPv6. It only works with IPv4 addresses and ports. - Check debug logs:
If you encounter issues, run the obfuscator with--verbose=DEBUG
(DEBUG level) to see detailed logs. This can help diagnose many common problems.
- You can always find the latest release (source code, Docker images and ready-to-use binaries for Linux, Windows, and macOS) at:
https://github.com/ClusterM/wg-obfuscator/releases - Also, you can download automatic CI builds at:
https://clusterm.github.io/wg-obfuscator/
Download it only if you want to test new features or bug fixes that are not yet released. Can be buggy or unstable, use at your own risk! - Android port:
https://github.com/ClusterM/wg-obfuscator-android
- Me: Cluster, email: cluster@cluster.wtf
- WireGuard - the VPN protocol this tool is designed to obfuscate.
- uthash - a great C library for hash tables, used for the NAT table.