云服务器做 VPN 体验:Docker 部署 WireGuard(wg-easy)
最近反代很火,所以不少人都买了或者白嫖了服务器,作为反代使用,给服务器只用来做反代肯定有很多的冗余,所以我考虑利用服务器的公网 ip,做成 vpn 使用,下面就是一个详细的教程
此方案重点是:
- 只对公网开放 VPN 端口(UDP 51820),管理后台不暴露公网,更安全。
- web 管理,方便多设备统一管理并导入
总体原理
- WireGuard 是 VPN,本质是服务器上开一个虚拟网卡
wg0,客户端连上后拿到一个虚拟 IP(如10.66.66.2)。 - “全局走 VPN / 分流” 主要由客户端配置里的
AllowedIPs决定:
- 全局:
0.0.0.0/0 - 分流:只填你想走 VPN 的网段(如
10.66.66.0/24或你家的内网段)
- 全局:
- wg-easy = WireGuard + Web 管理界面:让你一键创建多个设备配置、二维码导入。
A. 部署前检查(确认 Docker/Compose 可用)
在服务器执行:
docker --version
docker compose version
如果 docker compose version 报错,安装 compose 插件:
sudo apt update
sudo apt install -y docker-compose-plugin
确认 Docker 在运行:
sudo systemctl enable --now docker
B. 开启 IPv4 转发(否则连上 VPN 也可能无法上网)
执行:
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wg.conf
sudo sysctl --system
解释:
VPN 客户端的流量要 “经过服务器转发到公网”,Linux 默认可能不转发,所以要打开 ip_forward。
C. 云安全组 / 防火墙:放行端口
你需要在云厂商控制台安全组放行:
- 入站 UDP 51820(WireGuard 连接端口,必须)
- 管理后台端口 51821 不需要放行(我们会只让它监听 127.0.0.1)
解释:
如果 UDP 51820 没放行,客户端永远握手不上(handshake 失败),这是最常见原因。
D. 使用 Docker Compose 部署 wg-easy(安全版:后台不对公网开放)
1)创建目录
sudo mkdir -p /opt/wg-easy
cd /opt/wg-easy
2)创建 docker-compose.yml
把下面两处改掉:
WG_HOST=你的服务器公网IP或域名PASSWORD_HASH=改成密码的hash值
生成 bcrypt 密码哈希,并写入 PASSWORD_HASH
在服务器安装生成工具:
apt update
apt install -y apache2-utils
生成 bcrypt(示例密码用 123,实际请用强密码):
<BASH>
htpasswd -bnBC 10 "" "123" | tr -d ':\n' 会输出类似:
$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
关键细节:Compose 里必须把 $ 写成 $$
Docker Compose 会把 $VAR 当变量替换,所以 bcrypt 中的 $ 必须转义。
例如哈希是:
$2y$10$ABC...
写入 compose 时必须变成:
$$2y$$10$$ABC...
然后执行创建文件:
sudo tee /opt/wg-easy/docker-compose.yml >/dev/null <<'EOF'
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:latest
container_name: wg-easy
restart: unless-stopped
environment:
# 你的服务器公网 IP 或域名(客户端连接时用)
- WG_HOST=159.223.37.240
# 管理后台密码(务必设置强密码) # 这里切记(新版不可使用PASSDWORD,需要使用PASSWORD_HASH)
- PASSWORD_HASH= 这里填写你密码生成的hash值
# WireGuard 端口(UDP)
- WG_PORT=51820
# Web 管理后台端口(TCP)
- PORT=51821
# 给客户端分配的 VPN 网段
- WG_DEFAULT_ADDRESS=10.66.66.x
# 客户端默认 DNS(全局模式时通常需要)
- WG_DEFAULT_DNS=1.1.1.1
# 默认“全局走 VPN”(你优先全局,所以这里这样设)
- WG_ALLOWED_IPS=0.0.0.0/0
volumes:
# 配置与密钥会保存在宿主机这个目录,容器重建也不丢
- /opt/wg-easy:/etc/wireguard
# 让容器能使用宿主机内核模块
- /lib/modules:/lib/modules:ro
ports:
# 对公网开放 WireGuard
- "51820:51820/udp" # 管理后台只监听本机回环地址,不对公网开放(更安全)
- "127.0.0.1:51821:51821/tcp"
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
EOF
解释关键点:
WG_HOST:客户端配置里的Endpoint会用它,填错会导致连接不上。127.0.0.1:51821:51821/tcp:保证管理后台只能本机访问,公网扫不到。/opt/wg-easy:/etc/wireguard:把配置落地到宿主机,防止容器更新 / 重建后丢配置。
3)启动
cd /opt/wg-easy
sudo docker compose up -d
查看是否启动成功:
sudo docker ps
sudo docker logs --tail=200 wg-easy
E. 访问管理后台(通过 SSH 隧道)
因为我们没对公网开放 51821,所以用 SSH 隧道从你电脑访问:
在你自己的电脑(Windows/macOS/Linux 都可以)执行:
ssh -L 51821:127.0.0.1:51821 root@你的服务器公网IP
然后浏览器打开:
输入你设置的 PASSWORD 登录。
解释:
SSH 隧道相当于 “把服务器的本地端口映射到你本机”,外网无法直接访问后台,但你能安全管理。
F. 创建客户端(你的每台设备一个)
在 wg-easy 管理页面:
- 点 New Client
- 给设备起名(如
phone,laptop,ipad) - 直接:
- 扫二维码(手机 WireGuard App)
- 或下载配置文件(电脑 WireGuard 客户端导入)
建议:一台设备对应一个 client,方便你单独禁用 / 删除。
G. 连接测试(确认全局模式生效)
客户端连上后:
访问
https://ipinfo.io或https://ifconfig.me
看显示的出口 IP 是否变成你的服务器公网 IP(全局模式应当变为服务器 IP)如果你能 SSH 到服务器,也可以在服务器看握手:
sudo docker exec -it wg-easy wg show
H. 分流怎么实现
你现在默认是全局(WG_ALLOWED_IPS=0.0.0.0/0)。
如果某些设备想分流:在该设备的配置里把 AllowedIPs 改成你需要的网段即可,例如:
只走 VPN 内网(仅访问 VPN 内部资源,不代理全网):
AllowedIPs = 10.66.66.0/24
只访问你家 / 公司内网(举例 192.168.1.0/24):
AllowedIPs = 192.168.1.0/24, 10.66.66.0/24
做法:你可以在 wg-easy 里把该设备配置下载下来后手动改,或在客户端里编辑配置。
I. 结语
大家新手一般都是只有一台服务器,wg-easy 很适合作为第一站:先把 VPN 跑起来、把设备接入跑通;等你对需求更明确后,再决定是留在 wg-easy 继续精细化配置,还是迁移到原生 WireGuard、Headscale 这类更强的组网架构。