背景

OpenClaw 部署在本地服务器(无固定公网 IP),QQ Bot 开放平台要求配置 IP 白名单。通过 WireGuard VPN 将 OpenClaw 容器的出口流量从 VPS(固定公网 IP)出去,从而满足白名单要求。

架构

OpenClaw容器 → Docker网络 → 宿主机策略路由 → WireGuard隧道 → VPS → 互联网
(172.18.0.x)                  (10.10.0.2)                    (10.10.0.1)
                                                              出口IP = 43.138.233.89
  • 只有 OpenClaw 容器的流量走 VPN,宿主机和其他容器不受影响
  • 不需要修改 OpenClaw 容器,更新版本无需重新配置

环境信息

角色IP系统
VPS43.138.233.89OpenCloudOS (内核 5.4)
本地服务器动态 IPDebian
WireGuard VPS 端10.10.0.1-
WireGuard 本地端10.10.0.2-
OpenClaw 容器172.18.0.x (动态)Docker

一、VPS 端配置

1.1 开启内核转发

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

1.2 生成密钥

mkdir -p /root/wireguard/config
cd /root/wireguard
 
# 用 Docker 生成(或手动生成后放入 config 目录)
docker run --rm -i masipcat/wireguard-go wg genkey > config/privatekey
docker run --rm -i masipcat/wireguard-go wg pubkey < config/privatekey > config/publickey

1.3 创建 WireGuard 配置

cat > config/wg0.conf << EOF
[Interface]
PrivateKey = <VPS私钥内容>
Address = 10.10.0.1/24
ListenPort = 51820
PostUp = iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE
 
[Peer]
PublicKey = <本地服务器公钥>
AllowedIPs = 10.10.0.2/32
EOF

注意: eth0 需替换为 VPS 实际网卡名(用 ip -o -4 route show default | awk '{print $5}' 查看)。

1.4 Docker Compose 部署

cat > docker-compose.yml << 'EOF'
services:
  wireguard:
    image: masipcat/wireguard-go:latest
    container_name: wireguard
    cap_add:
      - NET_ADMIN
    network_mode: host
    volumes:
      - /dev/net/tun:/dev/net/tun
      - ./config:/etc/wireguard
    environment:
      - WG_COLOR_MODE=always
      - LOG_LEVEL=info
    restart: always
EOF

关键: 必须使用 network_mode: host,否则 wg0 在容器内部,宿主机看不到,NAT 转发不生效。使用 network_mode: host 后不能配置 sysctlsports,需在宿主机上手动设置。

1.5 启动并验证

docker compose up -d
docker logs wireguard
 
# 确认 wg0 在宿主机可见
ip a show wg0

1.6 添加 iptables 转发规则

如果日志中的 iptables MASQUERADE 因 iptables 版本问题未生效,手动在宿主机添加:

iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE
iptables -I FORWARD -i wg0 -j ACCEPT
iptables -I FORWARD -o wg0 -j ACCEPT

1.7 持久化 iptables 规则

yum install -y iptables-services
iptables-save > /etc/sysconfig/iptables
systemctl enable iptables

1.8 安全组

腾讯云安全组放行 UDP 51820 端口。


二、本地服务器配置

2.1 安装 WireGuard

apt install -y wireguard

2.2 生成密钥

wg genkey | tee /etc/wireguard/client_private | wg pubkey > /etc/wireguard/client_public

client_public 的内容填入 VPS 配置的 [Peer] PublicKey

2.3 创建 WireGuard 配置

CLIENT_KEY=$(cat /etc/wireguard/client_private)
cat > /etc/wireguard/wg0.conf << EOF
[Interface]
PrivateKey = $CLIENT_KEY
Address = 10.10.0.2/24
Table = off
 
[Peer]
PublicKey = <VPS公钥>
Endpoint = 43.138.233.89:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

关键配置说明:

  • Table = off:防止 WireGuard 覆盖宿主机默认路由,避免所有流量走 VPN
  • AllowedIPs = 0.0.0.0/0:允许所有目标地址的流量通过隧道(配合策略路由只让特定容器走)

2.4 启动 WireGuard

wg-quick up wg0
 
# 验证隧道连通
ping -c 3 10.10.0.1

2.5 设置开机自启

systemctl enable wg-quick@wg0

三、策略路由(只让 OpenClaw 容器走 VPN)

3.1 添加路由表

grep -q "wgvpn" /usr/share/iproute2/rt_tables || echo "100 wgvpn" >> /usr/share/iproute2/rt_tables

rt_tables 位置可能不同,用 find / -name "rt_tables" 2>/dev/null 查找。

3.2 配置策略路由

CONTAINER_IP=$(docker inspect 1Panel-openclaw-GCbN --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
 
ip route add default dev wg0 table wgvpn
ip rule add from $CONTAINER_IP table wgvpn

3.3 验证

# 容器走 VPN — 应返回 43.138.233.89
docker exec -it 1Panel-openclaw-GCbN curl -s --max-time 5 ifconfig.me
 
# 宿主机不走 VPN — 应返回本地 IP
curl -s --max-time 5 ifconfig.me

3.4 持久化策略路由

cat > /opt/openclaw-vpn-route.sh << 'SCRIPT'
#!/bin/bash
CONTAINER_IP=$(docker inspect 1Panel-openclaw-GCbN --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
if [ -z "$CONTAINER_IP" ]; then
    echo "Container not running"
    exit 1
fi
ip route replace default dev wg0 table wgvpn
ip rule del from $CONTAINER_IP table wgvpn 2>/dev/null
ip rule add from $CONTAINER_IP table wgvpn
echo "VPN route set for $CONTAINER_IP"
SCRIPT
chmod +x /opt/openclaw-vpn-route.sh
 
cat > /etc/systemd/system/openclaw-vpn-route.service << 'EOF'
[Unit]
Description=OpenClaw VPN Route
After=wg-quick@wg0.service docker.service
Requires=docker.service
 
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/openclaw-vpn-route.sh
ExecStartPre=/bin/sleep 10
 
[Install]
WantedBy=multi-user.target
EOF
 
systemctl daemon-reload
systemctl enable openclaw-vpn-route

四、OpenClaw 容器 DNS 配置

问题

容器默认使用本地 ISP 的 DNS,会将 api.sgroup.qq.com 解析到本地运营商优化的 IP(如 111.31.x.x)。流量走 VPN 从 VPS 出去后,这些 IP 无法从腾讯云网络访问,导致 QQ API 请求超时。

解决方案

在 OpenClaw 的 docker-compose 文件中(通过 1Panel 管理),为 OpenClaw 容器单独指定 DNS,不影响其他容器:

services:
  openclaw:
    # ... 现有配置保持不变 ...
    dns:
      - 119.29.29.29
      - 8.8.8.8
  • 119.29.29.29:腾讯 DNSPod,会返回腾讯云友好的 IP
  • 8.8.8.8:Google DNS,作为备用

验证

# 确认 DNS 配置生效
docker exec -it 1Panel-openclaw-GCbN cat /etc/resolv.conf
 
# 确认能连通 QQ API
docker exec -it 1Panel-openclaw-GCbN curl --max-time 5 -I https://api.sgroup.qq.com

注意: 修改 compose 文件后容器会重建,IP 可能变化,需重新执行策略路由脚本:/opt/openclaw-vpn-route.sh


五、QQ Bot 白名单

在 QQ 开放平台的 IP 白名单中填入 VPS 公网 IP:43.138.233.89


六、日常维护

查看 WireGuard 状态

# 本地
wg show
 
# VPS
docker exec wireguard wg show

OpenClaw 容器重启/更新后

如果容器 IP 变化,重新执行策略路由脚本:

/opt/openclaw-vpn-route.sh

故障排查

# 1. 检查隧道是否连通
ping -c 3 10.10.0.1
 
# 2. 检查容器出口 IP
docker exec -it 1Panel-openclaw-GCbN curl -s --max-time 5 ifconfig.me
 
# 3. 检查 WireGuard 握手状态
wg show
 
# 4. VPS 端检查
docker logs wireguard
ip a show wg0
iptables -t nat -L POSTROUTING -v -n | grep 10.10
iptables -L FORWARD -v -n | grep wg0
 
# 5. DNS 相关排查(QQ API 超时时检查)
docker exec -it 1Panel-openclaw-GCbN cat /etc/resolv.conf
docker exec -it 1Panel-openclaw-GCbN curl --max-time 5 -I https://api.sgroup.qq.com

七、安全提醒

  • WireGuard 私钥务必保密,不要泄露在聊天记录中
  • 如密钥已泄露,重新生成密钥对并更新两端配置
  • VPS 安全组只放行必要端口(UDP 51820)

Sources: