Sign inSign up

devontm/wg-userspace

By devontm

Updated 5 months ago

Pure userspace WireGuard server

Image
Networking
0

801

devontm/wg-userspace repository overview

wg-go

Pure userspace WireGuard server skeleton using wireguard-go plus gVisor-backed netstack, designed for container/cloud deployment where host TUN is unavailable.

What This Project Provides

  • Userspace WireGuard device creation with no host TUN management.
  • Standard WireGuard peer config model compatible with official Windows clients.
  • Transparent forwarding for TCP and UDP based on the original destination.
  • ICMP echo handling with PMTU-aware relay and local server-IP replies.
  • Env-driven runtime configuration for docker-compose workflows.

Current Scope

This starter now focuses on a single transparent data path.

TCP and UDP are handled by the gVisor netstack and forwarded upstream through transparent proxy connections based on the original destination address and port.

ICMP is handled separately in the transparent NAT wrapper. Local echo requests to the server IP are answered locally, and remote ICMP echo traffic is relayed with PMTU-aware error handling.

IPv6 is enabled only when WG_IPS contains IPv6 CIDRs. To disable IPv6, remove IPv6 prefixes from WG_IPS.

Project Layout

  • cmd/wguserspace: application entrypoint.
  • internal/config: env parsing and validation.
  • internal/wg: WireGuard userspace device and IPC config generation.
  • internal/forwarder: TCP/UDP transparent forwarding.
  • internal/transparentnat: ICMP relay, local echo handling, and packet rewriting.
  • deployments/docker: Dockerfile and compose setup.

Runtime Variables

  • WG_PRIVATE_KEY: base64 WireGuard private key (required).
  • WG_LISTEN_PORT: UDP listen port (default 51820).
  • WG_MTU: interface MTU (default 1420).
  • WG_IPS: comma-separated CIDRs assigned to server tunnel stack (required).
    • Example dual-stack value: 10.66.0.1/24,fd66::1/64
  • WG_DNS: optional comma-separated DNS IPs for tunnel resolver behavior.
  • WG_DEFAULT_KEEPALIVE_SEC: peer keepalive default (default 25).
  • WG_PEERS_JSON: JSON array of peers:
[
  {
    "public_key": "<client base64 public key>",
    "preshared_key": "<optional base64 psk>",
    "allowed_ips": ["10.66.0.2/32"],
    "persistent_keepalive_sec": 25
  }
]
  • WG_LOG_LEVEL: WireGuard device log level, one of silent, error, or verbose (default silent).
  • OUTBOUND_DIAL_TIMEOUT: upstream dial timeout (default 10s).
  • UDP_SESSION_TIMEOUT: UDP session idle expiration window (default 30s).
  • UDP_IDLE_IO_TIMEOUT: UDP socket read/write deadline while session is active (default 3s).
  • LOG_PACKET_SOURCES: logs observed TCP/UDP/ICMP source addresses at forwarder ingress for troubleshooting (default false).
  • LOG_ICMP_TRACE: enables verbose ICMP relay and PMTU trace logging (default false).

Build

go build ./cmd/wguserspace

Run Locally

export WG_PRIVATE_KEY="..."
export WG_IPS="10.66.0.1/24,fd66::1/64"
export WG_PEERS_JSON='[{"public_key":"...","allowed_ips":["10.66.0.2/32"]}]'
go run ./cmd/wguserspace

The binary automatically loads .env from the current working directory if it exists. This makes sudo ./wguserspace work without manually sourcing environment variables first.

Run With Docker Compose

cp .env.example .env
docker compose -f deployments/docker/compose.yaml up --build

Windows Client Compatibility Notes

Use a normal WireGuard client profile:

  • PublicKey = server public key derived from WG_PRIVATE_KEY.
  • Endpoint = <server-ip>:<WG_LISTEN_PORT>.
  • AllowedIPs = tunnel IP ranges (IPv4 and/or IPv6).
  • PresharedKey optional if configured in server peer JSON.

The handshake and cryptography remain standard WireGuard behavior via wireguard-go.

If you want IPv4-only operation, remove IPv6 CIDRs from WG_IPS. The server will then avoid configuring IPv6 in the netstack and transparent forwarding layers.

Tag summary

Content type

Image

Digest

sha256:1d978df84

Size

2.6 MB

Last updated

5 months ago

docker pull devontm/wg-userspace