Skip to content
Back to skills

Vpn Deployment

BSecurity

End-to-end WireGuard VPN deployment guide — VPS server setup, router client configuration, and traffic routing via apfree-wifidog tools.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
devopsgoshellbashawssecurity

Works with

  • cli

Security analysis

B84/100
  • mediumUses curl or wget to download content
  • criticalModifies startup scripts or system services for persistence

Pro shows the line behind each finding and how to fix it

Scanned September 29, 2026

npx -y skills add Arry8/openclaw-edge --skill vpn-deployment --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Vpn Deployment?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Vpn Deployment
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/arry8-vpn-deployment/badge)](https://www.skillsdirectory.com/skills/arry8-vpn-deployment)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: vpn-deployment
description: End-to-end WireGuard VPN deployment guide — VPS server setup, router client configuration, and traffic routing via apfree-wifidog tools.
user-invocable: true
---

# WireGuard VPN Deployment Guide

This skill guides you through the complete WireGuard VPN deployment workflow: installing and configuring a WireGuard server on a VPS, connecting an OpenWrt router as a client via `apfree_wifidog_set_wireguard_vpn`, and managing traffic routing via `apfree_wifidog_set_vpn_routes`.

## Overview

```
VPS (WireGuard Server)                     Router (WireGuard Client)
┌──────────────────────┐                   ┌──────────────────────┐
│  wg0: 10.0.0.1/24    │◄── WG tunnel ──► │  wg0: 10.0.0.2/24    │
│  Public IP: X.X.X.X  │                   │  LAN: 192.168.1.0/24 │
│  NAT masquerade       │                   │  ip route proto static│
└──────────────────────┘                   └──────────────────────┘
         │                                          │
    Internet ◄─── selected/all traffic ────── LAN clients
```

## Phase 1: VPS WireGuard Server Setup

These are local shell commands to run on the VPS directly (not through apfree-wifidog tools).

### 1.1 Install WireGuard

Detect the distro and use the appropriate package manager:

```bash
# Debian / Ubuntu
apt update && apt install -y wireguard

# CentOS 8+ / RHEL 8+ / Rocky / AlmaLinux
dnf install -y epel-release elrepo-release
dnf install -y kmod-wireguard wireguard-tools

# CentOS 7 (requires ELRepo)
yum install -y epel-release
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum install -y kmod-wireguard wireguard-tools

# Fedora
dnf install -y wireguard-tools

# Arch Linux
pacman -S --noconfirm wireguard-tools

# Verify
which wg && which wg-quick
modprobe wireguard && echo "wireguard module loaded"
```

> **Note:** On CentOS/RHEL with kernel < 5.6, the `kmod-wireguard` package provides the kernel module. On kernel >= 5.6 (including most CentOS 8 Stream / RHEL 9), WireGuard is built-in and only `wireguard-tools` is needed.

### 1.2 Generate Server Keys

```bash
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key
```

### 1.3 Generate Router Public Key (Secure — keys generated on router)

Instead of generating router keys on the VPS, use `apfree_wifidog_generate_wireguard_keys` to generate the key pair **on the router itself**. The private key is written directly to UCI and never leaves the device. Only the public key is returned.

```
Tool: apfree_wifidog_generate_wireguard_keys
Params:
  deviceId: "<router_device_id>"
```

Response will contain `data.public_key` — save this for the VPS `[Peer]` section below.

> **Security:** The router's private key never traverses the network (MQTT/WebSocket). It is generated locally by `wg genkey` and stored in UCI `network.wg0.private_key`.

### 1.4 Create Server Configuration

```bash
cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <server_private_key>
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT

[Peer]
# Router 1
PublicKey = <router1_public_key>
AllowedIPs = 10.0.0.2/32, 192.168.1.0/24
EOF
```

**Important:** Replace `eth0` with the actual public-facing interface name (`ip route get 1.1.1.1 | awk '{print $5}'`).

### 1.5 Enable IP Forwarding

```bash
# Check current state
sysctl net.ipv4.ip_forward

# Enable persistently (works on all distros)
sed -i '/^net.ipv4.ip_forward/d' /etc/sysctl.conf
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
```

### 1.6 Firewall Configuration

Open the WireGuard listen port. Detect which firewall is active:

```bash
# If firewalld is active (CentOS/RHEL/Fedora default)
if systemctl is-active --quiet firewalld; then
  firewall-cmd --permanent --add-port=51820/udp
  firewall-cmd --permanent --add-masquerade
  firewall-cmd --reload
# If ufw is active (Ubuntu/Debian default)
elif command -v ufw &>/dev/null && ufw status | grep -q "active"; then
  ufw allow 51820/udp
# Otherwise ensure iptables rules in wg0.conf PostUp/PostDown handle it
else
  echo "No firewalld or ufw detected; relying on wg0.conf PostUp/PostDown iptables rules."
fi
```

### 1.7 Start and Enable

```bash
systemctl enable --now wg-quick@wg0
wg show wg0
```

## Phase 2: Router WireGuard Client Configuration

Use apfree-wifidog tools to configure the router. Run these via the OpenClaw agent.

### 2.1 Configure WireGuard Tunnel

**Prerequisite:** Run `apfree_wifidog_generate_wireguard_keys` first (Phase 1.3). The private key is already stored in UCI.

Use `apfree_wifidog_set_wireguard_vpn` with:

- **interface**: tunnel address only (private key is already in UCI from key generation)
- **peers**: VPS public key + endpoint + `allowedIps: ["0.0.0.0/0"]` + `routeAllowedIps: false`

Setting `routeAllowedIps: false` prevents netifd from auto-creating kernel routes, letting us manage routes explicitly.

```
Tool: apfree_wifidog_set_wireguard_vpn
Params:
  deviceId: "<router_device_id>"
  interface:
    addresses: ["10.0.0.2/24"]
  peers:
    - publicKey: "<server_public_key>"
      endpointHost: "<vps_public_ip>"
      endpointPort: 51820
      allowedIps: ["0.0.0.0/0"]
      persistentKeepalive: 25
      routeAllowedIps: false
```

> **Note:** Do NOT pass `privateKey` here — it is already set by `generate_wireguard_keys`. The `set_wireguard_vpn` handler preserves existing UCI options that are not overwritten.

### 2.2 Verify Tunnel Status

Use `apfree_wifidog_get_wireguard_vpn_status` to confirm the tunnel is up and has a handshake.

## Phase 3: Traffic Routing

### 3.1 Selective Routing (specific destinations through VPN)

Use `apfree_wifidog_set_vpn_routes` with `mode: "selective"`:

```
Tool: apfree_wifidog_set_vpn_routes
Params:
  deviceId: "<router_device_id>"
  mode: "selective"
  routes: ["1.2.3.0/24", "4.5.6.0/24"]
```

### 3.2 Full Tunnel (all traffic through VPN)

Use `apfree_wifidog_set_vpn_routes` with `mode: "full_tunnel"` and `excludeIps` containing the VPS public IP to prevent routing loop:

```
Tool: apfree_wifidog_set_vpn_routes
Params:
  deviceId: "<router_device_id>"
  mode: "full_tunnel"
  excludeIps: ["<vps_public_ip>"]
```

### 3.3 Verify Routes

Use `apfree_wifidog_get_vpn_routes` to confirm routes are applied.

### 3.4 Remove Routes

Use `apfree_wifidog_delete_vpn_routes` with `flushAll: true` to clear all VPN routes.

## Phase 3B: Domain-Based Routing

When a user wants to route traffic for specific **domain names** (e.g. "youtube.com", "netflix.com") through the VPN tunnel, the agent must resolve domains to IP addresses first because `set_vpn_routes` only accepts CIDR blocks.

**Important:** `set_vpn_routes` does NOT accept domain names. Domains must be resolved to IPs before calling the tool.

### 3B.1 Resolve Domains to IPs

Run DNS resolution on the VPS (or any machine with internet access) using shell commands:

```bash
# Resolve a single domain to all IPs
dig +short youtube.com | grep -E '^[0-9]+\.' | sort -u

# Resolve multiple domains and aggregate
for domain in youtube.com netflix.com; do
  dig +short "$domain" | grep -E '^[0-9]+\.'
done | sort -u

# For domains with CDN (many IPs), use whois to get the CIDR block
whois $(dig +short youtube.com | head -1) | grep -i 'cidr\|route:' | head -3
```

### 3B.2 Convert IPs to CIDR Routes

Use `/32` suffix for each individual IP address to ensure precise routing through the tunnel.

1. **Individual IPs**: Use `/32` suffix for each IP — most reliable for domain-based routing.

   ```
   routes: ["142.250.80.46/32", "142.250.80.78/32"]
   ```

2. **CIDR aggregation**: Use the subnet that covers the IPs — fewer routes, slightly broader (use with caution).

   ```bash
   # Example: Google/YouTube IPs often fall within these ranges
   whois 142.250.80.46 | grep -i cidr
   # CIDR: 142.250.0.0/15
   ```

   ```
   routes: ["142.250.0.0/15"]
   ```

3. **Known service CIDR blocks**: For major services, use published IP ranges

   ```bash
   # Google/YouTube
   curl -s https://www.gstatic.com/ipranges/goog.json | jq -r '.prefixes[].ipv4Prefix' | head -20

   # Cloudflare
   curl -s https://www.cloudflare.com/ips-v4
   ```

### 3B.3 Push Routes to Router

After resolving domains to IPs (using `/32`), call `apfree_wifidog_set_vpn_routes`:

```
Tool: apfree_wifidog_set_vpn_routes
Params:
  deviceId: "<router_device_id>"
  mode: "selective"
  routes: ["142.250.80.46/32", "142.250.80.78/32"]
```

### 3B.4 Domain Routing Workflow Summary

The complete agent workflow when a user says "route youtube.com through VPN":

1. **Resolve**: Run `dig +short youtube.com` on VPS via shell → get IP list
2. **Aggregate**: Use `whois` or known ranges to find covering CIDRs
3. **Push**: Call `apfree_wifidog_set_vpn_routes` with the CIDRs
4. **Verify**: Call `apfree_wifidog_get_vpn_routes` to confirm

**Caveats:**

- DNS results change over time (CDN rotation). Routes may need periodic refresh.
- Large services (Google, AWS, Cloudflare) may have hundreds of CIDRs. Use aggregated ranges.
- Routes are kernel-only and lost on router reboot. Re-push after tunnel re-establishment.

## Phase 4: Adding More Routers

For each additional router:

1. Generate keys on the new router via `apfree_wifidog_generate_wireguard_keys` — note the returned public key
2. Add a `[Peer]` section to VPS `/etc/wireguard/wg0.conf` with the new router's public key and a unique tunnel IP (10.0.0.3/32, 10.0.0.4/32, etc.)
3. Reload VPS config: `wg syncconf wg0 <(wg-quick strip wg0)`
4. Configure the new router via `apfree_wifidog_set_wireguard_vpn` (Phase 2) — omit `privateKey` (already set)
5. Apply routes via `apfree_wifidog_set_vpn_routes` (Phase 3)

## Troubleshooting

| Symptom                           | Check                                                    | Fix                                                                              |
| --------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
| No handshake                      | `wg show wg0` on VPS — peer should show latest handshake | Verify endpoint host/port, check VPS firewall (see Phase 1.6)                    |
| WireGuard module not loaded       | `modprobe wireguard` fails                               | CentOS/RHEL: install `kmod-wireguard` from ELRepo; kernel >= 5.6 has it built-in |
| Tunnel up but no traffic          | `apfree_wifidog_get_vpn_routes` — routes should exist    | Re-apply routes with `set_vpn_routes`                                            |
| Full tunnel breaks VPS connection | `exclude_ips` missing VPS IP                             | Add VPS public IP to `excludeIps` array                                          |
| Routes lost after reboot          | Routes are not persisted in UCI                          | Re-push via `set_vpn_routes` after tunnel re-establishment                       |
| DNS not resolving through VPN     | Router using local DNS                                   | Configure DNS to use tunnel: `ip route add <dns_ip>/32 dev wg0 proto static`     |

## Security Notes

- **Private keys never leave the device.** Use `apfree_wifidog_generate_wireguard_keys` to generate keys on the router; only the public key is returned. The private key goes directly to UCI.
- Never expose private keys in logs or chat. Use placeholders when discussing.
- VPS firewall: open only the WireGuard listen port (default 51820/udp).
- Use `PresharedKey` for post-quantum protection when required.
- Rotate keys by calling `apfree_wifidog_generate_wireguard_keys` again and updating the VPS peer config with the new public key.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…