使用 OpenSSH 替沒有固定 IP 的本地主機 (WSL2) 建立反向 TCP 遠端通道 (Ngrok 免費替代)
- Leo
- 技術宅 ( tech geek)
- 2024年5月4日
目錄
若我們希望將本地主機的服務,例如 ssh
伺服器供外部連線,但我們又沒有固定 IP 時,我們可以使用 OpenSSH
建立反向 TCP
遠端通道,讓外部主機可以透過這個通道連線到我們的本地主機。
其實本質上還是透過一個具有固定 IP 的中間主機,將外部主機的請求轉發到本地主機,這個中間主機可以是我們自己的伺服器,也可以是一些提供這種服務的雲端主機,例如 Google Cloud
、AWS
等等。
假設我們使用 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
-M
讓ssh
建立 “master” 模式-S
讓ssh
在建立 “master” 模式之後,順便建立一個 control socket 檔案以利後續停止或添加新的通道-f
讓ssh
在開始執行之前,就將該程序放入到背景執行-N
讓ssh
不要在遠端主機執行命令,通常建立 SSH 通道時會使用這個參數-T
讓ssh
停用虛擬終端機建立-R
讓ssh
建立一個反向 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 為本地主機的使用者,若需要輸入密碼,則輸入本地主機的密碼