Quick start
This guide assumes you’ve completed installation and the setup wizard. We’ll add a WireGuard tunnel, define a routing policy, register a device, and watch traffic exit through the tunnel.
What we’ll build
Section titled “What we’ll build” Laptop (192.0.2.50) │ ▼ Gateway (10.10.0.1) │ wg0 tunnel ▼ VPN provider exitThe laptop’s traffic — and only that laptop’s — will be policy-routed through wg0. Other LAN devices keep their direct egress.
1. Add a WireGuard tunnel
Section titled “1. Add a WireGuard tunnel”-
Open Tunnels in the sidebar.
-
Click Add tunnel → choose
wireguard. -
Paste a config you got from your VPN provider:
[Interface]PrivateKey = REDACTED_PRIVATE_KEY=Address = 10.10.0.2/32DNS = 10.10.0.1[Peer]PublicKey = REDACTED_PUBLIC_KEY=Endpoint = vpn.example.invalid:51820AllowedIPs = 0.0.0.0/0PersistentKeepalive = 25 -
Name it
wg0and click Save. -
Toggle the tunnel Up.
# Tunnel CRUD has no gwctl wrapper — POST through the REST APIcurl -X POST https://gateway.lan:8080/api/v1/tunnels \ -H "Authorization: Bearer $GATEWAY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "wg0", "type": "wireguard", "interface": "wg0", "private_key":"REDACTED_PRIVATE_KEY=", "address": "10.10.0.2/32", "peers": [{ "public_key": "REDACTED_PUBLIC_KEY=", "endpoint": "vpn.example.invalid:51820", "allowed_ips": ["0.0.0.0/0"], "persistent_keepalive": 25 }] }'
gwctl tunnels up wg0gwctl tunnelscurl -X POST https://gateway.lan:8080/api/v1/tunnels \ -H "Authorization: Bearer $GATEWAY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "wg0", "type": "wireguard", "interface": "wg0", "private_key": "REDACTED", "peers": [{ "public_key": "REDACTED", "endpoint": "vpn.example.invalid:51820", "allowed_ips": ["0.0.0.0/0"], "persistent_keepalive": 25 }] }'The tunnel should show Up with a non-zero handshake age within a few seconds. If it doesn’t, check journalctl -u gatewayd -f for handshake errors.
2. Register the device
Section titled “2. Register the device”The policy engine routes traffic per device, not per IP, because IPs change. Devices are matched by MAC.
- Open Devices → Add device.
- Fill in:
- MAC:
aa:bb:cc:11:22:33 - Hostname:
laptop-quickstart - Trust class:
operator(default) - Privacy class:
balanced
- MAC:
- Save.
The device will appear with a green dot once The Gateway sees ARP / DHCP traffic from it.
3. Create a routing policy
Section titled “3. Create a routing policy”- Open Routing policies → New policy.
- Match: Device ==
laptop-quickstart. - Action: Route via tunnel
wg0. - Fail policy: fail-closed (the kill-switch engages if
wg0goes down). - Priority: leave default.
- Save & Apply.
Behind the scenes The Gateway compiles the policy into:
- an entry in the
split-marknftables chain that tags packets from the device’s MAC with anfwmark - an
ip rule fwmark 0xNNN lookup TTTT - a route in table
TTTTpointing towg0 - a kill-switch rule that drops these marked packets when
wg0is down
4. Verify
Section titled “4. Verify”From the laptop:
curl https://ifconfig.me# → 198.51.100.42 (the VPN exit, not your ISP)From the gateway:
gwctl evaluate laptop-quickstart# Resolved policy:# match : device=laptop-quickstart# action : route via tunnel=wg0# fwmark : 0x101# table : 1001# fail : closedIn the web UI, Dashboard → Live traffic should show non-zero RX/TX on wg0.
5. Test the kill-switch
Section titled “5. Test the kill-switch”Bring the tunnel down on purpose:
gwctl tunnels down wg0From the laptop:
curl --max-time 5 https://ifconfig.me# → curl: (28) Connection timed outThe laptop has no internet. Other devices on the LAN are unaffected — the kill-switch is per-policy, not global.
Bring it back:
gwctl tunnels up wg0Traffic resumes within ~1 second of the first WireGuard handshake.
Related
Section titled “Related”- Concepts — the vocabulary every command above uses.
- Recipes → Routing — more policy shapes than the single tunnel here.
- Use cases — five end-to-end deployments built on these primitives.
- Troubleshooting — what to check if any of the verification steps misbehaved.