Autonomous WireGuard mesh VPN with P2P and relay fallback
Project description
Wire — Self-Hosted WireGuard Mesh VPN
No Tailscale dependency — run your own mesh VPN with full control.
Overview
Wire is a self-hosted WireGuard mesh VPN that automatically connects all your servers into a single private network (10.99.x.x/16). It handles peer discovery, NAT traversal, relay failover, and interface management — all with zero manual WireGuard configuration.
Features
- Zero config: Point to coordinator server, get connected automatically
- Auto mesh: Nodes discover each other via coordinator API
- Relay failover: Multi-relay support with automatic fallback
- NAT traversal: UDP hole punching with relay fallback for NAT clients
- Cross-platform: Linux, macOS, Synology NAS (DSM 7)
- MCP support: AI-driven VPN management via MCP server
- Interface:
wire0: Standardized interface name across all nodes
Quick Start
Coordinator + Relay Server (VPS with public IP)
python3 server.py 8786
Client Node
sudo python3 client.py --server http://YOUR_VPS:8786
Done. All clients automatically discover each other and form a mesh.
Architecture
┌─────────────────────────────────────────────────────────┐
│ Wire Mesh Network │
│ 10.99.x.x/16 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ Relay Nodes (Public IP) │ │
│ │ v1 (Primary) v2 (Secondary) v3 (Tertiary) │ │
│ │ AllowedIPs: per-peer /32 routing │ │
│ └──────────┬───────────────────┬────────────┘ │
│ │ │ │
│ ┌──────────┴───────────────────┴────────────┐ │
│ │ Client Nodes (Behind NAT) │ │
│ │ g1-g4 (GPU) d1-d2 (Bare Metal) │ │
│ │ m1 (macOS) s1-s2 (Synology NAS) │ │
│ │ AllowedIPs: 10.99.x.x/16 via relay │ │
│ └───────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Routing Model
- Relay nodes (v1, v2, v3): Have
/32routes to every peer; forward traffic between NAT clients - Client nodes: Route all VPN traffic (
10.99.x.x/16) via the primary relay (v1); direct/32peers added for VPS nodes with known endpoints - Hub node (v1): Primary relay and coordinator; all nodes set
AllowedIPs: 10.99.x.x/16for v1
Installation
One-liner (Linux)
curl -sSL http://YOUR_VPS:8786/install.sh | sudo bash
This installs WireGuard, downloads client.py, registers as a systemd service, and enables IP forwarding.
macOS
brew install wireguard-tools wireguard-go
sudo python3 client.py --server http://YOUR_VPS:8786
Synology NAS (DSM 7)
# Requires WireGuard package from SynoCommunity
# Config: /etc/wireguard/wire0.conf
# WireGuard binary: /volume1/@appstore/WireGuard/wireguard/wg-quick
# Boot script: /usr/local/etc/rc.d/wire0.sh
cat > /usr/local/etc/rc.d/wire0.sh << 'EOF'
#!/bin/bash
case "$1" in
start) /volume1/@appstore/WireGuard/wireguard/wg-quick up wire0 ;;
stop) /volume1/@appstore/WireGuard/wireguard/wg-quick down wire0 ;;
esac
EOF
chmod +x /usr/local/etc/rc.d/wire0.sh
Configuration
wire0.conf (Example — Client Node)
[Interface]
PrivateKey = <generated-private-key>
ListenPort = 51820
Address = 10.99.x.x/16
[Peer]
PublicKey = <relay-public-key>
Endpoint = <relay-public-ip>:51838
AllowedIPs = 10.99.x.x/16
PersistentKeepalive = 25
Coordinator API
| Endpoint | Method | Description |
|---|---|---|
/register |
POST | Register node (node_id, wg_public_key, port, lan_ip) |
/peers |
GET | List all registered peers |
/punch |
POST | Request NAT hole-punching (relay fallback on failure) |
/health |
GET | Coordinator health check |
MCP Integration
Wire includes a dedicated MCP server (wire-mcp-server.py) for AI-assisted VPN management.
{
"mcpServers": {
"wire": {
"command": "python3",
"args": ["/path/to/wire-mcp-server.py"]
}
}
}
MCP Tools
| Tool | Description |
|---|---|
wire_status |
Check VPN interface and peer status |
wire_peers |
List all connected peers with handshake info |
wire_install |
Generate installation commands for new nodes |
wire_diagnose |
Diagnose connectivity issues |
wire_connect |
Generate connect commands |
wire_add_node |
Add a new node to the mesh |
wire_remove_node |
Remove a node from the mesh |
wire_watchdog |
Monitor VPN health |
Cluster Status (14 Nodes)
| Server | Role | VPN IP | Platform | Interface |
|---|---|---|---|---|
| v1 | Relay + Coordinator | 10.99.x.x | Linux | wire0 |
| v2 | Relay | 10.99.x.x | Linux | wire0 |
| v3 | Relay | 10.99.x.x | Linux | wire0 |
| n1 | Client | 10.99.x.x | Linux | wire0 |
| g1 | Client | 10.99.x.x | Linux | wire0 |
| g2 | Client | 10.99.x.x | Linux | wire0 |
| g3 | Client | 10.99.x.x | Linux | wire0 |
| g4 | Client | 10.99.x.x | Linux | wire0 |
| d1 | Client | 10.99.x.x | Linux | wire0 |
| d2 | Client | 10.99.x.x | Linux | wire0 |
| m1 | Client | 10.99.x.x | macOS | wire0 |
| s1 | Client | 10.99.x.x | DSM 7 | wire0 |
| s2 | Client | 10.99.x.x | DSM 7 | wire0 |
Note: All nodes migrated from legacy
awlite0interface towire0as of 2026-03-14. Theawlite0interface and all related configurations have been fully removed from every server.
Troubleshooting
No handshake with peer
# Check interface status
wg show wire0
# Verify endpoint is reachable
ping <relay-public-ip>
# Manually set endpoint
wg set wire0 peer <pubkey> endpoint <ip>:<port>
Check if traffic routes through relay
ping 10.99.x.x
wg show wire0 # Check "endpoint" column — relay IP means relayed
Restart service
# Linux
systemctl restart wire
# Synology NAS
/usr/local/etc/rc.d/wire0.sh stop && /usr/local/etc/rc.d/wire0.sh start
Tailscale Fallback
If Wire VPN is unreachable, all nodes also have Tailscale installed as backup access:
# Example: access s1 via Tailscale
ssh user@100.x.x.x
Requirements
- Python 3.8+
- WireGuard:
apt install wireguard(Linux),brew install wireguard-tools wireguard-go(macOS) - IP forwarding enabled on relay nodes
File Locations
| File | Path | Description |
|---|---|---|
| server.py | MeshPOP/wire/server.py |
Coordinator + relay server |
| client.py | MeshPOP/wire/client.py |
Auto-mesh client agent |
| wire-mcp-server.py | MeshPOP/wire/wire-mcp-server.py |
MCP server for AI integration |
| wire0.conf | /etc/wireguard/wire0.conf |
WireGuard interface config |
| install.sh | Served via coordinator | One-liner install script |
Migration History
| Date | Change |
|---|---|
| 2026-03-14 | awlite0 → wire0 migration on s1, s2 (Synology NAS); awlite0 remnants removed from all 14 servers |
| 2026-02-26 | Mesh routing fix — v1 hub model with /16 routing; NAT clients route via relay |
| 2026-02-20 | Initial Wire deployment replacing Tailscale dependency |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file meshpop_wire-1.0.0.tar.gz.
File metadata
- Download URL: meshpop_wire-1.0.0.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b49bd58024a31c0ce6b9c1ca1ab4631b0be1355d2ddcb52667ab3b5d46cc6e0
|
|
| MD5 |
a9c222209a1aae26e7dcf30f3fb16efa
|
|
| BLAKE2b-256 |
6115dfec0925958a039f29018246151fc26497c946ef25009d78e66c5e0370bc
|
File details
Details for the file meshpop_wire-1.0.0-py3-none-any.whl.
File metadata
- Download URL: meshpop_wire-1.0.0-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29d22a50000384d19bc5104d147ece6f02ab8c65f17c8c7484310aeedaf72fc3
|
|
| MD5 |
f3c401f51aca24cc56e1c22e1f44d6bb
|
|
| BLAKE2b-256 |
90885db24faf9187e1ef8f49bd3016c03c32f9a006798cc49b6a5410a69de3d7
|