随机推荐

WireGuard + Nginx 中转架构完整实战

目录

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 handshake
  • transfer: 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 availableAllowedIPs 写反
wg0 already exists接口残留
能 up 但不通公钥/私钥对错
过一段时间断没设 PersistentKeepalive
enable 没输出已启用(正常)

十二、小结

到这里你已经完成了一条:

  • 自动启动
  • 权限安全
  • 可扩展
  • 可维护

的 WireGuard 中转通道。

后续所有内容(Docker 回源 / Nginx / Discourse)都建立在这一条隧道之上

WireGuard + Nginx 中转架构实战(三)Docker 服务如何通过 WireGuard 回源(端口只绑定内网)

一、为什么中转机不能访问 http://app:80

因为:

  • app / portainerDocker 容器名
  • 只在 源站 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 = true
  • DISCOURSE_HOSTNAME = noth.me

五、常见 502 原因

原因说明
容器未启动完成Discourse 启动慢
端口未映射app.yml 写错
中转太快访问等 2~3 分钟

六、正确状态验证

curl -I http://10.100.0.2:8082

返回 200 / 302 即正常。


结语

到这里,你已经拥有一套:

  • 源站不可达
  • HTTPS 统一
  • Docker / Discourse 稳定运行
  • 可长期维护的中转架构