
你是否遇到过这些场景?
居家办公时,想连接公司内网的 MySQL 数据库(192.168.1.10:3306),但数据库仅允许内网访问,外网无法直接连接;客户现场调试,需要访问甲方内网的 PostgreSQL 服务,却没有 VPN 权限;本地开发环境需连接测试环境的 Redis 数据库(内网地址),直接访问被防火墙拦截。此时,SSH 本地端口转发(Local Port Forwarding) 就是最轻量的解决方案 —— 通过一台可 SSH 登录的 “内网跳板机”(如公司公网可达的服务器),将本地端口与内网数据库端口建立加密隧道,所有访问本地端口的请求都会经 SSH 转发到内网数据库,兼具 “零配置部署” 和 “数据加密” 优势。
本文以 “访问内网 MySQL 数据库” 为例,提供从 “环境验证→转发配置→客户端连接” 的完整实战步骤,其他数据库(PostgreSQL、Redis、MongoDB)操作逻辑一致,可直接复用。
在动手前先明确转发逻辑,避免操作时踩坑:
|
本地设备(如居家电脑)→ 本地端口(如 3306)→ SSH 加密隧道 → 跳板机(公网可达)→ 内网数据库(如 192.168.1.10:3306) |
这是关键前提:若跳板机无法访问内网数据库,本地转发必然失败,需先在跳板机上验证连通性。
|
# 格式:ssh 跳板机用户名@跳板机公网IP -p 跳板机SSH端口 ssh db-jump@47.100.xxx.xxx -p 22 # 示例(默认22端口可省略-p参数):ssh db-jump@47.100.xxx.xxx |
用 telnet 或 nc 工具测试跳板机到内网数据库的端口连通性(无需数据库账号密码,仅验证网络可达):
|
# 方法1:用telnet测试(若未安装,先执行 sudo yum install telnet -y 或 sudo apt install telnet -y) telnet 192.168.1.10 3306 # 方法2:用nc测试(更轻量,多数系统自带) nc -zv 192.168.1.10 3306 |
telnet 显示 Connected to 192.168.1.10;
nc 显示 192.168.1.10 3306 (mysql) open;
连通失败处理:若提示 Connection refused 或 Timeout,需联系内网管理员确认:
数据库服务是否正常运行;跳板机 IP 是否在数据库防火墙白名单中;数据库端口是否正确(如非默认 3306,需确认实际端口)。验证跳板机与数据库连通后,在本地设备执行转发命令,建立 “本地端口→跳板机→内网数据库” 的加密隧道。
|
# 完整格式 ssh -L [本地绑定IP:]本地转发端口:内网数据库IP:内网数据库端口 跳板机用户名@跳板机公网IP -p 跳板机SSH端口 [-fN] |
假设本地选择 3306 作为转发端口(与数据库默认端口一致,便于记忆),执行以下命令:
|
# 示例1:默认22端口,前台运行(需保持终端打开,关闭终端则转发断开) ssh -L 127.0.0.1:3306:192.168.1.10:3306 db-jump@47.100.xxx.xxx # 示例2:非默认SSH端口(如跳板机SSH端口为2222),后台运行 ssh -L 127.0.0.1:3306:192.168.1.10:3306 db-jump@47.100.xxx.xxx -p 2222 -fN # 示例3:本地端口被占用(如3306已被本地MySQL使用),改用3307端口 ssh -L 127.0.0.1:3307:192.168.1.10:3306 db-jump@47.100.xxx.xxx -fN |
|
# Linux/macOS 查看进程 ps aux | grep "ssh -L" | grep -v grep # 输出示例:db-user 1234 0.0 0.0 12345 6789 ? Ss 10:00 0:00 ssh -L 127.0.0.1:3306:192.168.1.10:3306 db-jump@47.100.xxx.xxx -fN # Windows(Git Bash)查看进程 tasklist | grep ssh.exe # 输出示例:ssh.exe 1234 Console 1 12,344 K |
转发隧道建立后,本地数据库客户端(如 Navicat、DataGrip、命令行)只需连接 “本地转发端口”,即可穿透到内网数据库。
本地已安装 MySQL 客户端(如 Linux/macOS 可通过 sudo yum install mysql 或 brew install mysql 安装):
|
# 格式:mysql -h 本地绑定IP -P 本地转发端口 -u 数据库用户名 -p mysql -h 127.0.0.1 -P 3306 -u dev_user -p # 若本地转发端口为3307,则改为:mysql -h 127.0.0.1 -P 3307 -u dev_user -p |
(截图描述:Navicat 新建连接窗口,上述参数对应输入框清晰标注,“测试连接” 按钮旁显示 “连接成功” 弹窗)
若执行转发命令时提示 bind: Address already in use(端口已被占用),按以下步骤解决:
查找占用端口的进程:|
# Linux/macOS 查找3306端口占用 lsof -i:3306 # 输出示例:COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME # mysql 5678 root 10u IPv4 12345 0t0 TCP *:mysql (LISTEN) # Windows(Git Bash)查找3306端口占用 netstat -ano | grep :3306 # 输出示例: TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 5678 |
默认后台转发依赖 SSH 连接,网络闪断或跳板机重启后会断开,用 autossh 工具可实现 “自动重连 + 心跳检测”:
本地安装 autossh:|
# Linux(CentOS/RHEL) sudo yum install autossh -y # Linux(Ubuntu/Debian) sudo apt install autossh -y # macOS(Homebrew) brew install autossh |
|
# 格式:autossh -M 心跳端口 -L 本地转发配置 跳板机信息 -fN # -M 20000:指定心跳检测端口(20000,需未被占用),autossh通过该端口检测连接状态 autossh -M 20000 -L 127.0.0.1:3306:192.168.1.10:3306 db-jump@47.100.xxx.xxx -fN |
手动杀死 SSH 进程(kill -9 转发进程号),10 秒后执行 ps aux | grep autossh,若能看到新的 SSH 转发进程,说明自动重连生效。
默认 127.0.0.1:3306 仅本地设备可访问,若误填 0.0.0.0:3306 会导致局域网其他设备可连接,存在安全风险,需通过以下方式加固:
转发命令强制绑定 127.0.0.1:执行转发时明确指定本地绑定 IP,如 ssh -L 127.0.0.1:3306:xxx,不使用 0.0.0.0;
本地防火墙限制端口访问(可选):|
# Linux(firewalld)禁止外部访问3306端口 sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="!127.0.0.1" port port="3306" protocol="tcp" reject' --permanent sudo firewall-cmd --reload |
|
-- 数据库管理员执行(在数据库服务器上) GRANT ALL PRIVILEGES ON *.* TO 'dev_user'@'跳板机内网IP' IDENTIFIED BY '数据库密码' WITH GRANT OPTION; FLUSH PRIVILEGES; -- 刷新权限 |
(跳板机内网 IP 可通过在跳板机执行 ip addr 查看,如 192.168.1.20)。
|
vim ~/.ssh/config # 添加以下内容(对所有跳板机生效,或指定 Host 仅对目标跳板机生效) Host * ServerAliveInterval 30 # 每30秒发送一次心跳包 ServerAliveCountMax 3 # 3次心跳无响应则断开 |
保存后重新执行转发命令,可大幅提升稳定性。
办公结束后,及时关闭本地转发进程,避免隧道长期开放:
|
# 查找转发进程号 ps aux | grep "ssh -L 127.0.0.1:3306" | grep -v grep | awk '{print $2}' # 杀死进程(替换为实际进程号) kill -9 1234 |
推荐用 ED25519 私钥登录跳板机,禁用密码登录(在跳板机 sshd_config 中设置 PasswordAuthentication no),避免暴力破解;
禁止转发敏感数据库到公网:仅用于测试 / 开发环境数据库,生产环境数据库需通过更严格的 VPN 或专线访问,禁止用本地转发暴露;
跳板机 IP 白名单:在跳板机防火墙(如 iptables)中仅允许自己的外网 IP 登录,拒绝其他 IP 访问 SSH 端口:
|
# 跳板机执行(仅允许 202.xxx.xxx.xxx 登录 SSH) sudo iptables -A INPUT -p tcp --dport 22 -s 202.xxx.xxx.xxx -j ACCEPT sudo iptables -A INPUT -p tcp --dport 22 -j REJECT |
|
数据库类型 |
内网数据库信息 |
本地转发命令示例 |
客户端连接参数(本地) |
|
PostgreSQL |
192.168.1.11:5432 |
ssh -L 127.0.0.1:5432:192.168.1.11:5432 ... |
主机 127.0.0.1,端口 5432 |
|
Redis |
192.168.1.12:6379 |
ssh -L 127.0.0.1:6379:192.168.1.12:6379 ... |
redis-cli -h 127.0.0.1 -p 6379 |
|
MongoDB |
192.168.1.13:27017 |
ssh -L 127.0.0.1:27017:192.168.1.13:27017 ... |
mongo --host 127.0.0.1 --port 27017 |
通过本文的实战步骤,你可快速掌握本地端口转发的核心操作,无需复杂部署就能安全访问内网数据库。若在操作中遇到其他问题,欢迎在评论区留言讨论!
附:本地端口转发常用命令速查表
|
操作场景 |
完整命令示例 |
|
前台转发(MySQL 3306) |
ssh -L 127.0.0.1:3306:192.168.1.10:3306 db-jump@47.100.xxx.xxx |
|
后台转发(非默认 SSH 端口) |
ssh -L 127.0.0.1:3306:192.168.1.10:3306 db-jump@47.100.xxx.xxx -p 2222 -fN |
|
查看转发进程 |
`ps aux |
|
杀死转发进程 |
kill -9 转发进程号(进程号通过查看命令获取) |
|
测试跳板机到数据库连通性 |
nc -zv 192.168.1.10 3306 |
|
命令行连接数据库 |
mysql -h 127.0.0.1 -P 3306 -u dev_user -p |