你在本機電腦啟動了一個尚未部署的 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 轉送、目標呼叫」三個層次,避免同時修改防火牆、應用程式設定與專案程式碼。
來源服務層
在開發電腦執行 curl 與 lsof。如果 API 只監聽 IPv6 的 ::1,但轉送目標填寫的是 127.0.0.1,連線就會遭到拒絕。此時應統一監聽協定,或將轉送目標改成實際位址。另外也要確認本機 Proxy 沒有接管回送流量,可暫時使用:
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,該連接埠便只能由雲端 Mac 本機存取。應避免使用 0.0.0.0,並以 lsof 核對實際監聽結果。
SSH 已連線,但雲端 Mac 仍無法存取映射連接埠怎麼辦?
先確認開發電腦上的來源服務正確監聽,再到雲端 Mac 使用 lsof 檢查目標連接埠。常見原因是連接埠衝突,或 SSH 伺服端禁止 TCP 轉送。
從 Xcode 執行的 App 可以直接使用通道位址嗎?
雲端 Mac 上的建置腳本可直接使用 127.0.0.1 與映射連接埠。模擬器或 App 還需要依其網路範圍及專案的 HTTP 安全規則個別驗證。
MiniD 雲端 Mac
按日、週或月租用獨享實體 Mac mini
整機獨享的實體 Mac mini,可透過遠端桌面與 SSH 連線;實際機型、區域與租期以訂購頁目前資訊為準。