在 AIStudio 镜像中心使用 Dockerfile 自助构建最新版 vLLM 镜像在 AIStudio 镜像中心使用 Dockerfile 自助构建最新版 vLLM 镜像 ,无需访问 DockerHub立即构建
Skip to content
回到全部文章

通过 SSH 端口转发访问开发机内 HTTP 服务

云端的应用或数据库通常仅允许从内网访问。SSH 端口转发通过建立一条加密隧道,让您在本地安全地访问这些服务。

本文介绍如何使用 SSH 本地端口转发 (Local Port Forwarding) 将云端内网服务映射到本地,适用于远程开发、性能测试等场景。

注意

本方案适用于本地或可信网络的临时访问。如果需要向公网用户暴露服务,应使用反向代理或负载均衡器。

适用场景

  • 从本地开发机访问云服务器内网的开发服务
  • 远程调试或测试部署在云端但未向公网暴露的应用
  • 临时访问内网数据库或缓存服务进行性能测试
  • 演示云端应用功能给团队或客户

工作原理

SSH 本地端口转发在您的本地计算机与远程 SSH 服务器之间建立一条加密隧道。您在本地开启一个监听端口,所有发往该端口的流量都被通过 SSH 加密后转发到远程服务器,再由远程服务器转发到目标服务。

本地电脑 (localhost:5000)

   [SSH 加密隧道]

开发机 (127.0.0.1:8000)

提示

不仅限于 HTTP 协议

SSH 端口转发支持任何基于 TCP 的协议,包括 MySQL、PostgreSQL、远程桌面等。例如,参考 配置 SSH 端口转发 TCP 服务

注意

反向的使用场景:远程端口转发

本文介绍的是 本地端口转发 (-L),用于将 远程服务 映射到 本地 访问。

相反的场景是 远程端口转发 (-R),用于将 本地服务 暴露给 远程主机 访问。常见用例包括:

  • 将本地代理服务(如 Clash、V2Ray)共享给远程开发机使用
  • 临时让远程主机访问本地的开发服务或资源

详见 共享本地代理服务至远程主机

开始前,请确保满足以下条件:

  • 可通过 SSH 访问的远程开发机(获取 IP 地址、用户名、SSH 端口)
  • 本地电脑已安装 SSH 客户端(macOS 和 Linux 内置;Windows 10+ 已包含)
  • 远程开发机上的目标服务已启动并监听特定端口
  • 本地电脑与开发机之间网络连通
  • (推荐)已配置 SSH 密钥认证,详见 添加 SSH 公钥指南

命令语法

bash
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 表示开发机本地环回地址,确保转发到本地运行的服务。

快速开始

  1. 在开发机上启动目标服务:SSH 登录到开发机后,启动您的目标服务。确保服务监听在本地地址(127.0.0.1)的某个端口上。

    示例:启动 Python HTTP 服务器

    bash
    ssh -p <ssh-port> <username>@<tunnel-host>
    # 在开发机上执行:
    python3 -m http.server 8000 --bind 127.0.0.1
  2. 在开发机上验证服务是否正常运行:

    bash
    curl http://127.0.0.1:8000
  3. 建立 SSH 端口转发隧道:在本地电脑打开新的终端,执行以下命令建立端口转发。将占位符替换为实际值。

    bash
    ssh -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

    执行命令:

    bash
    ssh -N -f -L 5000:127.0.0.1:8000 -p 45560 root@8.140.242.203

    如果提示输入密码,请输入开发机的 SSH 密码。命令执行后,隧道在后台运行,无需额外输出。

  4. 在本地电脑上测试转发是否成功

    返回本地电脑(不是开发机),进行以下测试:

    方法 A:使用浏览器

    在本地电脑上打开浏览器,访问:

    http://localhost:5000

    您应该看到与 http://127.0.0.1:8000 相同的内容。

    方法 B:使用 curl(推荐)

    在本地电脑的终端运行:

    bash
    curl http://localhost:5000

    如果返回了服务的响应,说明隧道建立成功。

    注意

    访问 localhost:<local-port> 时,流量经过 SSH 加密隧道转发到开发机的目标服务。所有通信都受到 SSH 加密保护。

关闭端口转发

建立的端口转发在后台运行,使用完毕需要手动关闭,以释放端口和网络资源。

查找转发进程

bash
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。

终止转发

bash
kill <PID>

以上面的例子为例:

bash
kill 1234

验证关闭

再次运行查找命令确认进程已终止:

bash
ps aux | grep "ssh -N -f -L"

如果只显示 grep 进程本身,说明转发已成功关闭。此时访问 http://localhost:5000 将返回连接错误。

多服务同时转发

如果需要同时转发多个服务,可在一条命令中指定多个 -L 参数:

bash
# 同时转发三个服务
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

本地访问方式:

bash
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 指令直接配置端口转发:

bash
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

配置后,只需简单连接即可自动建立转发:

bash
ssh -N -f dev-server

优势

  • 无需每次都输入完整的转发参数
  • 配置集中管理,便于维护
  • 支持配置多个 LocalForward 行来转发多个服务

使用 autossh 自动重连

对于长期运行的转发,网络中断会导致隧道断开。autossh 工具可以自动检测和重连,无需手动干预。

安装 autossh

bash
# macOS
brew install autossh

# Ubuntu/Debian
sudo apt-get install autossh

# CentOS/RHEL
sudo yum install autossh

使用 autossh

bash
# 基本用法:将 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 进行自动重连:

bash
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 密钥错误。

诊断和解决

bash
# 测试能否直接 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

原因:开发机上的目标服务未启动或端口号错误。

诊断和解决

bash
# 登录开发机查看服务是否运行
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

原因:本地选择的端口已被其他进程占用。

诊断和解决

bash
# 查看哪个进程占用了该端口
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:检查防火墙和网络

症状:命令执行无错误,但无法从本地访问服务。

诊断

bash
# 验证隧道是否建立成功
ps aux | grep "ssh.*-L" | grep -v grep

# 验证本地端口是否在监听
lsof -i :5000
netstat -tulpn | grep 5000

# 尝试本地连接(在开发机上)
curl http://localhost:5000

可能原因

  • 本地防火墙阻止了连接
  • 云服务商网络策略限制了出站 SSH
  • SSH 隧道建立但目标服务无响应

解决方案

  • 检查本地防火墙设置
  • 检查云服务商的安全组/防火墙规则
  • 在开发机上观察网络日志
bash
# 在开发机上实时监听 SSH 连接日志
sudo tail -f /var/log/auth.log | grep sshd

步骤 5:隧道间歇性断连

症状:转发工作一段时间后自动断开连接。

原因

  • 网络路由器/防火墙空闲连接超时
  • SSH 默认心跳检测间隔过长

解决方案

bash
# 方案 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

忘记隧道是否仍在运行

bash
# 快速检查特定端口的转发
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) 简化命令输入
  • 通过 ServerAliveIntervalServerAliveCountMax 配置心跳保活
  • 通过 systemd 或 launchd 将转发配置为系统服务(高级用法)

相关参考

找不到想要的答案?
让 AI 助手为您解答