Home

Awesome

docker-swgp-go

A set of Docker images of Simple WireGuard Proxy for various platforms:

Description

Simple WireGuard Proxy (SWGP) is a universal and effective solution for WireGuard (WG) traffic obfuscation. The original implementation is written in Go by @database64128 and published as swgp-go.

Purpose

It is a known limitation that WG implements no obfuscation. The WG protocol uses UDP transport with the first 4 bytes representing a message type (unsigned 32-bit integer, little endian) and predefined handshake packet lengths (refer to the technical whitepaper for details). As a result, pure WG traffic could easily be filtered based on some simple rules (e.g. nDPI). According to public reports, some countries like China, Egypt, Iran and Russia imposed a full ban on WG protocol, at least for the packets crossing the digital borders of these countries.

SWGP modifies WG packets in a way that they look like an unknown UDP traffic to DPI software, and the firewalls successfully pass them through. While there might still be a possibility to identify WG flows obfuscated with SWGP based on statistical analysis or other factors, no reports have been published about it yet.

Further discussions on WG censorship circumvention:

Terminology

Unlike WG that uses the concept of peers, SWGP is a typical client-server application. For the purposes of SVGP:

As such, a SWGP server cannot initiate connections to SWGP clients, and a SWGP client cannot initiate connections to WG peers. For a peer-to-peer setup with two equal WG peers each having a fixed IP address, it woudn't really matter where to deploy a SWGP server. Otherwise, for a peer-to-multiple-peers setup with one static WG peer and one or more dynamic WG peers, it would be desirable to deploy a SWGP server on (in front of) the static peer. Do not try to run two SWGP servers or two SWGP clients pointing to each other, it wouldn't work (at least, it is not implemented now).

Each SWGP instance (container, if you use Docker deployment, or process, if you install it directly on your machine) can handle multiple servers and clients at once. Be careful with proxyListen and wgListen fields, as no overlapping address-port combinations are allowed within one instance.

Configuration

Below is diagram illustrating three most common configuration scenarios. Case 0 is more or less what most WG users have: pure WG traffic between static and dynamic WG peers. Cases 1 and 2 provide for SWGP usage. The difference is whether SWGP server and client are deployed externally (dedicated hardware, virtual machines or bridged Docker containers, i.e. different IP addresses) or internally (same hardware, same machines or hosted Docker containers, i.e. identical IP addresses). The sample configurations below correspond to case 1.

SWGP Configuration Diagram

<details> <summary>WG. Static peer instance settings before/after SWGP deployment (server.conf)</summary>

Critical fields for a static peer (e.g. reachable at 2001:db8::1):

[Interface]
Address = 192.0.2.1/24
ListenPort = 20221
PrivateKey = 2O0/Uc8q2MrcBMUbYClu3MkgZOCqqeBffJwj17dzvU4=

[Peer]
PublicKey = UcT0x33H7aTXKMtZLi+S5LDgDio0jQTeTCbpIlf2ACI=
PresharedKey = OnWohs7BrG+1Os1zBRvJXZC9aU76JDTS5Wzpkcfhn1o=
AllowedIPs = 192.0.2.2/32
</details> <details> <summary>WG. Dynamic peer instance settings before SWGP deployment (client.pure.conf)</summary>

Critical fields for a dynamic peer (e.g. reachable at 2001:db8::4):

[Interface]
Address = 192.0.2.2/24
PrivateKey = EMzBeCTUpM2EwFz19ArhiXYf1vjS1T/e5f9LF5LFRGY=

[Peer]
PublicKey = Bj+VYMZ3Xt1ROgDuJ9fOm88Iw6s23hq+tyrsLrEOmGA=
PresharedKey = OnWohs7BrG+1Os1zBRvJXZC9aU76JDTS5Wzpkcfhn1o=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = [2001:db8::1]:20221
</details> <details> <summary>SWGP. Server instance config.json (server.json)</summary>

Critical fields for a server (e.g. reachable at 2001:db8::2):

{
  "servers": [
      {
          "proxyListen": ":20220",
          "proxyMode": "zero-overhead",
          "proxyPSK": "sAe5RvzLJ3Q0Ll88QRM1N01dYk83Q4y0rXMP1i4rDmI=",
          "wgEndpoint": "[2001:db8::1]:20221"
      }
  ]
}
</details> <details> <summary>SWGP. Client instance config.json (client.json)</summary>

Critical fields for a client (e.g. reachable at 2001:db8::3):

{
  "clients": [
      {
          "wgListen": ":20222",
          "proxyEndpoint": "[2001:db8::2]:20220",
          "proxyMode": "zero-overhead",
          "proxyPSK": "sAe5RvzLJ3Q0Ll88QRM1N01dYk83Q4y0rXMP1i4rDmI="
      }
  ]
}
</details> <details> <summary>WG. Dynamic peer instance settings after SWGP deployment (client.obfs.conf)</summary>

Modifications required for a dynamic peer (e.g. reachable at 2001:db8::4):

...
Endpoint = [2001:db8::3]:20222
</details>

Deployment

There are 3 approaches to SWGP deployment if you don't use Docker:

  1. Download prebuilt binaries available for linux/amd64, linux/arm64 and windows/amd64 platforms
  2. Compile a binary from source code for any compatible platform (there might be some platforms where golang and/or other dependencies are unavailable)
  3. Use SWGP code written in Go in your own project (for developers)

Alternatively, Docker images may be used, which is often a more convenient way for most users. The following samples provide for a hosted deployment. For a bridged option adjust the network argument. Remember you will need server.json and client.json files so as to be mounted in containers.

docker run --name swgp-server -d --network host --restart unless-stopped \
  -v ./server.json:/etc/swgp-go/config.json:ro vnxme/swgp-go:latest
docker run --name swgp-client -d --network host --restart unless-stopped \
  -v ./client.json:/etc/swgp-go/config.json:ro vnxme/swgp-go:latest
version: "3.8"
services:
  swgp-server:
    container_name: swgp-server
    image: vnxme/swgp-go:latest
    network: host
    restart: unless-stopped
    volumes:
      - ./server.json:/etc/swgp-go/config.json:ro
  swgp-client:
    container_name: swgp-client
    image: vnxme/swgp-go:latest
    network: host
    restart: unless-stopped
    volumes:
      - ./client.json:/etc/swgp-go/config.json:ro