- Shell 99%
- Dockerfile 1%
| .forgejo/workflows | ||
| configs | ||
| data | ||
| .gitignore | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| entrypoint.sh | ||
| README.md | ||
| wg-hub | ||
Wire-Hub
A Docker-based WireGuard VPN aggregator that connects to multiple upstream VPN servers and exposes a single endpoint for your devices.
+-----------------+
| Your Phone |
| / Laptop |
+--------+--------+
|
| WireGuard
|
+--------v--------+
| |
| Wire-Hub |
| (Your Home) |
| |
+--+----+----+----+
| | |
+----------+ | +----------+
| | |
+------v------+ +------v------+ +------v------+
| VPN #1 | | VPN #2 | | Home Network|
| 10.8.0.0/24 | |172.16.0.0/24| |192.168.1.0/24|
+-------------+ +-------------+ +-------------+
Use cases:
- Access multiple VPN networks from a single connection
- Reach your home network while connected to the hub
- Aggregate split-tunnel VPNs into one client config
- Share VPN access with mobile devices via QR code
Quick Start
1. Create the directory structure
mkdir -p wire-hub/configs wire-hub/data
cd wire-hub
2. Add your VPN configurations
Place your WireGuard .conf files in the configs/ directory:
cp ~/Downloads/my-vpn.conf configs/
3. Create docker-compose.yml
services:
wire-hub:
image: git.k4li.de/docker/wire-hub:latest
container_name: wire-hub
cap_add:
- NET_ADMIN
- SYS_MODULE
devices:
- /dev/net/tun:/dev/net/tun
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
environment:
HUB_ENDPOINT: "vpn.example.com" # Your public IP or domain
LOCAL_NETWORKS: "192.168.1.0/24" # Your home network (optional)
ports:
- "51820:51820/udp"
volumes:
- ./configs:/configs:ro
- ./data:/data
restart: unless-stopped
4. Start the hub
docker-compose up -d
5. Connect your device
View the logs to see the QR code:
docker-compose logs
Scan the QR code with the WireGuard app on your phone, or copy data/clients/default.conf to your device.
Client Management
Wire-Hub supports up to 8 simultaneous client connections. A default client is created automatically on first start.
CLI Commands
Manage clients using the wg-hub command:
# Add a new client (auto-generates name like wg0, wg1, etc.)
docker exec wire-hub wg-hub add
# Add a client with a specific name
docker exec wire-hub wg-hub add phone
docker exec wire-hub wg-hub add laptop
# Show QR code for a client
docker exec wire-hub wg-hub show phone
# List all clients
docker exec wire-hub wg-hub list
# Remove a client
docker exec wire-hub wg-hub remove phone
Client Files
Client configurations are stored in /data/clients/:
<name>.conf- WireGuard configuration file<name>_private.key- Client's private key<name>_public.key- Client's public key
Each client gets a unique IP address in the 10.100.0.0/24 range (10.100.0.2 - 10.100.0.9).
Configuration
Environment Variables
| Variable | Required | Description |
|---|---|---|
HUB_ENDPOINT |
Yes | Public IP or domain where clients connect. The QR code won't work without this. |
LOCAL_NETWORKS |
No | Comma-separated CIDRs for networks reachable via default gateway (e.g., your home LAN). These won't be routed through VPN tunnels but clients can still reach them through the hub. |
Upstream VPN Configs
Place standard WireGuard configuration files in the configs/ directory. Each file creates a separate tunnel.
Example config (configs/work-vpn.conf):
[Interface]
PrivateKey = <your-private-key>
Address = 10.8.0.2/24
DNS = 10.8.0.1
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.work.com:51820
AllowedIPs = 10.8.0.0/24, 172.16.0.0/16
PersistentKeepalive = 25
Routing Behavior
| Upstream Config | Hub Behavior |
|---|---|
AllowedIPs = 10.8.0.0/24 |
Adds route for 10.8.0.0/24 through this VPN |
AllowedIPs = 0.0.0.0/0 |
Adds routes for all private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), excluding LOCAL_NETWORKS |
Address = 10.8.0.5/24 |
Automatically adds route for 10.8.0.0/24 (VPN's own network) |
Multiple VPNs
Each config file in configs/ gets its own interface:
configs/vpn1.conf→wg1configs/vpn2.conf→wg2- etc.
Routes are added based on each config's AllowedIPs. Traffic is routed to the appropriate VPN based on destination.
Network Layout
| Component | Address | Interface |
|---|---|---|
| Hub Server | 10.100.0.1/24 | wg0 |
| Clients | 10.100.0.2-9/32 | - |
| Upstream VPNs | (from config) | wg1, wg2, ... |
Examples
Access work VPN + home network from mobile
environment:
HUB_ENDPOINT: "home.example.com"
LOCAL_NETWORKS: "192.168.1.0/24"
With configs/work.conf containing your work VPN config, your phone can now access:
- Work resources (10.8.0.0/24) via the VPN tunnel
- Home devices (192.168.1.0/24) via the hub's local connection
Multiple VPNs with specific routes
Place multiple configs in configs/:
cloud-vpn.confwithAllowedIPs = 10.0.0.0/16office-vpn.confwithAllowedIPs = 172.16.0.0/16
The client config will include routes for both networks, each going through the appropriate tunnel.
Troubleshooting
Check hub status
docker-compose exec wire-hub sh
# View interfaces
wg show
# View routes
ip route
# Test connectivity
ping -c 1 <vpn-server-ip>
Regenerate all client configs
If you change environment variables (like LOCAL_NETWORKS), regenerate configs:
rm -rf data/clients/*.conf
docker-compose restart
Reset everything
Delete all data and start fresh:
rm -rf data/*
docker-compose restart
View logs
docker-compose logs -f
Building from Source
For development or customization:
git clone https://git.k4li.de/docker/wire-hub.git
cd wire-hub
# Build and run
docker-compose up --build
# Or build the image manually
docker build -t wire-hub .
Project Structure
wire-hub/
├── Dockerfile # Alpine-based image with wireguard-tools
├── docker-compose.yml # Container configuration
├── entrypoint.sh # Main orchestration script
├── wg-hub # Client management CLI
├── configs/ # Upstream VPN configs (mount point)
└── data/ # Generated data (mount point)
├── server_*.key # Hub server keypair
└── clients/ # Client configs and keys
License
MIT