Simple WireGuard server with advanced traffic management
7.1K
Geek-friendly WireGuard server management with advanced routing capabilities.
WG-Busy is a web-based UI for managing a WireGuard server. It is inspired by projects like wg-easy but designed for power users who need more control over their configuration and routing.
Note
**WG-Busy is in early development.** Features may be incomplete, rough around the edges, or behave unexpectedly in certain environments. If you run into any issues or have ideas for improvement, please [open an issue](https://github.com/yix/wg-busy/issues) — feedback is very much appreciated and helps shape the project.
htmx and custom CSS for a fast, lightweight UI.wg0.conf files. You can customize PostUp/PostDown scripts and other advanced settings directly.CIDR via IP) per peer, automatically managing Linux policy routing tables. The gateway can be a WireGuard peer or a ZeroTier peer — each route is pinned to whichever interface its gateway is on-link for.bio-rd integration with dual-stack (IPv4 + IPv6) support for automated route advertisement and learning right into the Linux kernel routing table, complete with a BGP dashboard and per-peer route filters.zerotier-one alongside WireGuard — join and leave networks from the UI, with node status, assigned addresses, managed routes, peer latency/paths, and per-interface traffic counters.linux/amd64 and linux/arm64.Warning
**Security Notice**: WG-Busy **does not** implement authentication. It is intended to be run behind a reverse proxy (like Caddy, Nginx, or Traefik) that handles authentication (Basic Auth, OAuth, etc.) and TLS. Do not expose this UI directly to the public internet.
The easiest way to run WG-Busy is using Docker Compose.
services:
wg-busy:
image: ghcr.io/yix/wg-busy:latest
container_name: wg-busy
security_opt:
- systempaths=unconfined
cap_add:
- NET_ADMIN
- SYS_MODULE
devices:
- /dev/net/tun:/dev/net/tun # Required for ZeroTier
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
ports:
- "8080:8080" # Web UI
- "51820:51820/udp" # WireGuard
- "9993:9993/udp" # ZeroTier
volumes:
- ./data:/app/data # Configuration persistence
- /lib/modules:/lib/modules:ro # Required for WireGuard kernel module
restart: unless-stopped
wireguard-tools, iptables).make build
sudo ./bin/wg-busy-amd64 -config config.yaml -wg-config /etc/wireguard/wg0.conf
The application is configured via CLI flags:
| Flag | Default | Description |
|---|---|---|
-listen | :8080 | HTTP listen address for the UI |
-config | ./data/config.yaml | Path to the persistent YAML config file |
-wg-config | /etc/wireguard/wg0.conf | Path where the standard WireGuard config will be rendered |
-zt-data | ./data/zerotier | ZeroTier home directory (identity, authtoken, joined networks) |
One of WG-Busy's key features is the ability to define complex routing topologies. For a visual architecture guide with sequence and flow diagrams of all supported routing use cases, see ROUTING_SHOWCASE.md.
CIDR via Gateway IP rules per client. All traffic matching the CIDR and originating from that client will be directed to a dedicated policy routing table and pushed out the specified gateway.prohibit) instead of falling back to the server's main table.This is implemented using Linux policy routing (ip rule and custom routing tables), which WG-Busy manages automatically in the PostUp/PostDown hooks.
WG-Busy integrates deeply with bio-rd to provide a seamless BGP routing daemon working alongside WireGuard:
# 64000 - WG-Busy ASN
# 64001 - Mikrotik ASN
# 10.1.2.1 - WG-Busy BGP IP
# 10.1.2.3 - Mikrotik BGP IP
/routing bgp instance
add as=64001 disabled=no name=my-router router-id=10.1.2.3 routing-table=main
/routing bgp connection
add afi=ip as=64001 connect=yes disabled=no instance=my-router local.role=ebgp name=wg-busy output.filter-chain=wg-busy-out .keep-sent-attributes=yes .redistribute=connected,static remote.address=10.1.2.1 .as=64000 routing-table=main
# a list of allowed networks used in the bgp filter, if you would like to restrict advertised prefixes
/ip firewall address-list
# list will match exact network - 10.10.0.0/24 and longer prefixes, such as 10.10.0.1/32, 10.10.0.0/25, etc.
add address=10.10.0.0/24 list=wg-busy-out-allowed
add address=10.10.5.0/24 list=wg-busy-out-allowed
/routing filter rule
# match using an adress-list
add chain=wg-busy-out rule="if (dst in wg-busy-out-allowed) {accept}"
# match using a specific prefix, matches exact prefix unlike above ^^^
add chain=wg-busy-out rule="if (dst == 192.168.10.0/24) {accept}"
# reject all prefixes not matched by previous rules
add chain=wg-busy-out rule=reject
WG-Busy bundles the zerotier-one client and supervises it as a child process, so ZeroTier is
managed the same way as WireGuard: the desired state lives in config.yaml and the service is
reconciled toward it.
allowManaged, allowGlobal, allowDefault and allowDNS flags. Networks in the config are joined, networks removed from it are left. Changing a flag on an already-joined network applies without a rejoin.zt* interface, so traffic from a WireGuard client can be steered into a ZeroTier network.iptables -t nat -A POSTROUTING -o zt+ -j MASQUERADE), so WireGuard clients reach ZeroTier hosts without the ZeroTier network needing a route back to the WireGuard subnet. Disable it in the ZeroTier tab when the remote network already has a route back to the WireGuard subnet, or exempt enabled peers' advertised networks while retaining NAT for other traffic.zt* device. ZeroTier's local API exposes no byte counters, so traffic is per interface, not per peer.relayed when no direct path exists)./app/data/zerotier, so the node keeps its address across restarts. Requires /dev/net/tun and NET_ADMIN.[ZT] prefix, and its errors are shown in the tab with a remediation hint. A missing /dev/net/tun — where ZeroTier keeps running but can never create an interface — is detected up front and reported as "Running, degraded" rather than failing silently. Configured networks the service has not joined are listed separately under Not Joined.Members still need to be authorized in ZeroTier Central (or your own controller) before a network
leaves ACCESS_DENIED and gets an address.
make dev: Run locally (requires macOS/Linux with Go). Note that WireGuard interface management commands will fail on non-Linux systems or without sudo.make build: Cross-compile binaries for both linux/amd64 and linux/arm64.make build-amd64: Compile the linux/amd64 binary only.make build-arm64: Compile the linux/arm64 binary only.make docker-build: Build the Docker image.WG-Busy provides a clean, modern interface for managing your WireGuard server and advanced overlay routing.
Manage all your WireGuard clients, configure exit nodes, toggle policy routing, and view real-time bandwidth usage.

Configure the WireGuard server settings, including BGP overlay enablement, ASN, listen ports, and DNS preferences.

A dedicated dashboard for BGP sessions showing realtime stats on peer uptimes, received prefixes, and exactly which routes were accepted or filtered.

Run the managed ZeroTier client, join networks, inspect service and network status, and troubleshoot networks that have not joined.

MIT
Content type
Image
Digest
sha256:2e4db0a9f…
Size
14.3 MB
Last updated
19 days ago
docker pull mcgunn/wg-busy