WireGuard + Nginx 中转架构实战(一)从设计思路到整体拓扑
写在前面
这是一套已经在生产环境跑通的中转架构。
目标并不复杂,但很现实:
- 源站不暴露公网
- 公网只开放一个入口
- 支持 Docker / Discourse / Web 应用
- HTTPS 终止在中转机
- 可扩展、可维护、可排错
如果你也有这些需求,这套方案可以直接照搬。
一、为什么需要“中转机”
常见的真实场景:
- 源站在内网 / 弱公网 / 低配 VPS
- 源站 IP 不稳定或不适合暴露
- 想统一 HTTPS / 证书 / 防护策略
- 想把管理后台(Portainer / Admin)彻底隐藏
传统方案的问题:
| 方案 | 问题 |
|---|---|
| 直接暴露源站 | 攻击面大,安全差 |
| SSH 端口转发 | 不稳定,维护成本高 |
| FRP / 内网穿透 | 复杂、依赖中心 |
| 反代直连公网 | 源站仍暴露 |
真正想要的是:源站“彻底不可达”,但业务可达
二、为什么选 WireGuard,而不是别的
WireGuard 在这个架构里解决的是 “可靠的私有网络” 问题。
它的特点非常适合做中转:
- 内核态 VPN,性能好
- 配置简单,几乎零维护
- 点对点,不依赖中心
- 不引入复杂路由
在这里,WireGuard 的职责只有一个:
让中转机像在访问本地内网一样访问源站
三、整体架构图(文字版)
公网用户
│
▼
中转机(VPS)
- 公网 IP
- Nginx(80 / 443)
- HTTPS 终止
- 统一反代
│
▼ WireGuard(10.100.0.0/24)
源站(VPS / 物理机)
- 无公网暴露
- Docker / Discourse
- 端口只绑定 WireGuard IP
关键原则:
- 公网只打到中转机
- 源站完全不可被公网访问
- 所有回源流量走 WireGuard
四、核心设计原则(非常重要)
中转机是唯一公网入口
- 80 / 443 只在中转机开放
- 证书、TLS、HTTP 逻辑都在中转机
- 源站不处理 HTTPS
源站端口只绑定 WireGuard IP
例如:
10.100.0.2:8082 → Discourse
10.100.0.2:9000 → Portainer
而不是:
0.0.0.0:8082 ❌
这一步,决定了源站是否真正“隐身”。
中转机只关心“IP + 端口”
中转机 不关心 Docker 容器名,不关心内部结构:
proxy_pass http://10.100.0.2:8082;
这让职责边界非常清晰:
- 源站:负责跑服务
- 中转机:负责发布服务
五、适用场景与不适用场景
非常适合
- Discourse 论坛
- Docker 应用
- 管理后台(Portainer)
- 个人站点 / 小团队服务
- 低配 VPS(512MB 也足够)
不适合
- 超高并发(需要 CDN)
- 复杂多地域调度
- 对延迟极度敏感的场景
六、你能得到什么
完成整套架构后:
- 源站 完全不暴露公网
- 公网攻击面只有 Nginx
- 管理后台可单独加白名单
- HTTPS、证书统一管理
- Docker / 应用随便换,不影响入口
这是非常接近生产级的中转模型。
WireGuard + Nginx 中转架构实战(二)WireGuard 中转机 ↔ 源站实战配置
一、目标与使用场景
本篇文章解决一个明确的问题:
在中转机与源站之间,建立一条稳定、安全、可长期运行的 WireGuard 内网通道
设计目标:
- 中转机是唯一公网入口
- 源站不暴露任何公网端口
- 回源流量全部走 WireGuard
- 服务器重启后 自动恢复连接
- 配置简单、可排错、可维护
二、网络规划(先规划,后动手)
推荐一对一的最小可控规划:
| 角色 | WireGuard IP |
|---|---|
| 中转机 | 10.100.0.1/24 |
| 源站 | 10.100.0.2/32 |
| WireGuard 端口 | 51820/UDP |
设计原则:
- 中转机使用
/24,方便以后扩展 - 源站使用
/32,最小授权 - WireGuard 只做“点对点内网”,不做复杂路由
三、安装 WireGuard(两台机器都做)
apt update
apt install -y wireguard
确认版本:
wg --version
四、生成密钥(安全、标准写法)
这一段是很多教程没写清楚的地方
设置安全的文件权限掩码
umask 077
含义:
- 新创建文件权限为
600 - 只有 root 可读写
- 避免私钥被误读(非常重要)
生成密钥(推荐固定路径)
在 中转机 执行:
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub
在 源站 执行:
wg genkey | tee /etc/wireguard/client.key | wg pubkey > /etc/wireguard/client.pub
生成结果:
/etc/wireguard/server.key # 中转机私钥
/etc/wireguard/server.pub # 中转机公钥
cat /etc/wireguard/server.key
cat /etc/wireguard/server.pub
/etc/wireguard/client.key # 源站私钥
/etc/wireguard/client.pub # 源站公钥
cat /etc/wireguard/client.key
cat /etc/wireguard/client.pub
检查权限(必须是 600):
ls -l /etc/wireguard/*.key
五、中转机配置(wg0.conf)
路径:
/etc/wireguard/wg0.conf
内容示例:
[Interface]
Address = 10.100.0.1/24
ListenPort = 51820
PrivateKey = <中转机 server.key 内容>
SaveConfig = false
[Peer]
PublicKey = <源站 client.pub 内容>
AllowedIPs = 10.100.0.2/32
说明:
AllowedIPs= 对端允许访问的 IP- 这里表示:源站只允许使用 10.100.0.2
六、源站配置(wg0.conf)
[Interface]
Address = 10.100.0.2/32
PrivateKey = <源站 client.key 内容>
SaveConfig = false
[Peer]
PublicKey = <中转机 server.pub 内容>
Endpoint = 中转机公网IP:51820
AllowedIPs = 10.100.0.0/24
PersistentKeepalive = 25
关键点:
PersistentKeepalive = 25→ 防止 NAT / 云厂商回收 UDP 映射AllowedIPs = 10.100.0.0/24→ 允许访问整个 WireGuard 内网
七、启动 WireGuard(避免残留接口)
启动前先清理(防止残留)
ip link delete wg0 2>/dev/null
启动接口
wg-quick up wg0
查看状态(非常重要)
wg show
正常状态应看到:
latest handshaketransfer: xx received, xx sent
八、验证内网连通性
在 中转机 执行:
ping 10.100.0.2
成功即说明:
WireGuard 密钥 AllowedIPs 全部正确
九、设置 systemd 开机自启(生产必做)
在 中转机 & 源站 都执行:
systemctl enable wg-quick@wg0
说明:
- 第一次 enable:可能显示
Created symlink - 已经 enable:可能无任何输出 都代表成功
验证是否已启用:
systemctl is-enabled wg-quick@wg0
输出应为:
enabled
查看运行状态:
systemctl status wg-quick@wg0
看到:
Active: active (exited)
这是正常状态,不是异常
十、重启后的最终自检(非常推荐)
服务器重启后,检查这 3 条即可:
ip a show wg0
wg show
ping 10.100.0.2
全部正常 = 隧道长期稳定运行
十一、常见问题与排坑总结
| 问题 | 原因 |
|---|---|
Required key not available | AllowedIPs 写反 |
wg0 already exists | 接口残留 |
| 能 up 但不通 | 公钥/私钥对错 |
| 过一段时间断 | 没设 PersistentKeepalive |
| enable 没输出 | 已启用(正常) |
十二、小结
到这里你已经完成了一条:
- 自动启动
- 权限安全
- 可扩展
- 可维护
的 WireGuard 中转通道。
后续所有内容(Docker 回源 / Nginx / Discourse)都建立在这一条隧道之上。
WireGuard + Nginx 中转架构实战(三)Docker 服务如何通过 WireGuard 回源(端口只绑定内网)
一、为什么中转机不能访问 http://app:80
因为:
app/portainer是 Docker 容器名- 只在 源站 Docker 网络内有效
- 中转机完全无法解析
二、正确方案(推荐)
容器端口绑定 WireGuard IP
三、docker-compose 示例
services:
app:
image: your-app
ports:
- "10.100.0.2:8081:80"
portainer:
image: portainer/portainer-ce
ports:
- "10.100.0.2:9000:9000"
启动:
docker compose up -d
四、验证监听地址
ss -lntp | grep 10.100.0.2
应看到:
LISTEN 10.100.0.2:9000
不应出现 0.0.0.0:9000
五、中转机验证回源
curl -I http://10.100.0.2:9000
六、源站防火墙(强烈建议)
ufw allow from 10.100.0.1 to any port 9000
ufw default deny incoming
WireGuard + Nginx 中转架构实战(四)Nginx 中转机多站点最终目录结构(生产推荐)
一、推荐目录结构
/etc/nginx/
├── conf.d/
├── sites-available/
│ ├── 10-root.conf
│ ├── 20-docker.conf
│ ├── 30-app.conf
├── sites-enabled/
│ └── (软链接)
├── snippets/
│ ├── ssl.conf
│ └── proxy-common.conf
二、为什么要 sites-available / enabled
- available:写配置
- enabled:是否生效
- 通过软链启用/禁用
ln -sf sites-available/a.conf sites-enabled/a.conf
三、通用 proxy 片段
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
四、多站点示例
docker.example.com
server {
listen 443 ssl http2;
server_name docker.example.com;
location / {
proxy_pass http://10.100.0.2:9000;
}
}
五、优势总结
- 清晰
- 可维护
- 不易误删
- 支持多站点扩展
WireGuard + Nginx 中转架构实战(五)Discourse 中转发布与 HTTPS 正确姿势
一、Discourse 的核心原则
- 不支持子路径
- 必须子域名或根域名
- 不建议 Discourse 自己跑 HTTPS
二、源站 Discourse 端口绑定
编辑:
/var/discourse/containers/app.yml
ports:
- "10.100.0.2:8082:80"
重建:
./launcher rebuild app
三、中转机 Nginx 配置
server {
listen 443 ssl http2;
server_name noth.me;
location / {
proxy_pass http://10.100.0.2:8082;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
}
四、Discourse 后台设置
force_https = trueDISCOURSE_HOSTNAME = noth.me
五、常见 502 原因
| 原因 | 说明 |
|---|---|
| 容器未启动完成 | Discourse 启动慢 |
| 端口未映射 | app.yml 写错 |
| 中转太快访问 | 等 2~3 分钟 |
六、正确状态验证
curl -I http://10.100.0.2:8082
返回 200 / 302 即正常。
结语
到这里,你已经拥有一套:
- 源站不可达
- HTTPS 统一
- Docker / Discourse 稳定运行
- 可长期维护的中转架构