﻿# 如何使用 OpenSSH 手動打造類似 ngrok 或 serveo 等反向 TCP 通道服務

今天是台北《[ASP.NET Core 3 開發實戰：從入門到進階](https://www.accupass.com/event/1910160917451402730513)》課程最後一天，今天的教學內容包含了 SignalR 聊天室應用程式實作，我在解說完開發過程後，原本想透過 [serveo.net](http://serveo.net/) 線上服務，讓我正在本機跑的 SignalR 網站可以讓全班同學一起連上來壓力測試，結果該網站因為近期被有心人士濫用，導致關站數日，所以就暫時沒辦法使用。晚上回家後，特別研究了一下 OpenSSH 的反向 TCP 通道功能，發現這已經非常夠用，特別撰文紀錄設定的心得。

### 調整遠端 sshd 設定

雖然你的 `ssh` 可以透過 `-R` 參數建立反向通道，但是預設遠端主機只能建立監聽 localhost 本地網路介面，你必須特別開啟 `GatewayPorts` 特性，才能讓遠端主機也能在所有網路介面監聽所有 TCP 通訊埠。

以下是調整設定的方式：

1.  編輯 `/etc/ssh/sshd_config` 檔案
    
    ```bash
    sudo vi /etc/ssh/sshd_config
    ```
    
    找到 `GatewayPorts` 設定，預設該設定為**註解**狀態，請**取消註解**，並將值設定為 `yes`
    
    ```bash
    GatewayPorts yes
    ```
    
2.  重新載入 `/etc/ssh/sshd_config` 設定
    
    ```bash
    sudo /etc/init.d/ssh reload
    ```
    

### 建立一條反向 SSH 通道

接著，你可以透過 `ssh` 命令快速建立一個或多個反向 TCP 通道。

1.  建立一個反向 TCP 通道
    
    ```bash
    REMOTE_PORT=8080
    LOCAL_PORT=5000
    ssh -M -S /tmp/ssh_master -f -N -T -R $REMOTE_PORT:*:$LOCAL_PORT myubuntuserver
    ```
    
    參數說明：
    
    -   `-M` 讓 `ssh` 建立 "[master](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing)" 模式
    -   `-S` 讓 `ssh` 在建立 "master" 模式之後，順便建立一個 control socket 檔案！
    -   `-f` 讓 `ssh` 在開始執行之前，就將該程序放入到背景執行
    -   `-N` 讓 `ssh` 不要在遠端主機執行命令，通常建立 SSH 通道時會使用這個參數
    -   `-T` 讓 `ssh` 停用**虛擬終端機**建立
    -   `-R` 讓 `ssh` 建立一個**反向 TCP 通道**(Reverse TCP channel)
2.  關閉已建立的反向 TCP 通道
    
    以下命令可以透過 `-S` 指定 control socket 檔案，並透過 `-O exit` 直接設定該 "master" 連線關閉通道！
    
    ```bash
    ssh -S /tmp/ssh_master -O exit myubuntuserver
    ```
    
3.  使用 "master" 連線來連接到遠端伺服器
    
    你在建立 "master" 模式之後，可以透過 `-S` 所建立的 control socket 檔案，快速建立一條**新的連線**到同一台伺服器
    
    ```bash
    ssh -S /tmp/ssh_master myubuntuserver
    ```
    
4.  使用 "master" 連線來建立更多的反向 TCP 通道
    
    你可以在建立 "master" 模式之後，可以透過 `-S` 所建立的 control socket 檔案來建立更多通道。
    
    ```bash
    ssh -S /tmp/ssh_master -f -N -T -R 8080:*:8080 -R 5002:*:5002 myubuntuserver
    ```
    
    > 注意：要共用同一條 "**master mode**" 所建立的 SSH 連線，第二次執行不能再用 `-M` 參數！
    
5.  檢查 "**master**" 連線是否還開啟
    
    ```bash
    ssh -S /tmp/ssh_master -O check myubuntuserver
    ```
    

### 維持 SSH 連線不中斷

有時候建立通道時，我們希望確保通道可以隨時保持暢通，這時你可以考慮安裝 `autossh` 套件，這個套件可以確保 SSH 連線在中斷連接之後會自動重連！

1.  安裝 `autossh` 套件
    
    ```bash
    sudo apt install autossh -y
    ```
    
2.  修改現有的 `ssh` 命令，直接改成 `autossh` 即可
    
    ```bash
    REMOTE_PORT=4200
    LOCAL_PORT=4200
    autossh -M -S /tmp/ssh_master -f -N -T -R $REMOTE_PORT:*:$LOCAL_PORT myubuntuserver
    ```
    

### 相關連結

-   [OpenSSH/Cookbook/Multiplexing - Wikibooks, open books for an open world](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing)
-   [通過 ControlMaster 對 OpenSSH 進行加速，減少系統資源消耗](https://www.ibm.com/developerworks/community/blogs/IBMzOS/entry/20150502?lang=en)
-   [networking - How does reverse SSH tunneling work? - Unix & Linux Stack Exchange](https://unix.stackexchange.com/a/118650/288400)
-   [Poor man's ngrok with tcp proxy and ssh reverse tunnel - DEV Community](https://dev.to/k4ml/poor-man-ngrok-with-tcp-proxy-and-ssh-reverse-tunnel-1fm)
