办公室服务器上的应用通过 localhost 连接 MySQL,你把这个主机名抄进桌面客户端,连接要么失败,要么打开另一个数据库。VPN 并没有改变这个词的含义:localhost 仍然指运行客户端的那台机器。VPN 搬动的是数据包,而不是网卡。在动任何路由之前,先确定笔记本应当访问哪个端点。

第 1 步:确定笔记本应当访问哪个端点

两种设计都成立,回答的是不同的问题。直接访问是指数据库监听在隧道能到达的私有地址上,笔记本连接该地址。转发访问是指数据库留在 loopback 上,由 SSH 会话把端口带到你的机器。请有意识地选择其中一种,因为混用会产生一个「因错误原因而能用」的连接。

直接访问时,向运维人员索取数据库主机自己的私有名称或地址及其端口。除非是同一台机器,VPN 网关的地址并不是数据库地址。然后确认监听器确实绑定在该网卡上,因为通往某个网卡的路由并不会在其上创建监听器。

第 2 步:只有监听器留在本机时才转发端口

如果数据库必须只留在 loopback 上,就用 SSH 转发,并把本地一端也绑定到 loopback。左侧的绑定地址属于你的笔记本;右侧的目标按 SSH 服务器一侧解释,正如 OpenSSH 参考文档 所述。把这两个角色弄反,正是转发看似能用却连不上任何东西的常见原因。

ssh -N -o ExitOnForwardFailure=yes -L 127.0.0.1:13306:127.0.0.1:3306 [email protected]
ss -ltn 'sport = :13306'

如果 SSH 落在跳板机上而不是数据库主机上,右侧的 loopback 就指跳板机,目标必须改成该主机能到达的地址。ExitOnForwardFailure 会捕获转发建立失败,但不能证明之后连到目标的连接会成功。保持主机密钥校验开启,也不要把转发端口绑定到所有网卡、从而暴露给整个局域网。

如果数据库必须只留在 loopback 上,而你又无法使用 SSH,就停下来。此时直接访问是错误的设计,而不是要强行凑出的配置。

第 3 步:强制客户端走 TCP

在 Unix 上,被指定 localhost 的 MySQL 客户端默认选择 Unix 套接字,所以只改端口可能让它去找一个与你的转发毫无关系的套接字。使用显式的 TCP 协议和 loopback 地址,让客户端打开到转发端口的连接。

mysql --protocol=TCP --host=127.0.0.1 --port=13306 --user=DB_USER --password

不带取值的密码选项会改为提示输入,而不是把口令写进命令行,这个习惯值得保留。其他工具对同一区别有自己的开关,一些驱动对 localhost 也有特殊处理。请核实客户端的行为,而不要假设开关被沿用。数据库账号还需要与服务器所见来源相匹配的授权,而那个来源是转发主机,不是你的笔记本。

如果工具无法被强制走 TCP,就停下来。此时改用其他客户端,或直接访问私有监听地址。

第 4 步:证明你实际到达的是哪个端点

问服务器它认为这条连接是什么。主机名、端口和套接字变量会告诉你是否经 TCP 到达、是哪个监听器应答的,连接列表则显示服务器记录的来源地址。这些证据比再改一次路由更有用。

mysql --protocol=TCP -h 127.0.0.1 -P 13306 -u DB_USER -p -e "SELECT @@hostname, @@port, @@socket"

记下你尝试的是哪个端点:本机 Unix 套接字、你的转发端口,还是私有监听地址。这三种失败的修法各不相同,而在客户端仍与错误的 localhost 对话时去改 VPN 路由是白费力气。笔记里也要把 SSH 认证和数据库认证分开,因为从桌面客户端看,其中一个的失败很像另一个的失败。最后,用完记得撤掉转发。

当你能说出端点、客户端协议、服务器看到的来源地址,以及放行它的那条授权时,清单就结束了。四个事实,下一次连接问题就只需几分钟,而不是一个下午。

相关文章