一、項目準備
1、一個可用的域名(不是必須,但是最好有)
2、一臺有公網IP的服務器
二、項目實施
? ? ? ? 本文的操作過程主要參考了《教你自己服務器搭建Ngrok》,但是隨著時間的推移,很多軟件因版本升級而產生了一些變化,因此有必要重新梳理一遍部署過程。同時,本文也是操作筆記,方便日后查閱。
? ? ? ? 在服務商處購得一臺云服務器,使用MobaXterm以SSH遠程登錄,首先是更新一下軟件
yum update
然后安裝golang
yum install go
提示找不到包
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
?* base: mirror.xtom.com.hk
?* extras: mirror.xtom.com.hk
?* updates: mirror.xtom.com.hk
No package go available.
Error: Nothing to do
需要添加源
rpm --import https://mirror.go-repo.io/centos/RPM-GPG-KEY-GO-REPO
curl -s https://mirror.go-repo.io/centos/go-repo.repo | tee /etc/yum.repos.d/go-repo.repo
這時再安裝golang便會提示安裝成功。查看一下go的版本
go version
go version go1.21.5 linux/amd64
golang的當前最新版。下面,拉取Ngrok的源碼。也可以使用國內源ngrok: ngrok 國內加速版本
git clone https://github.com/inconshreveable/ngrok
?然后,進入ngrok目錄,并創建ssl目錄
cd ngrok/
mkdir ssl
cd ssl
生成自簽名證書
export NGROK_DOMAIN="xx.xx.xxx"
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 5000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 5000 -out server.crt
NGROK_DOMAIN那里設置成你的域名,此時會生成6個文件
base.key ?base.pem ?base.srl ?server.crt ?server.csr ?server.key
然后執行下面的命令替換源碼包自帶的證書
cp base.pem ../assets/client/tls/ngrokroot.crt
cp server.crt ../assets/server/tls/snakeoil.crt
cp server.key ../assets/server/tls/snakeoil.key
回到上級目錄,然后生成服務端
cd ../
GOOS=linux GOARCH=amd64 make release-server
結果提示錯誤
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
? ? ? ? -debug=false \
? ? ? ? -o=src/ngrok/client/assets/assets_release.go \
? ? ? ? assets/client/...
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
? ? ? ? -debug=false \
? ? ? ? -o=src/ngrok/server/assets/assets_release.go \
? ? ? ? assets/server/...
go get -tags 'release' -d -v ngrok/...
go: go.mod file not found in current directory or any parent directory.
? ? ? ? 'go get' is no longer supported outside a module.
? ? ? ? To build and install a command, use 'go install' with a version,
? ? ? ? like 'go install example.com/cmd@latest'
? ? ? ? For more information, see https://golang.org/doc/go-get-install-deprecation
? ? ? ? or run 'go help get' or 'go help install'.
make: *** [deps] Error 1
修改一下go的環境變量?
go env -w GO111MODULE=auto
再次編譯就會通過。接著生成Windows版的客戶端
GOOS=windows GOARCH=amd64 make release-client
注: 如果是32位系統,GOARCH=386;如果是64為系統,GOARCH=amd64
? ? ? ? 如果要編譯linux,GOOS=linux;? ? 如果要編譯window,GOOS=windows
在./bin/windows_amd64/目錄下,會生成?ngrok.exe,將其下載到本地電腦上。在本地電腦ngrok.exe的同目錄下,新建一個配置文件ngrok.cfg,保存以下內容
server_addr: "xx.xx.xxx:4443"
trust_host_root_certs: false
這里的域名要和上文證書簽名那里的保持一致。
接下來,先啟動服務端。在服務器輸入
./bin/ngrokd -domain="xx.xx.xxx"
?[06:51:54 UTC 2024/03/01] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[06:51:54 UTC 2024/03/01] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds
[06:51:54 UTC 2024/03/01] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:80
[06:51:54 UTC 2024/03/01] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:443
[06:51:54 UTC 2024/03/01] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443
[06:52:24 UTC 2024/03/01] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting: {"bytesIn.count":0,"bytesOut.count":0,"connMeter.count":0,"connMeter.m1":0,"httpTunnelMeter.count":0,"linux":0,"osx":0,"other":0,"tcpTunnelMeter.count":0,"tunnelMeter.count":0,"tunnelMeter.m1":0,"windows":0}
然后啟動客戶端,在本地電腦的CMD中輸入?
ngrok.exe -log=stdout -config=ngrok.cfg 8080
再然后,不出意外地出意外了。本地電腦提示
[15:02:25 CST 2024/03/01] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [ctl:7cd75b8e] Closing
[15:02:25 CST 2024/03/01] [EROR] (ngrok/log.Error:120) control recovering from failure tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead
服務器提示
[07:02:28 UTC 2024/03/01] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [tun:134e61f5] Waiting to read message
[07:02:28 UTC 2024/03/01] [WARN] (ngrok/log.(*PrefixLogger).Warn:87) [tun:134e61f5] Failed to read message: remote error: tls: bad certificate
[07:02:28 UTC 2024/03/01] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [tun:134e61f5] Closing?
這個報錯原因是生成證書沒有開啟SAN擴展,go 1.15 版本開始廢棄 CommonName,因此推薦使用 SAN 證書。?
那么可否使用低版本的go來編譯ngrok呢?答案是不行,ngrok的一些依賴組件在低版本的go下無法編譯通過。
下面,在服務器上重新制作證書,并啟用SAN。
cd ssl/
echo subjectAltName = DNS:xx.xx.xxx>extfile.cnf
然后,重新簽名,在上述簽名命令的最后一句加上?-extfile extfile.cnf
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 5000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 5000 -out server.crt -extfile extfile.cnf
完成之后,還是先替換證書,make clean 之后再重新編譯服務端和客戶端。
重新運行服務端和客戶端,可以看到,ngrok會隨機分配域名前綴。這就需要我們配置 *.xx.xx.xxx的泛解析為服務器IP。
Tunnel Status ? ? ? ? ? ? ? ? online ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
Version ? ? ? ? ? ? ? ? ? ? ? 1.7/1.7 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
Forwarding ? ? ? ? ? ? ? ? ? ?http://4ec9da1.xx.xx.xxx -> 127.0.0.1:8080 ? ? ? ? ? ? ? ? ? ? ? ?
Forwarding ? ? ? ? ? ? ? ? ? ?https://4ec9da1.xx.xx.xxx -> 127.0.0.1:8080 ? ? ? ? ? ? ? ? ? ? ? ?
Web Interface ? ? ? ? ? ? ? ? 127.0.0.1:4040 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
# Conn ? ? ? ? ? ? ? ? ? ? ? ?0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
Avg Conn Time ? ? ? ? ? ? ? ? 0.00ms ? ? ?
但是,我申請到的域名是一個二級域名,無法配置泛解析,必須修改源碼,讓ngrok不分配前綴。
在ngrok/src/ngrok/server/tunnel.go的89行,刪掉?%x.
?rand.Int31()
,以及該文件第一行引入的?math/rand
,重新編譯出服務端與客戶端即可。
// Register for random URLt.url, err = tunnelRegistry.RegisterRepeat(func() string {return fmt.Sprintf("%s://%x.%s", protocol, rand.Int31(), vhost)}, t)
如果你沒有域名,可以直接使用IP地址,那么前文把DNS字段改成IP即可。
三、參考文獻
內網穿透 ngrok 服務器搭建與坑點
教你自己服務器搭建Ngrok?
ngrok的https等多隧道搭建及使用(菜鳥篇)?
verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead?
我們來親手搭建一個Ngrok內網穿透服務器?
Ngrok內網穿透?