ngrok 實現內網穿透

ngrok 實現內網穿透

來自專欄 字裡行間

最近新買了一台伺服器放在家裡跑各種雜七雜八的服務,需整一個內網穿透的服務通過外網也能遠程登錄伺服器。很久之前就聽聞 ngrok 能實現,於是乎自己也整了一遍。這篇文章記錄服務端到客戶端部署的全過程,備忘。

首先得有一台外網能夠訪問的 vps 用以部署 ngrok 的服務端、及一個用以解析自搭建 ngrok 服務的域名。

創建證書

ngrok 的隧道採用 TSL 傳輸數據,如果使用默認證書的話任何人都可以連接你搭建的 ngrok 服務,在這裡你可以去買,不過還是推薦自己生成證書。

export NGROK_DOMAIN="ngrok.xxx.com"openssl genrsa -out base.key 2048openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.pemopenssl genrsa -out server.key 2048openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csropenssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt

執行上述文件會生成 6 個文件,server.key, server.crt, base.pem 這三個才是我們需要用到的,覆蓋 ngrok 默認證書

cp server.key assets/server/tls/snakeoil.keycp server.crt assets/server/tls/snakeoil.crtcp base.pem assets/client/tls/ngrokroot.crt

編譯 ngrok 服務端和客戶端

編譯需要 Golang 環境,獲取 ngrok 源碼: git clone https://github.com/inconshreveable/ngrok.git

ngrok 默認監聽 IPv6 埠,我大清自有國情,我們需要源碼兩處

  • src/ngrok/server/tunnel.go 文件中 net.ListenTCP 後面的 tcp 改為 tcp4
  • src/ngrok/conn/conn.go 文件中 net.Listen 後面的 tcp 改為 tcp4

接下來就是編譯,我們需要查看將要部署 ngrok 服務的服務端和客戶端 ARCH 信息以便進行跨平台編譯,使用命令:

// 這裡是我機器的信息,你需要根據你機器得到的信息使用對用的編譯指令dpkg --print-architectureamd64 // 將要部署 ngrok 服務端的 vps 伺服器 arch 信息i386 // 將要部署 ngrok 客戶端的內網伺服器

Go (Golang) GOOS and GOARCH

cd 到 ngrok 源碼的目錄準備編譯:

// 服務端GOOS=linux GOARCH=amd64 make release-server// 客戶端GOOS=linux GOARCH=386 make release-client

編譯得到的可執行文件在 bin 目錄下,然後我們使用 scp 命令或 async 命令把編譯後得到的文件拷貝到 vps 和內網伺服器上:

scp bin/linux_amd64/ngrokd {vps_server}scp bin/linux_386/ngrok {local_server}

配置域名和 ngrok 客戶端、服務端

首先你需要在域名解析網站解析域名,後續你就可以通過域名遠程連接內網伺服器,這也是我們最終的目的哈。

解析主機記錄為 ngrock 和 *.ngrok.xxx.com 且全部為 A 記錄類型,記錄值填你的 vps 外網地址。

服務端配置

前面我們已經把 ngrokd 文件拷貝到 vps 的根目錄,在這裡我們把轉移到這裡:sudo mkdir /opt/ngrkd & sudo mv ngrokd /opt/ngrokd/

然後使用 systemd 設置自啟動服務,把如下內容保存在 /lib/systemd/system/ngrokd.service, 域名要改成你自己的。

[Unit]Description=ngrok serverAfter=network.target[Service]Type=simpleExecStart=/opt/ngrokd/ngrokd -domain ngrok.xxx.com -httpAddr "" -httpsAddr "" -tunnelAddr ":4443" -log "/var/log/ngrokd.log"Restart=on-failure[Install]WantedBy=multi-user.target

啟動服務

sudo systemctl enable ngrokdsudo systemctl start ngrokdsudo systemctl status ngrokd

客戶端配置

登錄到內網伺服器, 同樣把編譯好的 ngrok 拷貝過來的 ngrok 客戶端,然後同樣客戶端服務添加到 systemd 自啟動服務中,保存下面內容到文件 /lib/systemd/system/ngrok.service

[Unit]Description=ngrok clientAfter=network.target[Service]Type=simpleExecStart=/opt/ngrok/ngrok -config "/opt/ngrok/ngrok.yml" -log "/var/log/ngrok.log" start transmission sshRestart=on-failure[Install]WantedBy=multi-user.target

ExecStart 載入了配置文件 /opt/ngrok/ngrok.yml,其文件內容如下:

server_addr: ngrok.xxx.com:4443trust_host_root_certs: falsetunnels: transmission: remote_port: 9091 proto: tcp: 9091 ssh: remote_port: 23333 proto: tcp: 22

然後像啟動 ngrok 服務端服務一樣啟動客戶端服務

在這裡提醒一點,我踩到了一個坑,啟動客戶端服務時日誌 (sudo tail -f /var/log/ngrok.log) 出現報錯:

[2018/02/13 01:41:28 CST] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [view] [term] Waiting for update[2018/02/13 01:41:28 CST] [EROR] (ngrok/log.Error:120) control recovering from failure dial tcp: lookup ngrok.xxx.com on 8.8.8.8:53: no such host

後面我在內網伺服器 ping ngrok.xxx.com 提示找不到 host, 應該是 dns 的問題,nslookup ngrok.xxx.com 看了一下,果不其然,我直接把域名和 IP 寫到內伺服器的 /etc/hosts 文件上。

systemd 重啟客戶端服務之後就正常了。

最後通過 ssh -p 23333 username@ngrok.xxx.com 即可遠程登錄區域網內的伺服器。

推薦及參考閱讀

內網穿透之ngrok [2017-10-13 UPDATED]


推薦閱讀:

泵、管道和水龍頭
喜歡玩遊戲的孩子適合學習編程嗎?
CodeCombat:在遊戲里學Python是一種怎樣的體驗?
一則Python小Trick[編程的日常]
Android網路許可權問題

TAG:Linux運維 | 編程 | 伺服器配置 |