Engineering note

云端 Mac 如何通过 SSH 反向隧道联调本地 API

远程 Mac ·约 7 分钟阅读

云端 Mac 如何通过 SSH 反向隧道联调本地 API

你在本地电脑启动了一个尚未部署的 API,Xcode 项目和构建脚本却运行在云端 Mac。直接开放路由器端口既慢又扩大攻击面,把代码仓库中的地址临时改成公网域名也容易污染配置。更稳妥的做法是让开发电脑主动建立 SSH 连接,通过反向隧道把本地端口映射到云端 Mac 的回环地址。

先确认流量方向

反向隧道解决的是“云端访问本地”。假设 API 在开发电脑的 127.0.0.1:8080 上运行,希望云端 Mac 通过 127.0.0.1:18080 调用它。SSH 连接由开发电脑发起,进入云端 Mac,再把云端收到的流量带回本地端口。

正向转发则相反:开发电脑需要访问云端 Mac 上仅监听回环地址的调试服务。例如云端服务位于 127.0.0.1:9000,可映射为开发电脑的 127.0.0.1:19000

目标 SSH 参数 发起连接的位置 访问入口
云端 Mac 访问本地 API -R 开发电脑 云端 127.0.0.1:18080
本地访问云端调试服务 -L 开发电脑 本地 127.0.0.1:19000

先用真实客户端确认源服务可用,不要一开始就排查隧道:

curl -i http://127.0.0.1:8080/health
lsof -nP -iTCP:8080 -sTCP:LISTEN

如果应用没有健康检查路径,也可临时运行一个只监听本机的测试服务:

python3 -m http.server 8080 --bind 127.0.0.1

建立最小暴露的反向隧道

在开发电脑设置云端地址后执行:

export CLOUD_MAC_IP="你的节点地址"
ssh -N \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=30 \
  -o ServerAliveCountMax=3 \
  -R 127.0.0.1:18080:127.0.0.1:8080 \
  dev@"$CLOUD_MAC_IP"

-N 表示不执行远端命令,连接只负责转发。ExitOnForwardFailure 可避免端口绑定失败后仍留下一个看似正常的 SSH 会话。两个保活参数用于识别失效连接,并不保证网络中断后自动重建隧道。

在云端 Mac 打开另一个终端验证:

lsof -nP -iTCP:18080 -sTCP:LISTEN
curl -i http://127.0.0.1:18080/health

检查 lsof 输出时,监听地址应是 127.0.0.1:18080,而不是 *:18080。应用配置也应把联调地址放进开发环境变量,不要写死在源码中:

export DEV_API_BASE_URL="http://127.0.0.1:18080"
xcodebuild -scheme DemoApp -configuration Debug test

隧道只加密传输并限制入口,不会替代 API 自身的认证。即使端口仅在回环地址监听,也应保留测试令牌、权限校验和脱敏日志。

用 SSH 配置减少误操作

反复输入长命令容易把本地端口、远端端口和目标地址写反。可在开发电脑的 ~/.ssh/config 中建立专用条目:

Host minid-api-tunnel
    HostName CLOUD_MAC_IP
    User dev
    RemoteForward 127.0.0.1:18080 127.0.0.1:8080
    ExitOnForwardFailure yes
    ServerAliveInterval 30
    ServerAliveCountMax 3

CLOUD_MAC_IP 替换为实际节点地址,并确保配置文件权限正确:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/config
ssh -N minid-api-tunnel

同一条目不要同时承载大量无关转发。一个项目一个别名,端口按用途分段,例如 API 使用 18080,调试面板使用 19000。这样看到监听端口时就能反推出所属项目,也能降低多人共用节点时发生冲突的概率。

需要从本地访问云端服务时,单独创建正向转发:

ssh -N \
  -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:19000:127.0.0.1:9000 \
  dev@"$CLOUD_MAC_IP"

随后只在开发电脑访问 http://127.0.0.1:19000。两种转发都不需要让业务服务监听公网网卡。

按层排查连接失败

隧道问题应按“源服务、SSH 转发、目标调用”三层检查,避免同时修改防火墙、应用配置和项目代码。

源服务层

在开发电脑执行 curllsof。如果 API 只监听 IPv6 的 ::1,而转发目标写的是 127.0.0.1,连接会被拒绝。应统一监听协议或把转发目标改为实际地址。还要确认本地代理没有接管回环流量,可临时使用:

curl --noproxy '*' -i http://127.0.0.1:8080/health

SSH 转发层

增加详细输出查看端口申请结果:

ssh -vv -N \
  -o ExitOnForwardFailure=yes \
  -R 127.0.0.1:18080:127.0.0.1:8080 \
  dev@"$CLOUD_MAC_IP"

若提示远端端口转发失败,先换一个未占用端口。仍然失败时,再确认云端 SSH 服务是否允许 TCP 转发。不要为了省事修改为公网监听,也不要直接放宽所有来源。

目标调用层

云端终端能够 curl 成功,不代表所有运行目标都会自动继承同一网络条件。构建脚本、图形应用与模拟器可能读取不同的环境配置;HTTP 请求还可能受到项目安全策略影响。应分别记录调用进程、目标 URL、返回码和超时时间,再判断是网络问题还是应用层拒绝。

上线前检查与收尾

联调完成后,先停止依赖隧道的测试任务,再退出 SSH 会话。用 lsof 确认映射端口已经消失,并删除项目中的临时地址、测试令牌和调试日志。

提交代码前至少检查以下项目:

  • API 仍只监听开发电脑的回环地址。
  • 云端映射端口只监听 127.0.0.1
  • SSH 私钥权限为 600,配置目录权限为 700
  • 项目通过环境变量选择联调地址,发布配置未引用该端口。
  • 日志没有请求令牌、密钥、完整用户数据和认证头。
  • 多人共用项目时,端口编号、负责人和结束时间已有记录。

这种方案适合临时 API、回调验证和远程构建联调。若服务需要长期被多个节点调用,应改用具备独立认证、访问控制和审计记录的正式部署,而不是把临时隧道当成生产入口。

常见问题

SSH 反向隧道会把本地 API 暴露到公网吗?

按文中的写法将远端监听地址固定为 127.0.0.1,API 只允许云端 Mac 本机访问,不会直接监听公网网卡。仍应检查实际监听地址,并避免使用 0.0.0.0。

隧道已经建立,但云端 Mac 访问端口仍然失败怎么办?

先在开发电脑确认源服务监听 127.0.0.1 和正确端口,再用 lsof 检查云端端口是否存在监听。如果 SSH 返回转发失败,通常是端口被占用或服务端禁止 TCP 转发。

Xcode 中的应用可以直接使用隧道地址吗?

构建脚本和运行在云端 Mac 上的工具可直接访问 127.0.0.1:映射端口。模拟器或应用进程还要结合其网络命名空间、HTTP 安全策略和项目环境配置单独验证。

MiniD Cloud Mac

按天、周或月租用独享物理 Mac mini

整机独享的物理 Mac mini,远程桌面与 SSH 均可接入;具体机型、区域与租期以订购页当前信息为准。

查看订购选项