外地访问家里的服务,比起使用frp等内网穿透工具,组建虚拟局域网更为省心。当设备数量增多时,组网的优势更加明显。

WireGuard作为现代VPN技术,优势不再赘述。用几个关键词来形容:简单 高效 内核级 跨平台

网络拓扑设计

异地组网需一台具备公网IP的服务器作网关。中心服务器模式如下:

graph TB
    GW[中心服务器<br/>公网IP: x.x.x.x<br/>内网IP: 10.8.0.1]

    subgraph 家庭网络
        PC[家用电脑<br/>10.8.0.2]
        NAS[NAS存储<br/>10.8.0.3]
        TV[智能电视<br/>10.8.0.4]
    end

    subgraph 移动设备
        Phone[手机<br/>10.8.0.5]
        Laptop[笔记本<br/>10.8.0.6]
    end

    PC --> |WireGuard| GW
    NAS --> |WireGuard| GW
    TV --> |WireGuard| GW
    Phone -.-> |WireGuard| GW
    Laptop -.-> |WireGuard| GW

    classDef local fill:#lightgreen
    class PC,NAS,TV local
设备类型 IP范围 示例IP
服务器 10.8.0.1 10.8.0.1
其他设备 10.8.0.0/24 10.8.0.2

服务端

要求:

  • 境内公网IP服务器。境外IP大概率封端口甚至封IP
  • 合适的服务器带宽。推荐阿里云/腾讯云200M机器,如果没有视频等大流量需求,4~8M也可
  • 可访问的UDP端口

替代方案:WG-Easy

服务器配置比较好的可以用wg-easy方案,直接在Web管理界面操作。

本文专注于低配服务器(内存<512M)方案。Docker额外占用系统资源,这里不做展开。

手动方案

WireGuard已进入Linux内核,安装起来非常简单。参考官方安装文档

sudo apt update
sudo apt install wireguard -y

安装后提供wgwg-quick两个主要命令。

生成密钥对

每个WireGuard节点需要一对公私钥:

cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey > publickey

创建服务端配置 /etc/wireguard/wg0.conf

[Interface]
Address = 10.8.0.1/24
ListenPort = 10012
PrivateKey = <服务器私钥>

[Peer]
PublicKey = <客户端1公钥>
AllowedIPs = 10.8.0.2/32

[Peer]
PublicKey = <客户端2公钥>
AllowedIPs = 10.8.0.3/32

参数说明:

  • Address:服务器在VPN中的IP地址和子网掩码
  • ListenPort:监听的UDP端口
  • PrivateKey:服务器私钥
  • PostUp/PostDown:启动/关闭时执行的命令,用于设置IP转发
  • eth0:替换为外网网卡名称(用ip a查看)
  • 每个客户端对应一个[Peer]

启用IPv4转发

echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

配置防火墙

在云服务厂商后台添加UDP端口流量放行,本文的例子是10012

启动 systemd 服务

# 启动服务
sudo systemctl start wg-quick@wg0
# 开机自启
sudo systemctl enable wg-quick@wg0

查看状态以及热重载

# 查看状态
sudo wg show
# 热重载配置
sudo bash -c 'wg addconf wg0 <(wg-quick strip wg0)'

GUI客户端配置

根据平台下载GUI客户端,编辑配置

[Interface]
PrivateKey = <自动生成客户端私钥>
Address = 10.8.0.9/32

[Peer]
PublicKey = <服务端公钥>
AllowedIPs = 10.8.0.0/24
Endpoint = <服务端IP:端口>
PersistentKeepalive = 25

MacOS效果如图

CLI客户端配置

与服务端安装所有操作相同,只是配置文件替换成上面的客户端配置文件

一个便捷脚本:

#!/bin/bash

# 检查参数
if [ -z "$1" ]; then
  echo "用法: $0 <client_last_octet>"
  echo "例如: $0 9"
  exit 1
fi

OCTET="$1"

# 检查OCTET是否为1-254的数字
if ! [[ "$OCTET" =~ ^[0-9]+$ ]] || [ "$OCTET" -lt 1 ] || [ "$OCTET" -gt 254 ]; then
    echo "错误:client_last_octet 必须是1-254之间的整数"
    exit 1
fi

CLIENT_ADDRESS="10.8.0.${OCTET}/32"

# 请将以下两项替换为实际信息
SERVER_PUBLIC_KEY="<服务端公钥>"
SERVER_ENDPOINT="<服务器IP:端口>"  # 例:1.2.3.4:10012

# 检查 WireGuard 是否已安装
if ! command -v wg > /dev/null 2>&1; then
    echo "WireGuard 未安装,正在安装..."
     apt update
     apt install -y wireguard
else
    echo "WireGuard 已安装,跳过安装步骤。"
fi

# 切换到配置目录
cd /etc/wireguard || exit 1

# 生成密钥对(如果不存在)
if [ ! -f privatekey ] || [ ! -f publickey ]; then
    echo "密钥不存在,正在生成新的密钥对..."
    umask 077
    wg genkey | tee privatekey | wg pubkey > publickey
else
    echo "发现已存在的密钥对,将继续使用现有密钥。"
fi

# 读取密钥
PRIVATE_KEY=$(cat privatekey)

# 备份旧配置(如果存在)
if [ -f wg0.conf ]; then
    BACKUP_FILE="wg0.conf.bak.$(date +%Y%m%d%H%M%S)"
    echo "检测到已存在的 wg0.conf,备份到 $BACKUP_FILE"
    cp wg0.conf "$BACKUP_FILE"
fi

# 生成客户端配置文件
cat > wg0.conf <<EOF
[Interface]
PrivateKey = $PRIVATE_KEY
Address = $CLIENT_ADDRESS

[Peer]
PublicKey = $SERVER_PUBLIC_KEY
AllowedIPs = 10.8.0.0/24
Endpoint = $SERVER_ENDPOINT
PersistentKeepalive = 25
EOF

# 修改权限
chmod 600 wg0.conf privatekey publickey

# 启动 WireGuard
systemctl restart wg-quick@wg0
systemctl enable wg-quick@wg0

# 查看状态
wg show

# 读取客户端 PublicKey
CLIENT_PUBLIC_KEY=$(cat publickey)

echo
echo "================ 服务端需要添加的 Peer 配置 ================"
echo "[Peer]"
echo "PublicKey = $CLIENT_PUBLIC_KEY"
echo "AllowedIPs = 10.8.0.$OCTET/32"
echo "==========================================================="
echo

一些常见问题

运营商UDP QoS问题

使用udp2raw将UDP封装为TCP。

性能测试

  • iperf3:带宽测试
  • ping:延迟测试

NAT穿透

客户端在严格NAT后,添加PersistentKeepalive参数(25秒)一般就能解决