NOW ON AIREP.0802026 年秋番

使用WireGuard隧道连接ssh和mysql

使用 WireGuard隧道连接 SSH 和 MySQL

服务器 Debian 12 / 内核 6.1 / MySQL 8.0 / Node 24,客户端 Windows 11。
做完之后公网只剩 80、443 和一个 UDP 端口,SSH 和数据库都只在内网地址上出现,客户端换 IP 也不用动安全组。

起因

需求很小:本机的 Navicat 想连服务器的 MySQL。

把 3306 直接开放出去肯定不行,公网上的 MySQL 容易被扫到,不安全。退一步只开 22 走 SSH 隧道,比 3306 强,但 SSH 也是爆破重点;更麻烦的是家里和公司的出口 IP 会变,安全组按网段放行根本维护不过来。

剩下的路子就是先把远程访问整体收进内网,公网只多一个 UDP 端口,能不能连不再取决于 IP,而是取决于有没有私钥。WireGuard 干这件事的成本比预想低:Linux 5.6 之后已经进内核,apt install wireguard 就能用,配置一共两个文件。

为什么是 WireGuard

它认证的是公钥,不是 IP。客户端换了出口地址,只要加密包还能发到服务器,握手时就会把新地址记下来(peer roaming),所以客户端不需要固定 IP,前面安全组的麻烦也就没了。

它跑在 UDP 上,认证不过的包直接丢弃,不返回任何错误,扫描器拿不到有效响应,看起来跟没开端口一样。开销是每个包多 60 字节左右的头部,按 1400 字节载荷算约 4%,SSH 和数据库查询这点量感觉不出来。

排查也省事,wg show 直接给出最近握手时间和收发字节数,状态一眼能看到。

服务端

安装:

bash
apt update
apt install -y wireguard wireguard-tools
# 确认内核模块可用
modprobe wireguard && lsmod | grep wireguard

生成密钥:

bash
umask 077
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub
wg genpsk > /etc/wireguard/client.psk   # 可选,但建议加

/etc/wireguard/wg0.conf:

ini
[Interface]
Address = 192.168.100.1/24
ListenPort = 48230
PrivateKey = <SERVER_PRIVATE_KEY>

[Peer]
# 客户端备注
PublicKey = <CLIENT_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
AllowedIPs = 192.168.100.2/32

ListenPort 别用默认的 51820,那个端口是扫描器的重点对象。服务端的 AllowedIPs 含义是「允许这个 peer 使用哪些源地址」,写 /32 就够。配置文件权限必须收紧:

bash
chmod 600 /etc/wireguard/wg0.conf

启动并设成开机自启:

bash
systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0 --no-pager
wg show

wg show 里出现 listening port: 48230,就说明在监听了。

安全组这边只加一条入方向规则,以阿里云为例:协议 UDP,端口 48230,源 0.0.0.0/0。然后才是关 22,顺序别搞反:先确认 VNC 或云控制台能登进去,再关。隧道一旦出问题,那是唯一的入口。

Windows 客户端

装好 WireGuard后,新建隧道,内容如下:

ini
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 192.168.100.2/24
MTU = 1420

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
Endpoint = 203.0.113.10:48230
AllowedIPs = 192.168.100.0/24
PersistentKeepalive = 25

AllowedIPs 这里写 192.168.100.0/24,表示仅仅需要访问内网,而非全局代理。

PersistentKeepalive = 25 表示连接存活时间是25秒,不加的话空闲一段时间就得由客户端重新发起握手。

连上后验证一下:

bash
ping 192.168.100.1
ssh root@192.168.100.1

Navicat 的 SSH 隧道模式里有两个主机字段,视角完全不同,这是最容易填反的地方。SSH 选项卡的主机是从你的电脑出发去连的,填隧道对端 192.168.100.1:22;常规选项卡的主机是登进服务器之后从服务器本机出发去连的,填 127.0.0.1:3306。

MySQL 的 bind-address 是 127.0.0.1,只监听回环,所以常规页写服务器公网 IP 或 192.168.100.1 都连不上,只能写 127.0.0.1。

SSH 选项卡:

字段 值
主机 192.168.100.1
端口 22
用户名 root
认证方式 公钥
私钥文件 本机 ~/.ssh/id_ed25519
通行短语 私钥没有加密就留空

左右滑动查看完整表格

常规选项卡:

字段 值
主机 127.0.0.1
端口 3306
用户名 dbuser
密码 <DB_PASSWORD>
数据库 litenote

左右滑动查看完整表格

如果私钥是 OpenSSH 格式而 Navicat 提示无法读取,用 PuTTYgen 转成 .ppk,转换时通行短语同样留空(前提是原私钥本身没有加密)。

连不上时怎么查

先用命令行把同样的链路走一遍,把 Navicat 这个变量排除掉:

bash
ssh -N -L 13306:127.0.0.1:3306 root@192.168.100.1
# 另开一个终端
mysql -h 127.0.0.1 -P 13306 -u dbuser -p litenote

几种常见现象:

现象 原因
隧道显示已连接,但 ping 不通 Endpoint 被解析到 Fake-IP;或安全组没放行 UDP
ssh: connect to host 192.168.100.1 port 22: Connection timed out 隧道没起来,或 AllowedIPs 没包含 192.168.100.0/24
SSH 能通,Navicat 报 2003 常规页主机填成了公网 IP 或 192.168.100.1,应填 127.0.0.1
提示私钥口令错误 私钥没有加密,通行短语留空就行,不要随手填一个

左右滑动查看完整表格

text

几种常见现象:

| 现象 | 原因 |
|---|---|
| 隧道显示已连接,但 ping 不通 | Endpoint 被解析到 Fake-IP;或安全组没放行 UDP |
| `ssh: connect to host 192.168.100.1 port 22: Connection timed out` | 隧道没起来,或 `AllowedIPs` 没包含 192.168.100.0/24 |
| SSH 能通,Navicat 报 2003 | 常规页主机填成了公网 IP 或 192.168.100.1,应填 `127.0.0.1` |
| 提示私钥口令错误 | 私钥没有加密,通行短语留空就行,不要随手填一个 |
分享到

本文为原创文章,采用 CC BY-NC 4.0 许可协议,转载请注明出处。

订阅更新

新文章发布时邮件通知,随时可退订

ON AIR · 放送中

79话已放送94.7k字146条留言