SSH 常见用法(三):本地端口转发与远程端口转发
系列导读
本系列共包含一篇总览和四篇专题文章:
| 系列位置 | 文章主题 | 主要内容 |
|---|---|---|
| 总览 | 浅谈 SSH:原理、认证与四种常见用法 | 认识 SSH 及其四种常见用法 |
| 第一篇 | SSH 常见用法(一):远程登录服务器 | 密码登录、密钥认证和~/.ssh/config |
| 第二篇 | SSH 常见用法(二):通过 SSH 认证访问 Git 仓库 | 配置 SSH Key,并通过 SSH 操作远程仓库 |
| 第三篇(本文) | SSH 常见用法(三):本地端口转发与远程端口转发 | -L本地端口转发与-R远程端口转发 |
| 第四篇 | SSH 常见用法(四):使用 SCP 和 SFTP 远程传输文件 | 在本机与服务器之间安全传输文件 |
一、前言
SSH 隧道通常通过端口转发(Port Forwarding)实现。它和“远程登录服务器”不一样。远程登录的目标是:
让我进入远程服务器的 Shell。
而 SSH 隧道的目标更像是:
借助 SSH 加密连接,在经过授权的网络环境中安全连接两端的服务。
SSH 连接负责建立“隧道”;隧道出口所在的那一侧,还必须能访问最终目标。
-L:在本机打开一个端口,通过 SSH 服务器连接远程目标服务。-R:在远程 SSH 服务器上打开一个端口,通过 SSH 隧道连接本机目标服务。
-R也常被称为“反向 SSH 隧道”,但它是 TCP 端口转发,不是 Nginx、Apache 等 Web 服务器提供的 HTTP 反向代理。
本文重点介绍-L和-R两种常见转发方式;-N、-f和-g是辅助参数。
| 类型 | 第一条件 | 另外还需要 |
|---|---|---|
-L本地端口转发 | 本机能 SSH 连接服务器 | SSH 服务器要能访问最终目标服务 |
-R远程端口转发 | 本机能 SSH 连接服务器 | 本机要能访问最终目标服务 |
| 参数 | 作用 | 常见程度 |
|---|---|---|
-L | 本地端口转发 | ⭐⭐⭐⭐⭐ |
-R | 远程端口转发 | ⭐⭐⭐⭐⭐ |
-N | 只建立隧道,不打开远程 Shell | ⭐⭐⭐⭐⭐ |
-f | 认证成功后转入后台运行 | ⭐⭐⭐⭐ |
-g | 允许其他机器访问本地转发端口 | ⭐⭐ |
-L / -R = 决定“怎么转发” -N = 决定“只做隧道,不登录进去”-L 本地端口转发 ← 最常用 -R 远程端口转发# 本地端口转发 【正向隧道 / 正向 SSH 隧道】 ssh -L 13306:10.0.0.20:3306 devuser@203.0.113.10 ssh -N -L 13306:10.0.0.20:3306 devuser@203.0.113.10 # 远程端口转发 【反向隧道 / Reverse SSH Tunnel】 ssh -R 8002:127.0.0.1:8002 devuser@203.0.113.10 ssh -N -R 8002:127.0.0.1:8002 devuser@203.0.113.10ssh -f -N -o ExitOnForwardFailure=yes -L 13306:10.0.0.20:3306 devuser@203.0.113.10 -f → 后台 -N → 不开 Shell -o ExitOnForwardFailure=yes → 转发建立失败时直接退出 -L → 本地端口转发二、-L本地端口转发
在你的本机打开一个端口,把访问这个本地端口的流量,通过 SSH 隧道转发到远程目标服务。
-L= 本机端口 → SSH 隧道 → 远程目标端口配置成功之后,本地端口只是一个“入口”,真正访问的是 SSH 隧道另一端配置的目标地址和目标端口。
语法:
ssh -L 本地端口:目标主机:目标端口 用户名@SSH服务器例如:
ssh-L13306:10.0.0.20:3306 devuser@203.0.113.102.1 本地端口转发的六种常见用法
下面六种写法建立的都是本地端口转发。其中前三种是基本运行方式,后三种是在后台运行的基础上增加连接检测、多端口转发和配置文件。
以下示例中的转发配置为:
-L 127.0.0.1:17000:127.0.0.1:7000- 第一个
127.0.0.1:17000表示仅在本机回环地址上监听17000端口。 - 第二个
127.0.0.1:7000是从 SSH 服务器的视角访问的目标地址。因此,目标服务需要运行在 SSH 服务器本机的7000端口上。
2.1.1 前台运行并进入远程 Shell
ssh-L127.0.0.1:17000:127.0.0.1:7000 devuser@203.0.113.10这条命令会同时完成两件事:
- 在本机建立
127.0.0.1:17000到远程目标服务的端口转发。 - 登录 SSH 服务器并进入远程 Shell。
在远程 Shell 中执行exit、关闭终端窗口、中断网络或终止 SSH 进程,都会使本地端口转发失效。这种方式适合一边登录服务器操作,一边临时使用端口转发。
2.1.2 前台运行但不进入远程 Shell
ssh-N\-L127.0.0.1:17000:127.0.0.1:7000\devuser@203.0.113.10-N表示不执行远程命令,也不会进入远程 Shell。SSH 进程会在前台持续运行并占用当前终端,按下Ctrl+C即可结束连接和端口转发。
2.1.3 后台运行
ssh-f-N\-L127.0.0.1:17000:127.0.0.1:7000\devuser@203.0.113.10-f会让 SSH 在认证成功后转入后台,-N表示只建立隧道、不进入远程 Shell。命令执行成功后,当前终端可以继续输入其他命令。
如果需要停止这个后台转发,可以先查找对应的 SSH 进程:
psaux|grep'[s]sh.*17000:127.0.0.1:7000'确认进程号后,只结束对应的进程:
killSSH进程PID不建议默认使用范围较宽的pkill -f,因为匹配条件不够精确时,可能同时结束其他 SSH 隧道。
2.1.4 后台运行并增加连接检测
如果希望隧道在后台运行,同时能够及时发现转发建立失败和连接失效,推荐使用下面的写法:
ssh-f-N\-oExitOnForwardFailure=yes\-oServerAliveInterval=30\-oServerAliveCountMax=3\-L127.0.0.1:17000:127.0.0.1:7000\devuser@203.0.113.10新增参数的作用如下:
ExitOnForwardFailure=yes:请求的端口转发无法建立时直接退出,避免在转发失败后仍进入后台。ServerAliveInterval=30:没有收到服务器数据时,每隔 30 秒发送一次 SSH 保活请求。ServerAliveCountMax=3:连续 3 次保活请求没有收到响应,就认为连接已经失效并退出。
可以简单记成:隧道启动失败就退出;启动成功后定期检查连接,连续大约 90 秒没有响应就退出。
短时间断网后,如果网络在超时阈值内恢复,并且原来的 TCP/SSH 连接没有被操作系统、路由器或服务器清除,端口转发通常可以继续使用。但是,这并不是绝对保证。
保活参数只能帮助检测失效连接,不能自动重连。SSH 一旦退出,即使网络随后恢复,端口转发也不会自行重新建立。
如果本机的127.0.0.1:17000已经被其他程序占用,通常会看到类似错误:
bind [127.0.0.1]:17000: Address already in use Could not request local forwarding.由于配置了ExitOnForwardFailure=yes,SSH 会直接退出,而不会留下一个看似已经启动、实际上没有正常转发的后台进程。需要注意,这个参数主要检查转发监听能否建立,不能保证隧道末端的目标服务一定正常运行。
因此,这种写法适合临时或中短期后台运行。后台运行并不等于永久生效;如果需要断线后自动重新建立隧道,还需要使用额外的进程管理或自动重连方案。
多行命令中的反斜杠
\必须是当前行的最后一个字符,后面不要再添加参数或空格。
2.1.5 同时转发多个端口
ssh-f-N\-oExitOnForwardFailure=yes\-oServerAliveInterval=15\-oServerAliveCountMax=3\-oConnectTimeout=10\-L127.0.0.1:17000:127.0.0.1:7000\-L127.0.0.1:13000:127.0.0.1:3000\-L127.0.0.1:21591:127.0.0.1:21591\devuser@203.0.113.10一个 SSH 连接可以配置多个-L,每个-L对应一组本地端口和目标地址。因为已经使用-N,不会执行远程命令,也不会进入远程 Shell,所以通常不需要再添加-T。
上面三个目标地址中的127.0.0.1都是从 SSH 服务器的视角解释的,因此对应服务必须运行在 SSH 服务器本机。如果目标服务在 SSH 服务器能够访问的其他机器上,可以将它改成相应的内网 IP 或主机名。
多个-L都由同一个 SSH 进程维护。结束这个 SSH 进程后,17000、13000和21591三个本地端口转发会同时失效。
可以根据其中一个端口查找对应的 SSH 进程:
psaux|grep'[s]sh.*17000:127.0.0.1:7000'确认进程号后结束该进程:
killSSH进程PID如果只想取消其中一个端口转发,最简单的方法是结束当前 SSH 进程,删除不需要的-L参数,然后重新建立剩余端口的转发。
2.1.6 使用~/.ssh/config简化长期配置
如果经常建立相同的端口转发,可以把连接参数保存到本机的~/.ssh/config:
Host dev-tunnel HostName 203.0.113.10 User devuser ControlMaster yes ControlPath ~/.ssh/control-%n-%C ExitOnForwardFailure yes ServerAliveInterval 30 ServerAliveCountMax 3 LocalForward 127.0.0.1:17000 127.0.0.1:7000 LocalForward 127.0.0.1:21591 127.0.0.1:21591 LocalForward 127.0.0.1:13000 127.0.0.1:3000其中:
ControlMaster yes:让这条 SSH 连接成为可以接收控制命令的主连接。ControlPath ~/.ssh/control-%n-%C:指定本机控制套接字的位置;%n表示命令中使用的原始别名,%C会根据连接信息生成唯一标识。这样可以避免多个隧道别名连接同一台服务器时共用一个控制套接字。
1. 开启全部本地端口转发
ssh-f-Ndev-tunnel2. 检查隧道是否正在运行
ssh\-oControlMaster=no\-oClearAllForwardings=yes\-Ocheck\dev-tunnel如果主连接正在运行,通常会看到:
Master running (pid=12556)-O check只检查状态,不会关闭隧道。
3. 关闭主连接以及它维护的全部本地端口转发
ssh\-oControlMaster=no\-oClearAllForwardings=yes\-Oexit\dev-tunnel关闭成功时通常会看到:
Exit request sent.控制命令中的两个参数很重要:
ControlMaster=no:当前控制套接字无效时直接报错,避免重新建立普通 SSH 连接并进入远程 Shell。ClearAllForwardings=yes:执行控制命令时不再重复申请配置文件中的LocalForward,避免出现本地端口已被占用的错误。
因此,-O check和-O exit的区别是:
| 命令 | 作用 |
|---|---|
-O check | 只检查主连接是否正在运行,不会关闭 |
-O exit | 关闭主连接及其维护的全部端口转发 |
4. 验证端口转发是否已经关闭
lsof-nP-iTCP:17000-sTCP:LISTENlsof-nP-iTCP:21591-sTCP:LISTENlsof-nP-iTCP:13000-sTCP:LISTEN如果命令没有输出,说明对应的本地监听端口已经释放。
5. 控制命令不可用时,通过 PID 检查和关闭
如果没有启用控制连接,或者ssh -O exit无法正常工作,可以查找通过dev-tunnel启动的 SSH 进程:
psaux|grep'[s]sh.*dev-tunnel'[s]sh可以匹配ssh,同时避免把当前的grep命令也显示在结果中。输出中通常可以看到类似内容:
wjg 12556 ... ssh -f -N dev-tunnel确认它确实是需要关闭的隧道进程后,使用对应的 PID 结束它:
kill12556同一个进程维护的全部LocalForward会一起失效。不要直接使用pkill ssh,否则可能同时关闭其他 SSH 登录和隧道。
正常情况下,优先使用ssh -O exit关闭主连接;通过 PID 结束进程可以作为控制连接不可用时的备用方案。
配置文件可以简化命令以及隧道的开启和关闭,但不会让隧道自动启动或自动重连。需要修改转发端口时,直接编辑对应的LocalForward配置即可。
六种常见用法可以归纳为:
| 用法 | 是否进入远程 Shell | 是否占用当前终端 | 适用场景 |
|---|---|---|---|
| 前台运行并进入 Shell | 是 | 是 | 临时转发,同时需要操作服务器 |
| 前台运行但不进入 Shell | 否 | 是 | 临时测试纯隧道 |
| 后台运行 | 否 | 否 | 转发需要在后台持续一段时间 |
| 后台运行并增加连接检测 | 否 | 否 | 希望及时发现连接或转发建立失败 |
| 同时转发多个端口 | 否 | 否 | 通过一个 SSH 连接访问多个服务 |
使用~/.ssh/config配置 | 取决于启动命令 | 取决于启动命令 | 经常重复使用同一组连接和转发参数 |
需要记住:端口转发的生命周期与 SSH 连接一致;SSH 连接结束,端口转发就会失效。
2.2 解决了什么问题:为什么需要跳板机
目标服务只在内网开放,而 SSH 服务器拥有访问权限,因此可以通过加密隧道安全连接。
# 1. 本机无法直接访问目标 MySQL 你的电脑 IP:192.168.1.20 本机 ────── X ──────> 10.0.0.20:3306 无法直接访问 # 2. 但是本机可以 SSH 登录跳板机 你的电脑 192.168.1.20 │ │ SSH ▼ devuser@203.0.113.10 │ │ 可以访问 ▼ 10.0.0.20:3306 # 3. 所以建立 SSH 本地端口转发 ssh -L 13306:10.0.0.20:3306 devuser@203.0.113.10 # 4. 建立成功以后 你的电脑访问: 127.0.0.1:13306 │ │ SSH 隧道 ▼ 203.0.113.10 │ ▼ 10.0.0.20:3306| 场景 | 例子 |
|---|---|
| 访问内网数据库 | MySQL 3306、PostgreSQL 5432 |
| 访问内网 Redis | Redis 6379 |
| 访问内部 Web 服务 | 比如 10.0.0.30:8080 |
| 访问管理后台 | 服务只允许内网访问 |
| 访问 Elasticsearch 等中间件 | 如 9200 |
| 通过跳板机访问内网资源 | 资源仅向跳板机所在网络开放 |
2.3 具体案例
比如一个非常典型的后端场景:
你的电脑 │ │ SSH 隧道 ▼ 跳板机 / Linux 服务器 │ │ 内网访问 ▼ MySQL 10.0.0.20:3306假设 MySQL 不对公网开放,你本机不能直接:
10.0.0.20:3306但是你能 SSH 登录一台服务器:
203.0.113.10那么你可以:
ssh-L13306:10.0.0.20:3306 devuser@203.0.113.10然后你本机访问:
127.0.0.1:13306实际上流量会走:
本机 127.0.0.1:13306 ↓ SSH 加密隧道 ↓ 203.0.113.10 ↓ 10.0.0.20:3306所以你可以先把它记成一句话:
SSH 隧道 = 通过一台拥有目标服务访问权限的 SSH 服务器,建立经过加密保护的连接通道。
在程序员日常工作中,最常见的是访问:
- MySQL / PostgreSQL
- Redis
- Elasticsearch
- 公司内网 Web 服务
- 只允许内网访问的管理后台
- Kubernetes / 开发环境里的服务
如果按重要性学习,可以先掌握-L本地端口转发,它是开发和运维工作中最常见的一种。
三、-R远程端口转发(反向 SSH 隧道)
-R表示Remote Port Forwarding(远程端口转发),也常被称为“反向 SSH 隧道”。
在远程 SSH 服务器上打开一个端口,把访问这个远程端口的流量,通过 SSH 隧道转发到本机能够访问的目标服务。
-R= 远程服务器端口 → SSH 隧道 → 本机一侧的目标端口配置成功之后,远程服务器上的监听端口只是一个“入口”,真正访问的是 SSH 客户端一侧配置的目标地址和目标端口。
关键点:
ssh -R ...命令需要在本机,也就是 SSH 客户端 A 上执行,而不是在公网服务器 B 上执行。本机 A 主动连接公网服务器 B,并通过这条 SSH 连接把服务器 B 上的监听端口转回本机服务。
| 机器 | 作用 | 在哪里执行什么命令 |
|---|---|---|
| 本机 A(SSH 客户端) | 运行目标服务,并主动建立反向隧道 | 启动本地服务,执行ssh -R ... |
| 公网服务器 B(SSH 服务器) | 提供远程监听端口,通过隧道访问本机服务 | 执行curl等命令验证远程监听端口 |
可以把两种方向记成:
-L:本机端口 → SSH 隧道 → 远程目标服务 -R:远程端口 → SSH 隧道 → 本机目标服务二者的区别如下:
| 对比项 | -L本地端口转发 | -R远程端口转发 |
|---|---|---|
| 监听端口所在位置 | 本机 | SSH 服务器 |
| 谁连接监听端口 | 本机程序 | SSH 服务器上的程序 |
| 谁访问最终目标 | SSH 服务器一侧 | SSH 客户端一侧 |
| 常见用途 | 本机访问内网服务 | 远程服务器访问本机服务 |
语法:
ssh -R 远程监听地址:远程端口:目标主机:目标端口 用户名@SSH服务器例如:
ssh-R127.0.0.1:8002:127.0.0.1:8002 devuser@203.0.113.10连接路径如下:
SSH 服务器访问 127.0.0.1:8002 ↓ SSH 加密隧道 ↓ 本机访问 127.0.0.1:8002这里两个127.0.0.1的视角不同:
127.0.0.1:8002表示在 SSH 服务器的回环地址上监听。- 目标
127.0.0.1:8002从 SSH 客户端,也就是本机的视角访问。
因此,本机必须先启动8002端口的服务。目标也可以是本机能够访问的其他内网地址。
3.1 远程端口转发的六种常见用法
3.1.1 前台运行并进入远程 Shell
ssh\-R127.0.0.1:8002:127.0.0.1:8002\devuser@203.0.113.10这条命令会建立反向隧道,同时进入远程服务器的 Shell。在远程 Shell 中执行exit、关闭终端或中断 SSH 连接,远程端口转发都会失效。
3.1.2 前台运行但不进入远程 Shell
ssh-N\-R127.0.0.1:8002:127.0.0.1:8002\devuser@203.0.113.10-N表示不执行远程命令,也不进入远程 Shell。SSH 进程会在前台持续运行,按下Ctrl+C即可关闭反向隧道。
3.1.3 后台运行
ssh-f-N\-R127.0.0.1:8002:127.0.0.1:8002\devuser@203.0.113.10SSH 认证成功后会转入后台运行。需要停止时,可以在本机查找对应的 SSH 进程:
psaux|grep'[s]sh.*8002:127.0.0.1:8002'确认进程号后结束该进程:
killSSH进程PID3.1.4 后台运行并增加连接检测
ssh-f-N\-oExitOnForwardFailure=yes\-oServerAliveInterval=30\-oServerAliveCountMax=3\-R127.0.0.1:8002:127.0.0.1:8002\devuser@203.0.113.10这条命令适合临时或中短期后台运行:
- 远程监听端口无法建立时直接退出。
- 没有收到服务器数据时,每隔 30 秒发送一次 SSH 保活请求。
- 连续 3 次保活请求没有响应时退出。
如果远程服务器的8002端口已经被占用,通常会看到类似错误:
remote port forwarding failed for listen port 8002保活参数只能帮助检测失效连接,不能实现断线自动重连。
3.1.5 同时转发多个远程端口
ssh-f-N\-oExitOnForwardFailure=yes\-oServerAliveInterval=30\-oServerAliveCountMax=3\-R127.0.0.1:8002:127.0.0.1:8002\-R127.0.0.1:8061:127.0.0.1:8061\devuser@203.0.113.10一个 SSH 连接可以配置多个-R:
SSH 服务器 127.0.0.1:8002 → SSH 隧道 → 本机 127.0.0.1:8002 SSH 服务器 127.0.0.1:8061 → SSH 隧道 → 本机 127.0.0.1:8061结束这个 SSH 进程后,它维护的两个远程端口转发都会同时失效。如果只想取消其中一个端口,需要结束当前进程、删除对应的-R,然后重新建立剩余的转发。
3.1.6 使用~/.ssh/config简化长期配置
如果经常建立相同的反向隧道,可以在本机的~/.ssh/config中添加:
Host reverse-tunnel HostName 203.0.113.10 User devuser ControlMaster yes ControlPath ~/.ssh/control-%n-%C ExitOnForwardFailure yes ServerAliveInterval 30 ServerAliveCountMax 3 RemoteForward 127.0.0.1:8002 127.0.0.1:8002 RemoteForward 127.0.0.1:8061 127.0.0.1:8061%n表示命令中使用的原始别名。即使dev-tunnel和reverse-tunnel连接同一台服务器,它们也会使用不同的控制套接字,避免相互冲突。
开启全部远程端口转发:
ssh-f-Nreverse-tunnel检查运行状态:
ssh\-oControlMaster=no\-oClearAllForwardings=yes\-Ocheck\reverse-tunnel关闭主连接以及它维护的全部远程端口转发:
ssh\-oControlMaster=no\-oClearAllForwardings=yes\-Oexit\reverse-tunnel-O check只检查状态,-O exit才会关闭主连接。控制命令中的ControlMaster=no可以避免控制套接字失效时意外建立普通 SSH 连接;ClearAllForwardings=yes可以避免控制命令再次申请配置中的RemoteForward。
3.2 解决了什么问题:为什么需要远程端口转发
远程端口转发主要解决下面的问题:
远程服务器无法主动连接本机,但本机可以主动 SSH 连接远程服务器。
例如,本机 A 运行着127.0.0.1:8002服务,但是本机没有公网 IP,或者位于路由器、NAT 和防火墙之后。公网服务器 B 无法直接连接本机 A:
公网服务器 B │ │ 无法主动连接 X 本机 A:127.0.0.1:8002但是,本机 A 通常可以主动 SSH 连接公网服务器 B:
本机 A │ │ 主动建立 SSH 连接 ▼ 公网服务器 BSSH 连接建立以后,就形成了一条双向的加密通道。-R可以在公网服务器 B 上创建监听入口,再把进入该端口的 TCP 连接送回本机 A 一侧的目标服务。
所以,远程端口转发的核心价值可以概括为:
利用本机主动建立的 SSH 连接,让远程服务器访问本机一侧原本无法直接访问的服务。
3.3 实际验证与常见场景
3.3.1 验证本机的8002服务
假设本机运行着一个正在开发的 Web 应用:
本机开发服务:127.0.0.1:8002 远程测试服务器:203.0.113.10第一步:在本机 A 启动一个临时 HTTP 服务
python3-mhttp.server8002--bind127.0.0.1第二步:在本机 A 的另一个终端中建立远程端口转发
ssh-N\-R127.0.0.1:8002:127.0.0.1:8002\devuser@203.0.113.10第三步:在公网服务器 B 上验证远程监听端口
连接建立后,在公网服务器 B 上执行:
curlhttp://127.0.0.1:8002实际连接路径如下:
远程服务器 127.0.0.1:8002 │ │ SSH 远程端口转发 ▼ 本机 127.0.0.1:8002常见的授权开发场景包括:
- 让远程测试程序临时调用本机开发服务
- 让远程测试服务器上的程序回调本机开发服务
- 在测试环境中演示尚未部署的本机应用
- 排查本机与远程服务之间的连接问题
3.3.2 让远程服务器使用本机代理服务
本机 A 上运行 HTTP 或 SOCKS 代理服务时,常见监听端口之一是127.0.0.1:7890。经过授权后,可以把这个代理端口通过反向隧道提供给公网服务器 B 使用:
ssh-N\-R127.0.0.1:7890:127.0.0.1:7890\devuser@203.0.113.10连接路径如下:
公网服务器 B:127.0.0.1:7890 ↓ SSH 反向隧道 ↓ 本机 A 的代理服务:127.0.0.1:7890如果本机运行的是 HTTP 代理,可以在公网服务器 B 上测试:
curl-xhttp://127.0.0.1:7890 https://example.com如果本机运行的是 SOCKS5 代理,可以使用:
curl--proxysocks5h://127.0.0.1:7890 https://example.com需要注意,SSH-R只负责转发 TCP 连接,真正的代理能力来自本机 A 上已经运行的代理服务。HTTP 和 SOCKS5 是不同的代理协议,应根据本机服务实际支持的协议选择测试命令。
这里将远程监听地址限制为127.0.0.1,因此只有公网服务器 B 本机能够使用该代理。不要随意改成0.0.0.0,否则可能形成未受控的开放代理。该方式只应在自己拥有或明确授权的网络环境中使用。
3.4 使用限制与注意事项
默认情况下,远程转发端口通常只监听远程服务器的回环地址。因此,上面的8002端口只能由远程服务器本机访问,其他机器无法直接连接。
如果确实需要让其他经过授权的机器访问远程转发端口,可以显式指定远程监听地址:
ssh-N\-R0.0.0.0:8002:127.0.0.1:8002\devuser@203.0.113.10这种写法还需要服务器端允许GatewayPorts clientspecified或GatewayPorts yes,并正确配置防火墙和访问权限。它会扩大本机服务的可访问范围,因此不能作为默认推荐写法,只应在自己拥有或明确授权的环境中使用。
另外,服务器端可能通过以下配置限制端口转发:
| 配置项 | 作用 |
|---|---|
AllowTcpForwarding | 控制是否允许 TCP 端口转发 |
PermitOpen | 限制本地端口转发可以连接的目标地址和端口 |
PermitListen | 限制远程端口转发可以监听的地址和端口 |
GatewayPorts | 控制远程转发端口能否监听非回环地址 |
普通用户通常不需要修改这些服务器配置。如果转发被服务器拒绝,应联系服务器管理员确认相关策略。
四、常用参数速查
| 参数或配置 | 作用 |
|---|---|
-L | 建立本地端口转发 |
-R | 建立远程端口转发 |
-N | 不执行远程命令,也不进入远程 Shell |
-f | 认证成功后转入后台运行 |
-T | 不分配伪终端;已经使用-N时通常不必再添加 |
-g | 允许其他机器连接本地转发端口 |
ExitOnForwardFailure=yes | 请求的端口转发无法建立时退出 |
ServerAliveInterval=30 | 无数据返回时,每隔 30 秒发送一次服务器保活请求 |
ServerAliveCountMax=3 | 连续 3 次保活请求没有响应时断开连接 |
ConnectTimeout=10 | 建立 SSH 连接时最多等待 10 秒 |
-fN和-f -N的作用相同。本文采用分开书写的形式,方便初学者逐项理解参数。
-g只影响本地端口转发。默认情况下,本地转发端口通常只供本机访问;添加-g后,其他能够连接本机的设备也可能访问该转发端口。
ssh-g-N-L13306:10.0.0.20:3306 devuser@203.0.113.10这会扩大本地转发端口的可访问范围,因此大多数只供自己使用的开发场景不需要添加-g。如确有需要,应同时确认本机防火墙、所在网络和目标服务的访问权限。
五、常见问题与排查
5.1 使用详细日志检查连接
如果端口转发没有按预期工作,可以添加-v查看 SSH 的连接和转发日志:
ssh-v-N-L13306:10.0.0.20:3306 devuser@203.0.113.105.2 检查端口是否已经被占用
如果本机的13306或远程服务器的8002已经被其他程序监听,SSH 将无法使用同一个端口。可以更换一个未被占用的端口后重新测试。
5.3 检查最终目标是否可达
端口转发建立成功并不代表最终目标一定可以访问:
-L 本地端口转发:SSH 服务器必须能够访问目标服务 -R 远程端口转发:本机必须能够访问目标服务因此,排查时不仅要检查 SSH 是否连接成功,还要检查隧道出口所在的一侧能否连接目标地址和目标端口。
5.4 检查服务器是否允许端口转发
如果日志中出现端口转发被拒绝,应确认服务器是否允许相应类型的转发。服务器可能通过AllowTcpForwarding、PermitOpen、PermitListen或GatewayPorts等配置限制转发行为。
六、总结
| 参数 | 作用 | 使用建议 |
|---|---|---|
-L | 在本机监听端口,并通过 SSH 服务器连接远程目标服务 | 优先掌握,常用于访问服务器所在网络中的服务 |
-R | 在远程服务器监听端口,并通过 SSH 隧道连接本机目标服务 | 适合经过授权的远程测试和临时联调 |
-N | 不执行远程命令,只保留 SSH 连接和端口转发 | 建立纯隧道时推荐使用 |
-f | 认证成功后转入后台运行 | 确认隧道正常后再使用 |
-g | 允许其他机器连接本地转发端口 | 会扩大访问范围,应谨慎使用 |
可以把最核心的方向记成:
-L:本机端口 → SSH 隧道 → 远程目标服务 -R:远程端口 → SSH 隧道 → 本机目标服务个人声明:本文为个人学习笔记,如有错误,欢迎指正。