Skip to content

Repository files navigation

stunmesh-go

STUNMESH is a WireGuard helper tool that establishes peer-to-peer connections through NAT — without any self-hosted coordination infrastructure.

It discovers each node's public IP and port via STUN, encrypts the endpoint with a Curve25519 sealed box, and shares it through a pluggable storage backend (Cloudflare DNS, OpenDHT, or your own script). Every node reads its peers' endpoints from the same storage and configures WireGuard accordingly. No rendezvous server, no relay, no VPS in the middle.

Inspired by manuels' wireguard-p2p project.

📖 Full documentation: docs.stunmesh.dev

Talks & Presentations

NAT Type Support

  • Full Cone NAT, Restricted Cone NAT, Port Restricted Cone NAT: fully supported
  • ⚠️ Symmetric NAT: may be difficult to support due to unpredictable port mapping

For best results, ensure at least one peer is behind a cone NAT type.

Supported Platforms

  • Linux (amd64, arm, arm64, mipsle)
  • macOS (amd64, arm64)
  • FreeBSD (amd64, arm64) - requires wireguard-tools
  • Windows (amd64, arm64) - shipped as stunmesh-windows-<arch>-<tag>.zip, requires the official WireGuard for Windows client
  • Android - separate app, see stunmesh-android

Important

FreeBSD binaries use the wgcli backend, which invokes wg(8). The base system ships the if_wg kernel module but not that tool, so pkg install wireguard-tools is required. See Backend Selection.

Note

We only support wireguard-go in MacOS, Wireguard App store version is not supported because of sandbox currently.

Quick Start

Download a binary from the releases page, or use the container image:

docker pull ghcr.io/tjjh89017/stunmesh

Warning

The Docker Hub image (tjjh89017/stunmesh) is deprecated and will stop receiving updates in a future release. Pull from ghcr.io instead.

On Linux, macOS, and FreeBSD, stunmesh-go needs raw socket access, so run it as root next to an already-configured WireGuard interface (Windows differs — see Windows below):

sudo ./stunmesh-go

On Linux, instead of running as root you can grant just the two capabilities it needs:

setcap cap_net_admin,cap_net_raw+ep ./stunmesh-go

It runs as a daemon by default; pass -oneshot to publish and establish 3 times and then exit.

Configuration is read from /etc/stunmesh/config.yaml, ~/.stunmesh/config.yaml, or ./config.yaml (.yml also works), or pass a file directly with -c <file>. A minimal two-node setup with the built-in Cloudflare plugin:

---
refresh_interval: "1m"
log:
  level: "info"
interfaces:
  wg0:
    peers:
      "PEER_B":
        public_key: "<PEER_B_PUBLIC_KEY_BASE64>"
        plugin: cf
stun:
  addresses: ["stun.l.google.com:19302"]
plugins:
  cf:
    type: builtin
    name: cloudflare
    zone: example.com
    token: "<CLOUDFLARE_API_TOKEN>"
    subdomain: wg

Run the same setup on the other node (with this node's public key), wait roughly two refresh intervals, and the tunnel comes up. Verify with wg show or by pinging the peer's tunnel address.

Important

stunmesh-go reads the WireGuard device's state once at startup — restart it after the interface is recreated, the listen port or fwmark changes, or config.yaml is edited. Under systemd, bind it to the WireGuard unit (After= + BindsTo=) so this is enforced automatically. See when stunmesh-go must be restarted.

Windows

Windows has no equivalent of the raw sockets (Linux) or pcap (macOS/BSD) stunmesh-go uses to share WireGuard's UDP port, so it instead runs a local UDP proxy that owns the public-facing socket, performs STUN on it, and relays WireGuard packets to per-peer loopback listeners. The official WireGuard for Windows client stays the data plane, and stunmesh-go rewrites each peer's endpoint to its loopback listener itself — there is nothing to change by hand in the tunnel.

  1. Install the official WireGuard for Windows client and create the tunnel.
  2. Activate the tunnel before starting stunmesh-go.
  3. Run stunmesh-go from an Administrator console. The WireGuard service requires the same privilege; without it stunmesh-go fails at the first device access with a "run stunmesh as Administrator" error.

The configuration file is unchanged from the other platforms and the proxy needs no configuration of its own; set interfaces.<name>.proxy.listen only if you need a fixed outer port for port forwarding or a port-based firewall.

Important

Deactivating and reactivating a tunnel in the WireGuard UI wipes the endpoints stunmesh-go set, because the service re-applies the .conf file. Restart stunmesh-go after any tunnel toggle or restart.

Note

ICMP ping monitoring is not implemented on Windows yet; stunmesh-go logs this and continues without it.

Full tunnel / restricted environments

Linux, macOS, and FreeBSD can opt into the same UDP proxy Windows always uses by setting interfaces.<name>.proxy.enabled: true (default false on these platforms). This is required for full-tunnel setups on macOS and FreeBSD, and optional on Linux for restricted environments that lack CAP_NET_RAW. See docs.stunmesh.dev for the full-tunnel guide per platform.

Android

Android is covered by a separate app, stunmesh-android, which embeds this project's STUN core alongside a userspace WireGuard implementation and runs as a VPN service — no root required. It is in early development: install by sideloading the universal APK from its releases page. Only the built-in storage plugins are available there, and exempting the app from battery optimization is recommended for long-lived tunnels.

Documentation

Topic Link
Getting started docs.stunmesh.dev/getting-started
Configuration reference (protocols, STUN servers, ping monitoring) docs.stunmesh.dev/configuration/overview
Storage plugins (built-in, exec, shell, dedup) docs.stunmesh.dev/plugins/overview
Writing your own plugin docs.stunmesh.dev/plugins/exec-protocol
Deployment guides (VyOS, macOS, OSPF/VRF) docs.stunmesh.dev/guides/vyos
Building from source & backend selection docs.stunmesh.dev/reference/build
Platform internals (fwmark, BPF capture, listen interfaces) docs.stunmesh.dev/reference/platform-internals

Build

make all

Note

For FreeBSD and MacOS, please use GNU Makefile gmake to build.

Build options (built-in plugin selection, binary minimization, WireGuard backend) are documented at docs.stunmesh.dev/reference/build. Contrib plugins live in contrib/ and are built with make plugin.

Future work / Roadmap

  • auto execute when routing engine notify change

License

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. See LICENSE (LGPL-3.0) and LICENSE.GPL (GPL-3.0, which the LGPL supplements).

Contributions are covered by the CLA.

WireGuard is a registered trademark of Jason A. Donenfeld.

About

A WireGuard helper that enables peer-to-peer connections through NAT using STUN discovery, with encrypted endpoint storage via a pluggable backend system.

Resources

Stars

249 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages