通过 SSH 端口转发访问开发机内 HTTP 服务
云端的应用或数据库通常仅允许从内网访问。SSH 端口转发通过建立一条加密隧道,让您在本地安全地访问这些服务。
本文介绍如何使用 SSH 本地端口转发 (Local Port Forwarding) 将云端内网服务映射到本地,适用于远程开发、性能测试等场景。
注意
本方案适用于本地或可信网络的临时访问。如果需要向公网用户暴露服务,应使用反向代理或负载均衡器。
适用场景
- 从本地开发机访问云服务器内网的开发服务
- 远程调试或测试部署在云端但未向公网暴露的应用
- 临时访问内网数据库或缓存服务进行性能测试
- 演示云端应用功能给团队或客户
工作原理
SSH 本地端口转发在您的本地计算机与远程 SSH 服务器之间建立一条加密隧道。您在本地开启一个监听端口,所有发往该端口的流量都被通过 SSH 加密后转发到远程服务器,再由远程服务器转发到目标服务。
本地电脑 (localhost:5000)
↓
[SSH 加密隧道]
↓
开发机 (127.0.0.1:8000)注意
反向的使用场景:远程端口转发
本文介绍的是 本地端口转发 (-L),用于将 远程服务 映射到 本地 访问。
相反的场景是 远程端口转发 (-R),用于将 本地服务 暴露给 远程主机 访问。常见用例包括:
- 将本地代理服务(如 Clash、V2Ray)共享给远程开发机使用
- 临时让远程主机访问本地的开发服务或资源
详见 共享本地代理服务至远程主机。
开始前,请确保满足以下条件:
- 可通过 SSH 访问的远程开发机(获取 IP 地址、用户名、SSH 端口)
- 本地电脑已安装 SSH 客户端(macOS 和 Linux 内置;Windows 10+ 已包含)
- 远程开发机上的目标服务已启动并监听特定端口
- 本地电脑与开发机之间网络连通
- (推荐)已配置 SSH 密钥认证,详见 添加 SSH 公钥指南
命令语法
ssh -N -f -L <local-port>:127.0.0.1:<target-port> -p <ssh-port> <username>@<tunnel-host>参数说明
-L:启用本地端口转发(必需)-N:不执行远程命令,仅建立隧道-f:在后台运行 SSH 进程<local-port>:本地监听端口(示例:5000)127.0.0.1:目标地址(开发机本地环回地址)<target-port>:开发机上目标服务的端口(示例:8000)-p <ssh-port>:开发机的 SSH 端口(示例:-p 45560)<username>@<tunnel-host>:开发机的用户名和 IP 地址(示例:root@8.140.242.203)
注意:127.0.0.1 表示开发机本地环回地址,确保转发到本地运行的服务。
快速开始
在开发机上启动目标服务:SSH 登录到开发机后,启动您的目标服务。确保服务监听在本地地址(
127.0.0.1)的某个端口上。示例:启动 Python HTTP 服务器
bashssh -p <ssh-port> <username>@<tunnel-host> # 在开发机上执行: python3 -m http.server 8000 --bind 127.0.0.1在开发机上验证服务是否正常运行:
bashcurl http://127.0.0.1:8000建立 SSH 端口转发隧道:在本地电脑打开新的终端,执行以下命令建立端口转发。将占位符替换为实际值。
bashssh -N -f -L <local-port>:127.0.0.1:<target-port> -p <ssh-port> <username>@<tunnel-host>完整示例
假设您的开发机信息如下:
- IP 地址:
8.140.242.203 - SSH 用户名:
root - SSH 端口:
45560 - 服务端口:
8000 - 本地转发端口:
5000
执行命令:
bashssh -N -f -L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203如果提示输入密码,请输入开发机的 SSH 密码。命令执行后,隧道在后台运行,无需额外输出。
- IP 地址:
在本地电脑上测试转发是否成功
返回本地电脑(不是开发机),进行以下测试:
方法 A:使用浏览器
在本地电脑上打开浏览器,访问:
http://localhost:5000您应该看到与
http://127.0.0.1:8000相同的内容。方法 B:使用 curl(推荐)
在本地电脑的终端运行:
bashcurl http://localhost:5000如果返回了服务的响应,说明隧道建立成功。
注意
访问
localhost:<local-port>时,流量经过 SSH 加密隧道转发到开发机的目标服务。所有通信都受到 SSH 加密保护。
关闭端口转发
建立的端口转发在后台运行,使用完毕需要手动关闭,以释放端口和网络资源。
查找转发进程
ps aux | grep "ssh -N -f -L"输出示例:
user 1234 0.0 0.0 42532 784 ? Ss 10:00 0:00 ssh -N -f -L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203
user 5678 0.0 0.0 12345 678 ? S+ 10:30 0:00 grep ssh -N -f -L第一行是您创建的 SSH 转发进程,第二列的数字(如 1234)是进程 ID。
终止转发
kill <PID>以上面的例子为例:
kill 1234验证关闭
再次运行查找命令确认进程已终止:
ps aux | grep "ssh -N -f -L"如果只显示 grep 进程本身,说明转发已成功关闭。此时访问 http://localhost:5000 将返回连接错误。
多服务同时转发
如果需要同时转发多个服务,可在一条命令中指定多个 -L 参数:
# 同时转发三个服务
ssh -N -f \
-L 5000:127.0.0.1:8000 \ # Web 应用
-L 5001:127.0.0.1:3306 \ # MySQL 数据库
-L 5002:127.0.0.1:5432 \ # PostgreSQL 数据库
-p 45560 root@8.140.242.203本地访问方式:
curl http://localhost:5000 # 访问 Web 应用
mysql -h 127.0.0.1 -P 5001 -u root # 连接 MySQL
psql -h 127.0.0.1 -p 5002 -U user # 连接 PostgreSQL提示
选择本地端口时,避免使用常见端口(如 3306、5432),防止与本地已安装的同类服务冲突。
使用 SSH 配置文件简化命令
为避免每次都输入完整的 IP、用户名、端口和密钥路径,可以通过 SSH 配置文件实现快速转发。
在配置文件中预配置转发(推荐用于固定转发)
编辑 ~/.ssh/config 文件,使用 LocalForward 指令直接配置端口转发:
Host dev-server
HostName 8.140.242.203
User root
Port 45560
IdentityFile ~/.ssh/id_rsa
LocalForward 5000 127.0.0.1:8000
ServerAliveInterval 30
ServerAliveCountMax 3配置后,只需简单连接即可自动建立转发:
ssh -N -f dev-server优势:
- 无需每次都输入完整的转发参数
- 配置集中管理,便于维护
- 支持配置多个
LocalForward行来转发多个服务
使用 autossh 自动重连
对于长期运行的转发,网络中断会导致隧道断开。autossh 工具可以自动检测和重连,无需手动干预。
安装 autossh
# macOS
brew install autossh
# Ubuntu/Debian
sudo apt-get install autossh
# CentOS/RHEL
sudo yum install autossh使用 autossh
# 基本用法:将 ssh 替换为 autossh
autossh -M 5555 -N -f -L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203参数说明:
-M 5555:监控端口(autossh 用来检测连接健康状态)- 其他参数与 SSH 相同
与 SSH 配置结合
如果 SSH 配置文件中已定义了 LocalForward,可使用 autossh 进行自动重连:
autossh -M 5555 -N -f dev-server故障排除
遇到连接问题时,可按照下列流程逐步排查,快速定位问题根源。
故障诊断流程图
是否看到错误消息?
├─ "Permission denied" → [步骤 1:验证认证]
├─ "Connection refused" → [步骤 2:验证远程服务]
├─ "Address already in use" → [步骤 3:检查本地端口]
├─ 无错误但无法访问 → [步骤 4:检查防火墙]
└─ 隧道间歇性断连 → [步骤 5:配置保活]步骤 1:验证 SSH 认证(Permission denied)
错误信息:
Permission denied (publickey,password).原因:用户名、密码或 SSH 密钥错误。
诊断和解决:
# 测试能否直接 SSH 登录
ssh -p <ssh-port> <username>@<tunnel-host>
# 如果使用密钥,确认密钥存在且权限正确
ls -la ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# 明确指定密钥进行转发
ssh -i ~/.ssh/id_rsa -N -f -L <local-port>:127.0.0.1:<target-port> -p <ssh-port> <username>@<tunnel-host>步骤 2:验证远程服务(Connection refused)
错误信息:
connect_to localhost port 8000: Connection refused原因:开发机上的目标服务未启动或端口号错误。
诊断和解决:
# 登录开发机查看服务是否运行
ssh -p <ssh-port> <username>@<tunnel-host>
# 在开发机上验证服务是否监听指定端口
curl http://127.0.0.1:8000
# 查看所有监听的端口
netstat -tulpn | grep LISTEN
# 或
ss -tulpn | grep LISTEN步骤 3:检查本地端口(Address already in use)
错误信息:
bind: Address already in use原因:本地选择的端口已被其他进程占用。
诊断和解决:
# 查看哪个进程占用了该端口
lsof -i :5000
# 或
netstat -tulpn | grep 5000
# 选择未被占用的端口重试
ssh -N -f -L 5001:127.0.0.1:8000 -p 45560 root@8.140.242.203
# 或关闭占用该端口的进程
kill $(lsof -ti:5000)步骤 4:检查防火墙和网络
症状:命令执行无错误,但无法从本地访问服务。
诊断:
# 验证隧道是否建立成功
ps aux | grep "ssh.*-L" | grep -v grep
# 验证本地端口是否在监听
lsof -i :5000
netstat -tulpn | grep 5000
# 尝试本地连接(在开发机上)
curl http://localhost:5000可能原因:
- 本地防火墙阻止了连接
- 云服务商网络策略限制了出站 SSH
- SSH 隧道建立但目标服务无响应
解决方案:
- 检查本地防火墙设置
- 检查云服务商的安全组/防火墙规则
- 在开发机上观察网络日志
# 在开发机上实时监听 SSH 连接日志
sudo tail -f /var/log/auth.log | grep sshd步骤 5:隧道间歇性断连
症状:转发工作一段时间后自动断开连接。
原因:
- 网络路由器/防火墙空闲连接超时
- SSH 默认心跳检测间隔过长
解决方案:
# 方案 A:配置 SSH 心跳检测
ssh -N -f -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
-L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203
# 参数说明:
# ServerAliveInterval=30 : 每 30 秒发送一次心跳
# ServerAliveCountMax=3 : 3 次心跳无响应后断开
# 方案 B:使用 autossh 自动重连(推荐用于长期运行)
autossh -M 5555 -N -f -o ServerAliveInterval=30 \
-L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203忘记隧道是否仍在运行
# 快速检查特定端口的转发
lsof -ti:5000
# 如果有输出(进程 ID),说明转发仍在运行
# 如果无输出,说明转发已断开最佳实践
以下建议可以帮助您更安全、更高效地使用 SSH 端口转发。
安全建议
- SSH 端口转发使用加密隧道,比直接暴露服务更安全
- 使用 SSH 密钥而非密码进行认证(更强的安全性)
- 不在互联网上直接暴露开发机的 SSH 端口,仅从可信网络访问
- 使用完毕后及时关闭转发隧道
- 使用
-g标志暴露到网络时,需确保防火墙和网络环境可信
使用建议
- 为常用的转发配置创建别名 (alias),简化后续操作bash
alias tunnel-dev='ssh -N -f -L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203' - 同时转发多个服务时,使用不同的本地端口
- 记录下使用的端口映射,避免混淆
- 选择本地端口时,避免常见端口(如 3306、5432)与本地服务冲突
自动化建议
对于长期运行的转发,可考虑:
- 使用
autossh自动检测并重连中断的隧道 - 配置 SSH 配置文件 (
~/.ssh/config) 简化命令输入 - 通过
ServerAliveInterval和ServerAliveCountMax配置心跳保活 - 通过 systemd 或 launchd 将转发配置为系统服务(高级用法)