使用 OpenSSH 替沒有固定 IP 的本地主機 (WSL2) 建立反向 TCP 遠端通道 (Ngrok 免費替代)

使用 OpenSSH 替沒有固定 IP 的本地主機 (WSL2) 建立反向 TCP 遠端通道 (Ngrok 免費替代)

目錄

若我們希望將本地主機的服務,例如 ssh 伺服器供外部連線,但我們又沒有固定 IP 時,我們可以使用 OpenSSH 建立反向 TCP 遠端通道,讓外部主機可以透過這個通道連線到我們的本地主機。

其實本質上還是透過一個具有固定 IP 的中間主機,將外部主機的請求轉發到本地主機,這個中間主機可以是我們自己的伺服器,也可以是一些提供這種服務的雲端主機,例如 Google CloudAWS 等等。

假設我們使用 Google 雲端主機作為交換的通道,大致上的流程會是:

sequenceDiagram
    participant A as 電腦A (內網Linux主機)
    participant B as 電腦B (Google雲端主機)
    participant C as 電腦C (任意外部電腦)

    A->>+B: 建立反向通道到電腦B
    Note over A,B: 電腦A透過反向通道與電腦B保持連線

    C->>+B: 連線到電腦B
    B->>+A: 透過反向通道轉發請求給電腦A
    A-->>-B: 回應請求
    B-->>-C: 轉發回應給電腦C

在 Google 雲端主機上建立反向通道

首先,我們需要在 Google 雲端主機上建立一個 OpenSSH 伺服器,並且允許 GatewayPorts 選項。

# 安裝 OpenSSH 伺服器
sudo apt update && sudo apt install -y openssh-server
# 編輯 sshd_config
# 將 ListenAddress 設定為 0.0.0.0
# 將 GatewayPorts 設定為 yes
sudo vim /etc/ssh/sshd_config
# 重啟 OpenSSH 伺服器
sudo systemctl restart sshd
# 確認 OpenSSH 伺服器是否啟動
sudo systemctl status sshd

在本地主機上建立反向通道

接著,我們需要在本地主機上建立一個反向通道,將本地主機的 22 port 與 Google 雲端主機的 2222 port 進行映射。

# 安裝 OpenSSH 伺服器
sudo apt update && sudo apt install -y openssh-server
# 編輯 sshd_config 並將 GatewayPorts 設定為 yes
# 如果要讓遠端主機可以使用密碼登入,則將 PasswordAuthentication 設定為 yes
sudo vim /etc/ssh/sshd_config
# 啟動 OpenSSH 伺服器
sudo systemctl start ssh

# 啟用 OpenSSH 服務
sudo systemctl enable ssh

# 重新載入 sshd_config
sudo /etc/init.d/ssh reload

# 查看 OpenSSH 服務狀態
sudo systemctl status ssh

產生 ssh public key 並複製到 Google 雲端主機:

# 產生 ssh key
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 複製 ssh public key 到 Google 雲端主機
ssh-copy-id -i ~/.ssh/id_rsa.pub <Google Cloud User>@<Google Cloud IP>

將遠端主機的連線資訊寫入 ~/.ssh/config 檔案中:

Host google-cloud
    HostName <Google Cloud IP>
    Port 22
    User <Google Cloud User>
    IdentityFile ~/.ssh/id_rsa
    ServerAliveInterval 60 # 每 60 秒發送一次心跳
    ServerAliveCountMax 3 # 最多發送 3 次心跳

建立反向通道:

# 在本地主機上建立反向通道
REMOTE_PORT=2222
LOCAL_PORT=22
ssh -M -S /tmp/ssh_master -f -N -T -R $REMOTE_PORT:localhost:$LOCAL_PORT google-cloud
  • -Mssh 建立 “master” 模式
  • -Sssh 在建立 “master” 模式之後,順便建立一個 control socket 檔案以利後續停止或添加新的通道
  • -fssh 在開始執行之前,就將該程序放入到背景執行
  • -Nssh 不要在遠端主機執行命令,通常建立 SSH 通道時會使用這個參數
  • -Tssh 停用虛擬終端機建立
  • -Rssh 建立一個反向 TCP 通道(Reverse TCP channel)
# 關閉反向通道
ssh -S /tmp/ssh_master -O exit google-cloud

測試反向通道

在 Google 雲端主機上,使用 ssh 連線到本地主機:

ssh user@localhost -p 2222

確認 port 2222 是否允許外部連線:

sudo ss -tuln | grep 2222
# 預期輸出:
# tcp   LISTEN 0      128          0.0.0.0:2222        0.0.0.0:*
# tcp   LISTEN 0      128             [::]:2222           [::]:*

使用 autossh 保持反向通道連線並在開機後自動啟動

由於 ssh 通道可能會因為網路問題或其他原因而中斷,我們可以使用 autossh 來保持通道連線。 並且使用 systemd 服務來在開機後自動啟動 autossh

# 安裝 autossh
sudo apt update && sudo apt install -y autossh

# 建立 systemd 服務
sudo vim /etc/systemd/system/create_reverse_tunnel.service
[Unit]
Description=Create reverse tunnel to Google Cloud
After=network-online.target ssh.service

[Service]
User=<user> # 誰執行這個服務
ExecStart=/usr/bin/autossh -M 0 -N -T -R 2222:localhost:22 google-cloud
Restart=always
RestartSec=20
Environment="AUTOSSH_GATETIME=0"

[Install]
WantedBy=multi-user.target
# 啟動 systemd 服務
sudo systemctl start create_reverse_tunnel

# 啟用 systemd 服務
sudo systemctl enable create_reverse_tunnel

# 查看 systemd 服務狀態
sudo systemctl status create_reverse_tunnel

在外部主機上連線到本地主機

上述步驟完成後,我們就可以在外部主機上使用 ssh 連線到本地主機:

ssh user@<Google Cloud IP> -p 2222 # user 為本地主機的使用者,若需要輸入密碼,則輸入本地主機的密碼

相關連結

comments powered by Disqus

相關文章

一文掌握 Linux 常用指令,讓你的系統管理更得心應手

一文掌握 Linux 常用指令,讓你的系統管理更得心應手

Linux 是一款強大的開源作業系統,被廣泛用於各種伺服器、桌面和嵌入式平台。由於其高度的可定制性和靈活性,Linux 成為了許多開發者和系統管理員的首

閱讀更多
為什麼 clone 下來的檔案不是正確的格式?認識 Git LFS

為什麼 clone 下來的檔案不是正確的格式?認識 Git LFS

最近遇到同事 git clone 一個專案,發現 clone 下來的壓縮檔居然是文字檔案!但我們在遠端看到的是壓縮檔,為什麼會這樣呢?原來是因為專案使用了 Git LFS,所以在

閱讀更多
如何配置多個 git ssh keys 並依照專案動態切換 git config

如何配置多個 git ssh keys 並依照專案動態切換 git config

我有時候會在公司的電腦開發自己的專案,也會在家裡的電腦開發公司的專案,這時候就會遇到一個問題,就是公司的 Git 用的是公司的帳號,而自己的專案用的

閱讀更多