1. 程式人生 > >利用ngrok實現內網穿透

利用ngrok實現內網穿透

實現內網穿透紫ngrok無法通過天牆之後,國內也出現了一批成熟的商業化實現方案,諸如花生殼、net123、Sunny-ngrok等。不過免費的極不穩定還有流量頻寬限制,最後還是決定自己搭一個。本文利用ngrok搭建一個用於內網穿透的環境。需求是通過一層反向代理,實現通過一個外網域名訪問一個部署在區域網上的服務。

準備

  • 一個公網伺服器(Linux系統) ==> 阿里雲,騰訊雲之類的都行
    • 這個公網伺服器主要用作反向代理,我們在本文中稱之為VPS伺服器
  • 一個獨立的域名
  • 一個用於提供服務的本地PC

步驟

  • GO語言環境搭建

    ngrok專案是用GO語言實現的,需要先安裝GOLANG開發環境,系統不限,因為GO語言是跨平臺的!安裝過程很簡單,參考

    官網的教程即可!

  • 獲取ngrok原始碼

    
    # 下面是直接去ngrok的github地址下載(待會兒make的時候還會需要裝幾個其它的依賴,可能會出現很多問題)
    
    git clone https://github.com/inconshreveable/ngrok.git
    
    
    # 下面是筆者將程式碼clone下來,並添加了相應依賴之後的地址,如果用上面的方式出現錯誤,可以clone下面的地址
    
    git clone https://github.com/SunnyQjm/ngrok.git
  • 解析域名

    因為我們自己搭建,需要使用自己的域名(以 test.j.cn )為例,我們需要做以下解析:

    test.j.cn    ------------> A記錄到你的VPS伺服器的IP
    
    
    # ngrok可以指定子域名,下面的解析方式可以讓任意子域名都能得到正確的解析
    *.test.j.cn ------------> CNAME記錄到 test.j.cn
  • 生成簽名證書

    • 因為我們是自己搭建,就不能用ngrok官方的SSL證書,需要自己生成
    • 下面生成證書在編譯專案的時候要用到,所以務必要在編譯之前生成
    • 需要注意的是,客戶端和伺服器的證書必須是同一份,這樣在程式在認證的時候才能正確解析
    
    # 首先匯出環境變數,將下面的值替換成你的域名
    
    export NGROK_DOMAIN="test.j.cn"
    
    
    #先進入到ngrok的根目錄,生成證書的操作需要在根目錄下進行
    
    cd ngrok
    
    
    # 下面的命令用於生成證書
    
    openssl genrsa -out rootCA.key 2048
    openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem openssl genrsa -out device.key 2048 openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000 # 下面的命令用於將我們生成的證書替換ngrok預設的證書 cp rootCA.pem assets/client/tls/ngrokroot.crt cp device.crt assets/server/tls/snakeoil.crt cp device.key assets/server/tls/snakeoil.key
  • 編譯執行

    • 服務端(VPS伺服器一端)

      • 首先指定一下環境變數,在不同的作業系統下需要指定不同的環境變數,才能正確編譯(預設是Linux 64位的配置,如果你的伺服器是64位的Linux系統,也可以不指定,直接用預設的就行)

          GOOS=linux GOARCH=amd64
          #如果是32位系統,這裡 GOARCH=386
          #如果是windows系統,GOOS=windows
      • 然後make出服務端程式

        make release-server
      • 如果編譯成功,你會在bin目錄下看到ngrokd程式

        cd bin
        
        
        # 檢視使用幫助
        
        ./ngrokd -h
      • 檢視使用幫助

        
        # 檢視使用幫助
        
        ./ngrokd -h
        -domain string
            Domain where the tunnels are hosted (default "ngrok.com")
        -httpAddr string
            Public address for HTTP connections, empty string to disable (default ":80")
        -httpsAddr string
            Public address listening for HTTPS connections, emptry string to disable (default ":443")
        -log string
            Write log messages to this file. 'stdout' and 'none' have special meanings (default "stdout")
        -log-level string
            The level of messages to log. One of: DEBUG, INFO, WARNING, ERROR (default "DEBUG")
        -tlsCrt string
            Path to a TLS certificate file
        -tlsKey string
            Path to a TLS key file
        -tunnelAddr string
            Public address listening for ngrok client (default ":4443")
      • 啟動服務端

        
        # 如果不能執行,你可能需要用 sudo chmod +x ngrokd 給它執行許可權
        
        
        # domain域輸入之前生成證書時指定的域名
        
        
        # httpAddr 指定轉發http協議的哪個埠
        
        
        # httpAddrs 指定轉發https協議的哪個埠(如果不需要可以省略)
        
        ./ngrokd  -domain="$NGROK_DOMAIN" -httpAddr=":8000" -httpsAddr=":4433"
      • 如果執行成功,你會看到類似以下介面:

        [16:23:40 CST 2018/03/19] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
        [16:23:40 CST 2018/03/19] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:9748
        [16:23:40 CST 2018/03/19] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:443
        [16:23:40 CST 2018/03/19] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443
        [16:23:40 CST 2018/03/19] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds
      • 自此,服務端算是配置好了

    • 客戶端(部署了服務,需要內網穿透訪問的主機)

      客戶端要做的事情就是指定把本機的那個埠暴露給VPS伺服器,客戶端要在該埠上部署了服務(web服務或者tomcat服務等),這樣VPS就能夠將請求轉發到該埠對應的服務上了

    
    # 因為前面說過,服務端和客戶端的證書要是同一份,這樣認證才能通過,所以好的解決方案是在服務端上把客戶端程式也編譯出來,然後通過scp命令拷貝到客戶端
    
    
    # 假設我要在mac上執行客戶端,需要在編譯命令前加上一些引數(如果客戶端伺服器也是Linux 64位,則不用指定環境變數)
    
    GOOS=darwin GOARCH=amd64 make release-client
    make release-client
    
    
    # 編譯好後scp到本地
    
    scp xxx xxx
    
    
    # 下面開始本地配置(下面的配置在客戶端進行)
    
    
    
    # 新建一個配置檔案(在ngrok/bin目錄下)
    
    vim ngrok.cfg
    
    
    # 新增一下兩行
    
    
    # 第一行是將要繫結的域名+4443埠(因為ngrok服務端預設有一個服務是堅挺在4443埠的,客戶端會通過這個埠與之相連)==> 記得將域名換成自己在生成證書時指定的
    
    server_addr: "test.j.cn:4443"
    trust_host_root_certs: true
    
    
    # 幫助資訊
    
    ./ngrok -h
    Examples:
        ngrok 80
        ngrok -subdomain=example 8080
        ngrok -proto=tcp 22
        ngrok -hostname="example.com" -httpauth="user:password" 10.0.0.1
    
    
    # 80就是我們要轉發的埠了
    
    ./ngrok -config=./ngrok.cfg 80
    
    
    # 指定協議和埠,不指定預設是 http+https
    
    ./ngrok -config=./ngrok.cfg -proto=tcp 22
    
    
    # 指定子域名,不指定就會隨機生成
    
    ./ngrok -config=./ngrok.cfg -subdomain=test 80
    • 連線成功會顯示如下狀態:

注意

上文中所有出現域名的地方都要統一,客戶端和服務端的證書要是同一份,否則在連線的時候會出現bad certification

參考