扔飒 发表于 2026-2-12 00:25:01

如何用SSH访问远程服务器上的内网服务(如:MySQL、Redis、Kafka)?

你是否有遇到以下的需求场景:

[*]场景1:你部署在个人的云服务器上的服务,出现了问题,想在本地的Navicat / DBeaver查一下线上MySQL,却发现连都连不上。
[*]场景2:线上 Redis 出问题了,你排查时发现无从下手。

[*]如果有打印日志,你还可以结合代码逻辑和日志来分析
[*]但是对于某些业务场景下的缓存穿透,Key 被误删,排查起来就比较困难了

[*]场景3:Kafka 有消息积压,但我连 Topic 都看不到

[*]有消息积压,你想:看 topic 列表,看 consumer group 状态,尝试手动消费一条消息。但是,Kafka 端口 9092 / 9093 不开放公网,本地 Kafka 工具根本连不上。
[*]Kafka 本身就复杂,一出问题,你连“观察窗口”都没有,完全依赖运维、日志和平台,排查问题的复杂度飙升。

以上问题的原因是什么?

[*]MySQL、Redis、Kafka配置了只有本地127.0.0.1可以访问,不能通过其他IP访问
[*]防火墙没有对服务端口开放
[*]云服务器的安全策略也没有对端口打开
而我只想临时做几件事:

[*]只想临时查看数据、验证问题
[*]不想改防火墙、安全策略组
[*]不想改代码、不想提需求、不想走审批
我要临时访问内网服务,但是网络不通,不能随便改网络,有没有什么技术方法解决这个问题?答案是肯定的 —— SSH本地端口转发。
注意:这有个很重要的前提条件,你能通过SSH连接到远程服务器。
实现思路

一句话概括原理:利用 SSH 在本地和远程服务器之间建立一条加密通道,把远程内网端口“转发”到本地端口。
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211215118833-328938205.png
对本地工具来说:它以为自己连的是 localhost
实际上流量通过 SSH:

[*]先到远程服务器
[*]再由远程服务器访问内网服务
[*]你不需要改网络、不需要开端口、不需要暴露服务。
语法:ssh -L [本地端口]:[目标主机]:[目标端口] @
对于开发人员来说,常用的两类应用场景:

[*]远程服务器上的某些服务无法从公网访问

[*]线上环境里,数据库、中间件(MySQL / Redis / Kafka)几乎从不暴露公网端口,只能在内网访问。
[*]防火墙是关闭状态,暴露公网访问需要改动防火墙(易出错)
[*]云服务器的安全策略阻止访问,需要手动配置流入、流出的安全策略端口


[*]公司内网服务器上的服务无法从本机访问

[*]服务内网部署,不对开发人员开放
[*]权限管控严格
[*]想调试问题,但安全策略比问题还复杂,懒得去配置
[*]内网服务器上不允许随便安装其他第三方软件
[*]注意:此方式可能让你违规,谨慎使用
这种方式适合哪些场景?

[*]非常适合

[*]临时排查线上问题
[*]查看缓存数据
[*]不想改代码
[*]不想装客户端
[*]权限受限环境

[*]不适合

[*]长期运维通道
[*]高并发访问

执行步骤

在了解了基本原理和实现思路后,开始梳理执行步骤,跟着我一步一步来实现吧。
执行步骤

[*]第一步:能正常 SSH 登录到一台服务器,且允许端口转发
[*]第二步:明确你要连接的目标,开启本地端口转发
[*]第三步:验证 SSH 隧道是否生效
[*]第四步:远程访问目标服务
假设我要连接远程服务器(8.145.45.70)的Redis服务,他们在远程服务器上分别使用6379端口。
在本地选择一个没被占用、你自己记得住的端口,比如:16379。不要求和远端端口一致,只是为了好记。
如何检查SSH服务器是否允许端口转发?检查sshd_config中以下配置项的值

[*]AllowTcpForwarding no  #应该改为yes
[*]AllowAgentForwarding no  #应该改为yes
[*]PermitTunnel no  #应该改为yes
开启本地端口转发

在本地创建 SSH 隧道

[*]这一操作的目标是:让本地某个端口,指向远程内网服务端口
[*]流量流向:localhost:本地端口 --> SSH 隧道 --> 远程内网IP:服务端口
在终端执行命令:ssh -L 16379:127.0.0.1:6379 root@8.145.45.70
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211223744883-1369635982.png
验证本地端口是否生效:netstat -ano | findstr 16379
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211223911662-2126026790.png
验证方式最简单,检查本地端口是否处于监听状态。如上图,本地的16379已经处于LISTENING状态。
执行完成后:SSH 连接会保持,本地端口开始监听,所有访问都会被转发。此时你“看起来什么都没做”,但通道已经打通了。
 
在上面的开启本地端口转发的图片中,你可能发现了这个SSH链接进入了交互式的Shell Terminal,要是我不想进入这种交互式的终端,应该怎么做呢?
不打开交互式对话:ssh -N -L 16379:127.0.0.1:6379 root@8.145.45.70

[*]-N:不执行远程命令(只做端口转发)
[*]更安全、更清晰
放到后台运行:ssh -f -N -L 16379:127.0.0.1:6379 user@server_ip

[*]-f:放到后台
[*]用完记得杀掉进程:tasklist + taskkill / ps + kill
远程访问

接下来是最“反直觉但最爽”的一步:

[*]不再使用内网 IP,也不再使用远程服务器 IP,而统一使用: 127.0.0.1 或 localhost
[*]端口使用你刚刚在本地绑定的端口
 
本地使用已安装的 redis-cli 工具连接Redis:redis-cli -h 127.0.0.1 -p 16379
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211224212748-461304407.png
使用 GUI 客户端(Another Redis Desktop Manager)连接远程Redis
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211224250941-2082874978.png
QA

报错:prohibited
channel X: open failed: administratively prohibited
channel 3: open failed: administratively prohibited: open failed
原因:管理员禁止了你使用端口转发
解决:sshd_config 中禁用了端口转发

[*]AllowTcpForwarding no  #应该改为yes
[*]AllowAgentForwarding no  #应该改为yes
[*]PermitTunnel no  #应该改为yes
 
报错:Connection timed out
原因:连接超时,网络问题
解决:检查网络是否连通、防火墙是否开放
 
我有MySQL、redis、kafka都要进行本地端口转发,可以只有一个端口吗?
不行。
SSH 本地端口转发是:一个本地端口 与 一个远程地址:端口 是一对一映射。
一条命令同时开启转发:ssh user@server \
  -L 13306:127.0.0.1:3306 \
  -L 16379:127.0.0.1:6379 \
  -L 19092:127.0.0.1:9092
 
连不上 Redis,但 SSH 没报错?

[*]检查Redis 是否监听 127.0.0.1
[*]是否启用了密码
[*]是否限制 protected-mode
 
在使用过程中,是否SSH 连接必须保持?

[*]是的
[*]SSH 断开 = 隧道失效,本地工具会立即连不上
[*]建议单独开一个终端,专门用于维护 SSH 隧道
[*]根据场景考虑是-N、-f参数
 
为什么有些公司的安全团队会关闭SSH的端口转发?

[*]SSH 端口转发 = 隐形隧道
[*]可绕过防火墙 / 网关 / 审计
[*]本地流量进了内网,难以追踪
[*]容易被当成内网代理滥用
[*]场景配置:

[*]AllowTcpForwarding no
[*]AllowAgentForwarding no
[*]PermitTunnel no
[*]X11Forwarding no #是否允许把“远程服务器上的图形界面程序”,转发到你本地屏幕上显示。

额外提醒:

[*]SSH隧道用完即关,本地端口立即释放,不留任何后门
[*]妥善保管SSH连接密码、私钥
多级跳板

企业服务器通常有以下特点:

[*]内网环境,不直接暴露公网
[*]安全要求高,必须对访问进行审计
[*]多人运维或开发团队共用服务器
[*]不允许直接暴露管理端口
问题:如果你直接 SSH 登录内网服务器,就会导致

[*]没有日志记录
[*]难以审计操作
[*]可能导致安全风险
解决方案就是:在公网部署一台或多台跳板机 (Bastion / JumpServer),通过 SSH 间接访问目标服务器。接下来,我们一起探索如何在一台和多台跳板机上实现端口转发。
一级跳板

通过跳板机(Jump Host / Bastion Host),利用 SSH 作为中转,访问内网里的目标服务器。
一级跳板的网络结构:
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211225042832-192074460.png
实现方式一:手动两次SSH逐步跳转

[*]第一步:先登录跳板机:ssh jump_user@jump_host
[*]第二步:在跳板机上,再 SSH 到目标服务器:ssh target_user@target_host
实现方式二:-J语法实现
语法:ssh -J jump_user@jump_host target_user@target_host
例如:ssh -NT -L 3306:127.0.0.1:3306 -J jump_user@jump_host target_user@target_host

[*]-L 3306:127.0.0.1:3306  本地 3306 → 目标3306
[*]-J jump_user@jump_host  先跳到跳板机
[*]target_user@target_host 再连到目标机
[*]-N  不执行远程命令
[*]-T  不分配 TTY
[*]仅支持OpenSSH(7.3+)
实现方式三:-o语法实现
语法:ssh -o ProxyCommand="ssh jump_user@jump_host -W %h:%p" target_user@target_host
例如:ssh -NT -L 3306:127.0.0.1:3306 -o ProxyCommand="ssh jump_user@jump_host -W %h:%p" target_user@target_host

[*]如果 SSH 版本 < 7.3(没有 -J)
[*]注意是小写的o
二级跳板

二级跳板的网络结构:
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211225336322-880147829.png
实现方式一:-J语法实现
ssh -J user1@jump1,user2@jump2 user3@target
例子:ssh -NT -L 3306:127.0.0.1:3306 -J user1@jump1,user2@jump2 user3@target

[*]跳板机之间连续写,逗号分割
[*]注意:跳板机前后顺序非常重要,按网络进入方向写。
[*]-L 3306:127.0.0.1:3306  本地 3306 → 目标3306
[*]-N  不执行远程命令
[*]-T  不分配 TTY
[*]仅支持OpenSSH(7.3+)
实现方式二:-o语法实现
语法:ssh -o ProxyCommand="ssh user1@jump1 \
               -o ProxyCommand='ssh user2@jump2 \
               -o ProxyCommand=\"ssh user3@jump3 -W %h:%p\" -W %h:%p' \
           -W %h:%p" \
          user4@target

[*]注意引号,最外层是双引号,内层是单引号,区分引号的边界
[*]命令太复杂了,维护起来很难
[*]不推荐使用
 
三级跳板?
语法:ssh -J jump1,jump2,jump3 target
注意点:-J后面跟跳板机,注意顺序
服务部署在Docker上

如果你的内网服务部署在Docker上,如何实现SSH的本地转发呢?
两种情况

[*]容器的端口映射到了宿主机
[*]容器的端口没有映射到了宿主机
映射到了宿主机

Redis容器的端口映射到了宿主机

[*]在启动容器时指定了端口映射:docker run -d --name redis-server-16379 -p 16379:6379 redis:7
[*]SSH本地端口转发直接参考上文中的执行步骤。因为相当于宿主机的16379号端口上工作了Redis服务,对于我们来说,跟Redis直接运行于宿主机上没有区别。
执行步骤

[*]环境准备

[*]进入远程服务器,启动一个Redis Docker:docker run -d --name redis-server-16379 -p 16379:6379 redis:7
[*]进入容器:docker exec -it redis-server-16379 /bin/bash
[*]往容器中的Redis塞入一个键值对:set name hackyle

https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230123602-556526716.png
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230201238-1099260311.png

[*]在本台机器上开启本地端口转发:ssh -NT -L 16379:127.0.0.1:16379 root@8.145.45.70
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230330785-1307889599.png

[*]验证:在本台机器上连接16379端口,访问到远程Docker中的Redis
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230458069-231244983.png
未映射到宿主机

MySQL容器的端口没有映射到了宿主机

[*]先查看容器 IP:docker inspect mysql | grep IPAddress
[*]再SSH 本地端口转发,直接指向容器 IP:ssh -L 3306:172.17.0.3:6379user@remote-host
 
执行步骤
1.环境准备

[*]进入远程服务器,启动一个Redis Docker:docker run -d --name redis-server-26379 redis:7
[*]查看容器IP:docker inspect redis-server-26379 | grep IPAddress
[*]进入容器:docker exec -it redis-server-16379 /bin/bash
[*]往容器中的Redis塞入一个键值对:set name hackyleshawe
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230636360-296586627.png
2. 在本台机器上开启本地端口转发:ssh -NT -L 26379:172.17.0.3:6379 root@8.145.45.70

[*]本地端口使用26379,转发的目标是docker的IP
[*]docker redis运行的端口时6379,所以“-L 26379:172.17.0.3:6379”
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230841057-1595647213.png
3.验证:在本台机器上连接26379端口,访问到远程Docker中的Redis
https://img2024.cnblogs.com/blog/3067233/202602/3067233-20260211230947517-774638042.png
结尾

本文主要阐述了用SSH访问远程服务器上的内网服务(如:Redis)的原理和操作步骤,同时对部署在Docker中的服务如何访问也做了解释说明。
在文章最后,尝试对自己提问一下问题,来检验你是否真正了解到了本文的核心内容:

[*]什么是SSH的本地端口转发(Local Port Forwarding)?
[*]他能做什么?能帮你解决什么问题?
[*]怎么使用?语法是什么?
[*]内网服务部署在Docker和宿主机,使用端口转发访问时有什么区别?
本文结束。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

庞悦 发表于 2026-2-22 09:36:20

用心讨论,共获提升!

孟清妍 发表于 2026-2-24 14:27:47

喜欢鼓捣这些软件,现在用得少,谢谢分享!

利怡悦 发表于 2026-3-5 06:18:19

鼓励转贴优秀软件安全工具和文档!

洪思思 发表于 2026-3-11 05:27:33

分享、互助 让互联网精神温暖你我

吁寂 发表于 2026-3-12 04:03:46

很好很强大我过来先占个楼 待编辑
页: [1]
查看完整版本: 如何用SSH访问远程服务器上的内网服务(如:MySQL、Redis、Kafka)?