SSH 隧道与端口转发实战:安全访问内网数据库与运维服务

为什么需要 SSH 隧道

当数据库或运维服务部署在防火墙之后、没有公网 IP 时,直接远程访问往往寸步难行。开放数据库端口到公网会带来明显的安全风险,而临时修改防火墙规则又繁琐且容易出错。SSH 隧道(SSH tunnel)通过一条已加密的 SSH 连接,把本机端口与远端内网端口安全地桥接起来,让你像访问本地服务一样访问内网资源,全程数据加密、无需暴露额外端口。本文将以访问内网数据库和运维服务为例,完整演示 SSH 隧道与端口转发(port forwarding)的三种典型用法,并给出安全加固建议。如果你希望从整体上排查数据库性能问题,可以先参考我们关于 MySQL 慢查询分析 的实践,建立定位瓶颈的基础能力。

SSH 隧道连接内网数据库示意图

理解 SSH 端口转发的三种模式

SSH 端口转发本质上是把一条 TCP 连接”搬进”SSH 加密通道里。根据数据流动方向,可以分成三种模式:本地转发(local forwarding)、远程转发(remote forwarding)和动态转发(dynamic forwarding)。本地转发用 -L 参数,把本机某个端口映射到远端能访问的地址;远程转发用 -R 参数,把远端某个端口映射回本机或本机能访问的地址;动态转发用 -D 参数,在本机开一个 SOCKS 代理(SOCKS proxy,一种通用的网络代理协议),让所有走代理的流量都经 SSH 通道转发。

选择哪种模式,取决于”谁发起连接、目标在哪里”。如果你在本机,想访问远端内网里的数据库,用本地转发;如果你在远端,想让远端的人通过隧道访问你本机的服务,用远程转发;如果你只想让浏览器等应用安全地走代理访问内网,用动态转发。三种模式共用同一个底层机制,理解清楚方向后,命令参数就很好记了。

本地端口转发:安全访问内网数据库

最常见的场景是:数据库跑在一台内网服务器上,只监听 127.0.0.1,你需要在本地用客户端工具连接它。直接改监听地址到公网风险很高,本地转发是最稳妥的方案。命令格式是 ssh -L 本地端口:目标地址:目标端口 用户@跳板机

 # 把本机 3307 端口映射到内网数据库的 3306 端口
 ssh -L 3307:127.0.0.1:3306 deploy@192.168.1.10 -N -f

上面的命令中,-N 表示不执行远程命令、只建立隧道,-f 表示隧道建立后转入后台运行。执行后,本机的 3307 端口就相当于内网数据库的 3306 端口,你可以用数据库客户端连接 127.0.0.1:3307。这里 192.168.1.10 是跳板机(jump host,即能同时访问公网和内网的中间服务器)的内网地址,3307 是本地端口号,均为示例值,实际请按你的环境替换。相比直接开放数据库端口,这种方式的优势在于:数据库始终只监听内网地址,公网无法直接触达,所有流量都经过 SSH 加密通道。

如果数据库和跳板机不在同一台机器,只需把目标地址改成数据库的内网 IP。例如数据库在 192.168.1.20,命令就写成 ssh -L 3307:192.168.1.20:3306 deploy@192.168.1.10 -N -f。对于需要长期保持的隧道,建议配合密钥登录和 autossh(一个能自动重连的 SSH 守护工具)使用,避免隧道因网络波动断开后无人恢复。关于把高频只读数据缓存到内存层以减轻数据库压力的思路,可以参考我们关于 Redis 持久化与恢复 的实践。

SSH 本地端口转发示意图

远程端口转发:把内网服务安全暴露出去

另一种常见需求是反向的:内网里有一台机器,你想让外部(例如另一台公网服务器)通过隧道访问它上面的服务,但内网机器没有公网 IP。远程转发用 -R 参数,让内网机器主动连到一台有公网 IP 的跳板机,把跳板机上的某个端口映射回内网服务。

 # 在内网机器上执行:把公网跳板机的 8080 端口映射回本机 80 端口
 ssh -R 8080:127.0.0.1:80 deploy@203.0.113.5 -N -f

执行后,任何访问 203.0.113.5:8080 的流量,都会经 SSH 通道转发到内网机器的 80 端口。这里 203.0.113.5 是公网跳板机地址,8080 是公网端口,均为示例值。远程转发特别适合临时把内网的运维面板、测试服务暴露给外部协作者,而不必在路由器上做端口映射。需要注意的是,远程转发默认只监听跳板机的回环地址(loopback,即 127.0.0.1),要让外部网络也能访问,通常需要在跳板机的 SSH 配置里开启 GatewayPorts yes,并确认防火墙放行对应端口。如果担心暴露的服务被滥用,建议在跳板机上用防火墙或反向代理做访问控制,相关限流思路可以参考我们关于 Nginx 限流配置 的实践。

动态转发:一条隧道代理所有流量

当内网里有多个服务需要访问,逐个做端口映射会很繁琐。动态转发用 -D 参数,在本机开一个 SOCKS5 代理端口,之后把浏览器、命令行工具等应用的代理指向这个端口,所有流量都会经 SSH 通道转发到远端,由远端去访问目标地址。

 # 在本机开一个 SOCKS5 代理,监听 1080 端口
 ssh -D 1080 deploy@192.168.1.10 -N -f

执行后,把应用的 SOCKS5 代理设置为 127.0.0.1:1080,就能通过隧道访问内网里的任意服务,无需为每个服务单独建隧道。这里 1080 是本地代理端口,为示例值。动态转发非常适合需要同时访问内网多个 Web 服务、管理面板或 API 的场景,一条隧道即可覆盖。对于需要可视化监控内网服务运行状态的场景,把 Grafana 等监控面板部署在内网后,用动态转发或本地转发访问,既安全又方便,相关部署思路可以参考我们关于 Grafana 服务器部署 的实践。

SSH 动态转发代理多服务示意图

SSH 隧道的安全加固

隧道虽好,配置不当也会引入风险。以下几点是实践中值得注意的加固方向。第一,优先使用密钥登录并禁用密码登录,避免弱口令被爆破;第二,为隧道单独创建低权限用户,限制其能访问的资源;第三,在 ~/.ssh/config 里为常用隧道写别名,把参数固化下来,减少手写命令出错的可能。

 # ~/.ssh/config 示例:为内网数据库隧道配置别名
 Host db-tunnel
   HostName 192.168.1.10
   User deploy
   LocalForward 3307 127.0.0.1:3306
   ServerAliveInterval 30
   ServerAliveCountMax 3

配置完成后,直接执行 ssh db-tunnel 即可建立隧道。ServerAliveIntervalServerAliveCountMax 用于发送保活探测,避免空闲连接被网络设备断开,数值均为示例。对于长期运行的隧道,建议用 autossh 托管,并配合 systemd 服务实现开机自启和自动重连。此外,隧道本身不解决所有安全问题:如果跳板机被攻破,隧道内的流量也可能被截获,因此敏感服务仍应启用应用层加密,例如为 Web 服务配置 HTTPS,相关证书排错思路可以参考我们关于 Certbot 与服务器 SSL(Secure Sockets Layer,安全套接层)排错 的实践。

总结

SSH 隧道与端口转发是运维中非常实用的能力,用一条加密连接就能安全地访问内网数据库和运维服务,避免开放额外端口带来的风险。本地转发适合从本机访问内网资源,远程转发适合把内网服务安全暴露出去,动态转发则用一条隧道覆盖多个服务。建议你从本地转发访问内网数据库开始,先在小范围验证隧道连通性和安全性,再逐步扩展到远程转发和动态转发。配置时优先使用密钥登录、低权限用户和 autossh 托管,并定期检查跳板机的访问日志。如果你需要一台稳定、可灵活配置的服务器来承载跳板机或内网服务,Hostease 的 VPS(Virtual Private Server,虚拟专用服务器)方案支持自定义 SSH 配置,为这类运维场景提供了灵活的部署空间。建议把常用隧道参数固化到 ~/.ssh/config,让日常运维更省心、更安全。

发表评论