簡單來說內網穿透的目的是:讓外網能訪問你本地的應用,例如在外網打開你本地http://127.0.0.1指向的Web站點。
最近公司的花生殼到期了,要續費,發現價格一直在漲,都是5年以上的老用戶,旗艦版都沒有實現內網完全穿透,打算自己動手替換這個服務,中間走了不少的彎路,這里記錄一些文字為大家提供參考。
隨著開發與運行移動互聯網的應用越來越多對打通內外網的需要也更加迫切,如微信開發、IOS與Android開發等。
雖然租用VPS、ECS等服務器可以解決很多問題但高性能的外網服務器價格非常貴還有數據安全問題,我選擇的是公網服務器僅做代理與輕量應用,復雜的應用部署到內網服務器再穿透訪問。
一、內網穿透概要
為了理解內網穿透我們先來了解幾個概念:
1.1、IP地址
網絡中唯一定位一臺設備的邏輯地址,類似我們的電話號碼
在互聯網中我們訪問一個網站或使用一個網絡服務最終都需要通過IP定位到每一臺主機,如訪問baidu網站:

其中119.75.213.61就是一個公網的IP地址,他最終指向了一臺服務器。
IP地址是IP協議提供的一種統一的地址格式,它為互聯網上的每一個網絡和每一臺主機分配一個邏輯地址,以此來屏蔽物理地址的差異。
內網IP可以同時出現在多個不同的局域網絡中,如A公司的U1用戶獲得了192.168.0.5,B公司的U3用戶也可以獲得192.168.0.5;但公網IP是唯一的,因為我們只有一個Internet。
//局域網可使用的網段(私網地址段)有三大段:10.0.0.0~10.255.255.255(A類)172.16.0.0~172.31.255.255(B類)192.168.0.0~192.168.255.255(C類)
1.2、域名
域名是IP的別名,便于記憶,域名最終通過DNS解析成IP地址。

IP V4是一個32位的數字,IP V6有128位,要記住一串毫無意義的數字非常困難,域名解決了這個問題。
如www.zhangguo.com.cn就是一個域名,cn表示地區,com表示商業機構,zhangguo是公司名稱,www是主機名

DNS查詢過程如下,最終將域名變成IP地址

1.3、NAT
NAT(Network Address Translation)即網絡地址轉換,NAT能將其本地地址轉換成全球IP地址。
內網的一些主機本來已經分配到了本地IP地址(如局域網DHCP分配的IP),但現在又想和因特網上的主機通信(并不需要加密)時,可使用NAT方法。
通過使用少量的公有IP 地址代表較多的私有IP 地址的方式,將有助于減緩可用的IP地址空間的枯竭。
NAT不僅能解決了lP地址不足與共享上網的問題,而且還能夠有效地避免來自網絡外部的攻擊,隱藏并保護網絡內部的計算機。
多路由器可完成NAT功能。
NAT的實現方式:
靜態轉換是指將內部網絡的私有IP地址轉換為公有IP地址,IP地址對是一對一。
動態轉換是指將內部網絡的私有IP地址轉換為公用IP地址時,IP地址是不確定的,是隨機的。
端口多路復用(Port address Translation,PAT),內部網絡的所有主機均可共享一個合法外部IP地址實現對Internet的訪問,從而可以最大限度地節約IP地址資源。同時又可隱藏網絡內部的所有主機,有效避免來自internet的攻擊。因此,目前網絡中應用最多的就是端口多路復用方式。
應用程序級網關技術(Application Level Gateway)ALG:傳統的NAT技術只對IP層和傳輸層頭部進行轉換處理,ALG它能對這些應用程序在通信時所包含的地址信息也進行相應的NAT轉換。


1.4、Proxy
Proxy即代理,被廣泛應用于計算機領域,主要分為正向代理與反向代理:
1.4.1、正向代理
比如X花店代A,B,C,D,E五位男生向Candy女生送匿名的生日鮮花,這里的X花店就是5位顧客的代理,花店代理的是客戶,隱藏的是客戶。這就是我們常說的代理。
正向代理隱藏了真實的請求客戶端。服務端不知道真實的客戶端是誰,客戶端請求的服務都被代理服務器代替來請求,某些科學上網工具扮演的就是典型的正向代理角色。用瀏覽器訪問http://www.google.com時被墻了,于是你可以在國外搭建一臺代理服務器,讓代理幫我去請求google.com,代理把請求返回的相應結構再返回給我。

當多個客戶端訪問服務器時服務器不知道真正訪問自己的客戶端是那一臺。正向代理中,proxy和client同屬一個LAN,對server透明;

1.4.2、反向代理
撥打10086客服電話,接線員可能有很多個,調度器會智能的分配一個接線員與你通話。這里的調度器就是一個代理,只不過他代理的是接線員,客戶端不能確定真正與自己通話的人,隱藏與保護的是目標對象。
反向代理隱藏了真實的服務端,當我們請求 ww.baidu.com 的時候,就像撥打10086一樣,背后可能有成千上萬臺服務器為我們服務,但具體是哪一臺,你不知道,也不需要知道,你只需要知道反向代理服務器是誰就好了,ww.baidu.com 就是我們的反向代理服務器,反向代理服務器會幫我們把請求轉發到真實的服務器那里去。Nginx就是性能非常好的反向代理服務器,用來做負載均衡。

反向代理中,proxy和server同屬一個LAN,對client透明。

了解更多關于代理內容請點擊這里。
1.5、DDNS
DDNS即動態域名解析,是將用戶的動態IP地址映射到一個固定的域名解析服務上,用戶每次連接網絡的時候,客戶端程序就會通過信息傳遞把該主機的動態IP地址傳送給位于服務商主機上的服務器程序,服務程序負責提供DNS服務并實現動態域名解析。就是說DDNS捕獲用戶每次變化的IP地址,然后將其與域名相對應,這樣域名就可以始終解析到非固定IP的服務器上,互聯網用戶通過本地的域名服務器獲得網站域名的IP地址,從而可以訪問網站的服務。
1.6、為什么需要內網穿透
當內網中的主機沒有靜態IP地址要被外網穩定訪問時可以使用內網穿透
在互聯網中唯一定位一臺主機的方法是通過公網的IP地址,但固定IP是一種非常稀缺的資源,不可能給每個公司都分配一個,且許多中小公司不愿意為高昂的費用買單,多數公司直接或間接的撥號上網,電信部門會給接入網絡的用戶分配IP地址,以前上網用戶少的時候基本分配的都是臨時的靜態IP地址,租約過了之后可能會更換成另一個IP地址,這樣外網訪問就不穩定,因為內網的靜態IP地址一直變化,為了解決這個問題可以使用動態域名解析的辦法變換域名指向的靜態IP地址。但是現在越來越多的上網用戶使得臨時分配的靜態IP地址也不夠用了,電信部門開始分配一些虛擬的靜態IP地址,這些IP是公網不能直接訪問的,如以125開頭的一些IP地址,以前單純的動態域名解析就不好用了。
1.7、內網穿透的定義與障礙
簡單來說實現不同局域網內的主機之間通過互聯網進行通信的技術叫內網穿透。
障礙一:位于局域網內的主機有兩套 IP 地址,一套是局域網內的 IP 地址,通常是動態分配的,僅供局域網內的主機間通信使用;一套是經過網關轉換后的外網 IP 地址,用于與外網程序進行通信。

障礙二:位于不同局域網內的兩臺主機,即使是知道了對方的 IP 地址和端口號,“一廂情愿”地將數據包發送過去,對方也是接收不到的。
因為出于安全起見,除非是主機主動向對方發出了連接請求(這時會在該主機的數據結構中留下一條記錄),否則,當主機接收到數據包時,如果在其數據結構中查詢不到對應的記錄,那些不請自來的數據包將會被丟棄。

解決辦法:要想解決以上兩大障礙,我們需要借助一臺具有公網 IP 的服務器進行橋接。
二、常見的內網穿透產品
2.1、花生殼
花生殼既是內網穿透軟件、內網映射軟件,也是端口映射軟件。規模最大,較正規,完善。
收費高,使用簡單
官網:http://www.oray.com/

2.2、Nat123
nat123是內網端口映射與動態域名解析軟件,在內網啟動映射后,可在外網訪問連接內網網站等應用。整個網站我都沒有找到客服電話,網友發了一些反面的評價
收費,使用簡單
官網:http://www.nat123.com

2.3、NATAPP
NATAPP基于ngrok的國內內網穿透服務,免費版會強制更換域名,臨時用一下可以
收費,使用簡單
官網:https://natapp.cn/

2.4、frp與其它
frp 是一個高性能的反向代理應用,可以幫助您輕松地進行內網穿透,對外網提供服務,支持 tcp, http, https 等協議類型,并且 web 服務支持根據域名進行路由轉發。
開源免費
使用相對復雜,需要代理服務器支持
官網:https://github.com/fatedier/frp
文檔:查看幫助文檔,簡書示例
利用處于內網或防火墻后的機器,對外網環境提供 http 或 https 服務。
對于 http, https 服務支持基于域名的虛擬主機,支持自定義域名綁定,使多個域名可以共用一個80端口。
利用處于內網或防火墻后的機器,對外網環境提供 tcp 和 udp 服務,例如在家里通過 ssh 訪問處于公司內網環境內的主機。

因為frp 仍然處于前期開發階段,未經充分測試與驗證,不推薦用于生產環境,所有我選擇了ngrok,資料比較多。
還有如圣劍內網通、ngrok(開源免費)、更多辦法
三、ngrok
ngrok是一個反向代理,通過在公共的端點和本地運行的Web服務器之間建立一個安全的通道。ngrok可捕獲和分析所有通道上的流量,便于后期分析與響應。
開源免費
官網:https://ngrok.com/
源碼:https://github.com/inconshreveable/ngrok

ngrok1.x開源,ngrok2.x不開源
ngrok使用Go語言開發,源代碼分為客戶端與服務器端。
國內免費服務器:http://ngrok.ciqiuwl.cn/,更多免費服務器請大家挖掘,資源共享,我隨時更新:)
如果有服務器,僅客戶端的使用是不復雜的,以上面的免費服務器為示例完成內網穿透
現在假定我的本地已成功部署了一個網站,訪問地址為127.0.0.1,想內網穿透后被公網上的用戶訪問,一般步驟如下:
步驟1、下載windows版本的客戶端,解壓。一般在為你提供代理服務器的網站上找你要下載的客戶端:

步驟2、在命令(cmd)行下進入到ngrok客戶端目錄下

步驟3、執行 ngrok -config=ngrok.cfg -subdomain xxx 80 //(xxx 是你自定義的域名前綴),建議批處理

如果連接成功,會提示如下信息:

這一步如果你認為太麻煩,可以直接運行目錄下的start.bat批處理文件就不用進DOS環境了。運行start.bat直接跳過2,3步
步驟4、如果開啟成功 你就可以使用 xxx.ngrok.xiaomiqiu.cn 來訪問你本機的 127.0.0.1:80 的服務了,當然你必須確定的是你本機的Web是可以正常訪問的。

注意:
如果你自己有頂級域名,想通過自己的域名來訪問本機的項目,那么先將自己的頂級域名解析到120.25.161.137(域名需要已備案哦,80端口必須備案),然后執行 ngrok -config=ngrok.cfg -hostname xxx.xxx.xxx 80 //(xxx.xxx.xxx是你自定義的頂級域名)
四、ubuntu下生成ngrok服務器主程序
4.1、步驟與先決條件
如果你只是臨時穿透或調試用,到第三步基本就可以了,但如果想作為穩定的商業服務,用別人的服務器還是受制于人,這里我們準備搭建自己的ngrok服務器。大致的步驟如下:

ngrok服務器可以是多種平臺,如windows、linux(centos、Debian、Ubuntu等)、mac OS等。
編譯源代碼生成應用強烈建議大家使用linux環境,windows肯定可以成功,但非常麻煩,我在windows操作系統上兜了一個大圈圈。
先決條件:
a)、您有一臺公網上的服務器,如阿里云的ECS
b)、您有一個域名,最好ICP備案成功,不然80端口沒有辦法使用,不過像微信開發是不使用80端口的,可以用nginx代理轉換。
4.2、安裝ubuntu操作系統
在linux環境下編譯ngrok的源代碼比windows下 方便很多,這里我們選擇使用ubuntu,獲得ubuntu的方法有如下幾種:
1)、全新安裝ubuntu系統
2)、申請VPS服務器, 阿里云、騰訊云、華為云、百度云、新浪云等,僅編譯一下這種方法不錯
3)、在虛擬機中安裝ubuntu系統
綜合考慮我選擇了在虛擬機中安裝ubuntu操作系統

4.2.1、安裝VMware虛擬機
VMware Workstation是一款功能強大的虛擬機軟件,在不影響本機操作系統的情況下,用戶可以在虛擬機中同時運行不同版本的操作系統,用于開發、測試以及部署工作。
VMware Workstation 12 pro下載:VMware-workstation-full-12.1.0-3272444.exe
序列號:5A02H-AU243-TZJ49-GTC7K-3C61N(商業應用請購買正式版權,這里僅為學習使用)
1)、雙擊VMware Workstation 12安裝文件,或者右鍵管理員身份打開,提示是否允許更改,點擊是;
2)、打開VMware安裝向導,點擊下一步;

3)、VMware Workstation 12激活步驟:
方法一、首次開啟直接輸入上文密鑰,即可激活;
方法二、首次開啟選擇試用,進入試用后按一下步驟激活:
a、打開虛擬機主界面,點擊“幫助”—“輸入許可證密鑰”;

b、在密鑰輸入框輸入永久許可證密鑰5A02H-AU243-TZJ49-GTC7K-3C61N,確定;更多
4.2.2、安裝ubuntu到虛擬機
1)、下載ubuntu操作系統鏡像
下載地址:https://www.ubuntu.com/download/desktop
這里我下載的是ubuntu-16.04.3-desktop-amd64.iso

2)、在VMware中安裝ubuntu
打開VMware點擊“創建新的虛擬機”

向導選擇自定義

然后下一步再下一步,直到這里,稍后再安裝系統

后面設置處理器和內存的,電腦配置好的可以試試,否則采用默認的,博主這里是采用默認的,然后下一,直到這里,選擇將虛擬機存儲為單個磁盤:

個人建議至少20G硬盤空間,內存建議給1.5G,當然也要看電腦本身的配置,1G的內存跑起來比較卡。
其它的步驟比較簡單,更多細節可以參考這里,《VMware Ubuntu安裝詳細過程》。
4.2.3、配置ubuntu系統
當ubuntu系統安裝成功后,在虛擬機中可以啟動ubuntu系統,啟動后的系統如下:

ubuntu系統的使用還是有許多內容的,這里需要設置的內容如下:
a)、設置上網
就是在ubuntu中可以訪問外網,可以使用多種形式

b)、設置語言
可以選擇使用中文版的ubuntu語言環境

c)、設置屏幕分辨率
如果不設置默認的屏幕比較小

d)、設置以root超級管理員的身份登錄
許多操作要求管理身份

e)、安裝VMware Tools工具
只有在VMware虛擬機中安裝好了VMware Tools,才能實現主機與虛擬機之間的文件共享,同時可支持自由拖拽的功能,鼠標也可在虛擬機與主機之間自由移動(不用再按ctrl+alt),且虛擬機屏幕也可實現全屏化。
VMware Tools是VMware虛擬機中自帶的一種增強工具,相當于VirtualBox中的增強功能(Sun VirtualBox Guest Additions),是VMware提供的增強虛擬顯卡和硬盤性能、以及同步虛擬機與主機時鐘的驅動程序。

注意如果這里是灰色的需要您將linux.iso鏡像加載到虛擬光驅中,一般在VM的安裝目錄下有,如果沒有您需要自行下載。
說明:ubuntu的使用不是本文的重點,相關操作請大家自行查找。
4.3、生成ngrok服務器與客戶端應用程序
4.3.1. 導出源代碼
ngrok的源代碼托管在github上,可以先在ubuntu下安裝git再將ngrok的源代碼克隆到本地。

其實也可以直接下載到本地后解壓,這里使用命令行完成。
啟動ubuntu,開打命令行(終端),如下所示:

以root身份執行如下命令:
mkdir ngrok #創建名稱為ngrok的目錄 apt-get update #更新包管理器 apt-get install git #安裝git git clone https://github.com/inconshreveable/ngrok.git ngrok2 #將ngrok源代碼克隆回本地
成功執行后如下所示:

導出成功后的源代碼:

PS. 直接在服務器上下載的話實在太慢,可以先在本地下載好,然后用ftp放到服務器上去直接用,如果安裝了VMware tools直接拖進去就可以了。
4.3.2. 安裝Go語言開發環境
直接在命令模式下執行如下指令:
apt-get install golang #安裝go語言
執行結果如下:

4.3.3. 更改ngrok域名
在自己的域名管理中添加解析A記錄,如下所示:

將*.ngrok與ngrok都指向您的主機IP。
默認的域名是ngrok自己的,要替換成您自己的域名
export GOPATH=/usr/local/ngrok/ #設置環境變量,Go語言的安裝位置export NGROK_DOMAIN="ngrok.yourdomain.com" #設置環境變量,ngrok域名
PS. ngrok名稱可以任意,推薦名稱為ngrok或者tunnel
4.3.4. 為域名生成證書
openssl genrsa -out rootCA.key 2048openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pemopenssl genrsa -out server.key 2048openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csropenssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 5000
生成后的結果如下:

證書如下:

4.3.5. 拷貝證書到指定位置
cp rootCA.pem assets/client/tls/ngrokroot.crt #復制rootCA.pem到assets/client/tls/并更名為ngrokroot.crtcp server.crt assets/server/tls/snakeoil.crt #復制server.crt到assets/server/tls/并更名為snakeoil.crtcp server.key assets/server/tls/snakeoil.key #復制server.key到assets/server/tls/并更名為snakeoil.key
運行結果:

4.3.6. 編譯
由于go語言的特性,在編譯時直接生成機器碼,所以在運行過程中并不需要go的環境(非托管應用)。在ngrok目錄下,運行一下命令分別生成對應的客戶端與服務端。
#win服務端GOOS=windows GOARCH=386 make release-server #win客戶端GOOS=windows GOARCH=386 make release-client#linux服務端GOOS=linux GOARCH=386 make release-server#linux客戶端GOOS=linux GOARCH=386 make release-client
生成完成后,在工作目錄的bin文件夾下,產生對應的文件。以編譯windows平臺為例,會產生“ngrok.exe”與“ngrokd.exe”這兩個文件,前者客戶端,后者需要運行在公網服務器上。
因為項目中引用了一些外部資源,生成會耗費一些時間,對網絡也有一定的要求,太慢會中短,命令執行下如:

生成結果:

這里我還生成了兩個運行在windows服務器與客戶端的應用:

ngrok.exe是客戶端,ngrokd.exe是服務端,下面是比較連續的操作結果。


五、部署服務器端主程序
5.1、部署到Windows Server服務器
將生成的ngrokd.exe文件復制到windows服務器中,當然如果要部署到linux中也是沒有問題的。
這里我將ngrokd.exe放在c:grokeServer目錄下:

為了方便,我編寫了一個批處理文件:ngrokserver2.bat
ngrokd.exe -tlsKey="snakeoil.key" -tlsCrt="snakeoil.crt" -domain="ngrok.你的域名.com" -httpAddr=":801" -httpsAddr=":802"
點擊批處理運行結果如下:

綁定的域名換成自己的域名,http使用801端口,https使用802端口,供客戶端連接的管道端口設置為4443端口,必須前面的域名相同。
為了安全許多服務器會將端口屏蔽,我使用的是ECS服務器,默認801,802都是關閉的,需要手動開啟,在阿里云的后臺添加開放的端口就可了:

5.2、一鍵部署ngrok服務器(CentOS、Debian、Ubuntu)
如果編譯生成ngrok的源代碼生成應用太麻煩,你可以選擇網友寫的工具,支持一鍵部署到安裝平臺:CentOS、Debian、Ubuntu。
https://github.com/clangcn/ngrok-one-key-install
六、部署ngrok客戶端
這里的客戶端就是您的web應用程序所運行的主機,將ubuntu生成的ngrok.exe客戶端應用復制到您的系統中:

添加配置文件ngrok.cfg:
server_addr: "ngrok.你的域名.com:4443"trust_host_root_certs: false
添加批處理start.bat,如果只運行一次直接在命令行下輸入命令也是一樣的效果,內容如下:
ngrok.exe -subdomain kyt -config=ngrok.cfg 8987
其中8987為端口號,運行成功的結果如下所示:

看到這個界面時說明已成功了。
七、啟動客戶端并測試
打開瀏覽器,輸入您映射后的域名就可以穿透內網訪問您的web服務器了。

八、總結
一開始選擇錯了平臺,在windows花了不少時間,在ubuntu下順利完成。
無論是客戶端還是服務器端最好都做成服務,更方便與穩定。
由于服務器上同時運行著IIS,故服務端Ngrok啟動時無法使用80端口,所以在上面,我使用了801作為Ngrok服務器的http端口,使用IIS的代理功能可以解決這個問題,點擊這里。當然也可以使用nginx將80轉換成其它端口。
許多內容都參考了網友的文章。
如果服務器搭建好了,只運行客戶端穿透內網一分鐘夠了:)。