前言
本教程不適合小白皆辽,本人因為水平有限柑蛇,也無法解決大家遇到的問題,一旦出現問題還得請各位自行摸索驱闷。
首要條件:NAT 類型為 NAT1耻台,即 fullcone饶米;光貓橋接或開啟 dmz种远;路由器能刷機或者開啟 upnp/dmz
建議:路由器能夠控制具體的端口開放與否,而不是只能全開或全關聪铺。
本文中的操作基于 OpenWrt 上的 Lucky扼菠,在其它設備使用或是使用 NATMAP 進行穿透同樣可以類比摄杂。建議在閱讀了第一期與第二期的基礎上閱讀本文。
需解決的問題與思路
STUN穿透的端口不固定循榆,并且更換較為頻繁析恢,雖然在第一期中,我們使用Cloudflare頁面規(guī)則秧饮,將域名重定向到了公網端口映挂,解決了web應用的訪問泽篮;而絕大多數需要連接自建后端的應用程序并不支持重定向,必須指定端口袖肥,甚至部分應用程序不允許修改默認端口咪辱。
我們可以借鑒其它內網穿透軟件的思路振劳,通過一個端口來轉發(fā)其他端口的流量椎组,常見的做法有兩種:
- 通過frp的stcp和sudp,將內網端口一對一的綁定到異地設備的本機端口上历恐。
- 通過wireguard或n2n寸癌,將內網整個網段轉發(fā)過去。
因為我的內網服務比較多弱贼,不想讓連teamspeak的朋友都來欣賞我的“學習資料”蒸苇,所以我選擇使用frp。
此處放兩個教程供各位參考吮旅,不過他們用的是NATMAP溪烤。
使用NATMap在NAT-1私網IP寬帶上部署FRP服務
natmap內網穿透讓內網實現公網IP,遠程訪問異地組網庇勃,做frps檬嘀,ssh ,web责嚷,wireguard..
如果你不考慮訪問者的權限鸳兽,僅僅想把整個內網網段轉發(fā)出去,可以考慮使用tailscale罕拂,并利用Lucky將搭建的Derp中繼服務器穿透出去揍异,操作更為簡單,具體方法請參考第四期教程爆班。
第一步 在內網安裝frps和frpc衷掷,并配置stcp
在內網配置的frps和frpc使用官方版即可,此處簡單帶過柿菩。官方文檔
frps
在路由器或nas上下載并安裝frps棍鳖,我是在Unraid里用docker安裝:
配置frps.ini :
[common]
bind_port = 7000
token = your_token
只需配置bind_port
和token
就行,也就是frps的訪問端口和令牌碗旅,默認采用TCP協議渡处。
配置完成后運行frps,接下來參考之前的教程祟辟,它創(chuàng)建STUN穿透通道医瘫、配置端口轉發(fā)、開啟防火墻旧困,在外網能ping通后為它設置開機自啟醇份。
frpc
為何在內網中也要frpc稼锅?這跟stcp與sudp的工作方式有關,官網的描述如下:
STCP 和 SUDP 的 (S) 的含義是 Secret僚纷。其作用是為 TCP 和 UDP 類型的服務提供一種安全訪問的能力矩距,避免讓端口直接暴露在公網上導致任何人都能訪問到。
這兩種代理要求在被訪問服務的機器上以及要訪問的用戶的機器上都部署上 frp 的客戶端怖竭。被訪問的服務所在機器叫做服務端锥债,另一端叫做訪問端。
frp 會在訪問端監(jiān)聽一個端口和服務端的端口做映射痊臭。訪問端的用戶需要提供相同的密鑰才能連接成功哮肚,從而保證安全性。
參考官方的使用示例 广匙,配置時根據需要把~~xtcp~~
改成~~stcp~~
或~~sdup~~
即可允趟。 官方已經不再推薦使用ini配置文件。
下載安裝官方版frpc后鸦致,編輯frpc.ini潮剪。common
中的token
必須與frps相同。
[common]
server_addr = 127.0.0.1
server_port = 7000
token = your_token
# jellyfin
[svc_jellyfin]
type = stcp
sk = B9jNFfUy3hDrmi
local_ip = 127.0.0.1
local_port = 8096
use_compression = true
role = server
# nginx
[svc_nginx]
type = stcp
sk = x5Y6f8VBbXQ5NY
local_ip = 192.168.0.115
local_port = 18443
use_compression = true
# teamspeak
[svc_ts1]
type = sudp
sk = khgtqgyCk3u3JZ
local_ip = 127.0.0.1
local_port = 9987
use_compression = false
[svc_ts2]
type = stcp
sk = khgtqgyCk3u3JZ
local_ip = 127.0.0.1
local_port = 10011
use_compression = true
[svc_ts3]
type = stcp
sk = khgtqgyCk3u3JZ
local_ip = 127.0.0.1
local_port = 30033
use_compression = true
我將frpc和frps部署在了同一臺機器上分唾,因此server_addr
填的是127.0.0.1抗碰,你要改為frps的內網ip。有網友反映將frps和frpc部署在同一臺機器上可能會出錯鳍寂,但是我沒遇到改含。
為你想要在外網訪問的所有端口都配置frpc的stcp/sudp服務端(如果不指定role
則默認為server
),local_ip
和local_port
為相應服務的內網地址和端口迄汛。我這里的添加了本地地址上的jellyfin捍壤、nginx和teamspeak。
如果你需要訪問的所有服務都經過反向代理鞍爱,那也可以只為反向代理配置stcp鹃觉,并在異地機器上修改HOSTS文件。
第二步 解析frps的公網端口
繞了這么一大圈睹逃,還是要面對最頭疼的問題:frps的公網訪問端口不固定怎么辦盗扇?
解決思路
ip4p
NATMAP的作者給出了名為ip4p的方案,也就是將ipv4地址和端口轉化成ipv6地址沉填,添加為一條AAAA記錄疗隶。當公網地址或端口改變時,只要修改該記錄翼闹,即可實現類似DDNS的效果斑鼻。作者也對frpc進行了修改,為它添加了解析ip4p的功能猎荠。支持ip4p的frp
The IP4P address format uses IPv6 special addresses to encode IPv4 addresses and ports for easy distribution through DNS AAAA records.
2001::{port}:{ipv4-hi16}:{ipv4-lo16}
-
ip4p存在的問題
在windows平臺和安卓平臺上坚弱,如果沒有外網ipv6環(huán)境蜀备,那么他程序里使用的LookupIP函數不會獲取AAAA記錄。雖然調用nslookup可以解析AAAA記錄荒叶,但是我懶......
也就是說碾阁,你連不上外網ipv6,就解析不了ip4p些楣,但是如果你連得上ipv6脂凶,為什么不用ipv6直連呢......
TXT記錄
我進交流群向帶佬求助后,帶佬建議我直接把公網ip和端口放進TXT記錄里戈毒。于是我花了倆小時自學了一下golang艰猬,添加了解析TXT記錄的功能横堡。我的做法是埋市,假設公網地址是183.6.66.666:6666
,將其用BASE64編碼命贴,變成MTgzLjYuNjYuNjY2OjY2NjY=
放進TXT記錄里道宅,供frpc解析。如果你覺得不安全胸蛛,那可以考慮加個AES加密之類的污茵。
創(chuàng)建TXT記錄
進入Cloudflare后臺,在dns - 記錄中創(chuàng)建一條TXT記錄葬项,TTL我設為了一分鐘泞当,不確定是否生效。
將你剛才創(chuàng)建的TXT記錄的域名民珍、Cloudflare的郵箱襟士、Global API Key和域名的區(qū)域id填入下面的指令里(忘記的可以看看第一期第四步和第五步),并在命令行里執(zhí)行嚷量。
curl -s -X GET "https://api.cloudflare.com/client/v4/zones/區(qū)域id/dns_records?type=TXT&name=ip4p.s***********n.online" -H "X-Auth-Email:******@qq.com" -H "X-Auth-Key:f9***********************1b" -H "Content-Type: application/json"
把結果里"id":
后面的那一串數字+字母復制下來陋桂,這就是這條記錄的id。
把包括剛才id在內的信息替換到下一行指令里執(zhí)行蝶溶,嘗試對剛才添加的TXT記錄進行修改:
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/區(qū)域id/dns_records/記錄id" -H "X-Auth-Email:******@qq.com" -H "X-Auth-Key:f9*************************1b" -H "Content-Type: application/json" --data '{"type":"TXT","name":"ip4p.s************.online","content":"changed","ttl":60,"proxied":false}'
再回到Cloudflare后臺嗜历,應該就能看到這條記錄更改了。
部分免費域名無法使用API修改抖所。
配置腳本
在以下腳本中填入Cloudflare的郵箱梨州、Global API key、區(qū)域id田轧、txt記錄的id暴匠。
domain="ip4p.s******n.online"
zone="e7***************************fb"
txt_id="a19***********************8a06"
email="****@qq.com"
key="f9*****************1b"
echo "change txt record"
#base64 encode
addr_64=$(echo -n ${ipAddr} | base64)
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone/dns_records/$txt_id" \
-H "X-Auth-Email: $email" -H "X-Auth-Key: $key" \
-H "Content-Type: application/json" \
--data '{"type":"TXT","name":"'$domain'","content":"'$addr_64'","ttl":60,"proxied":false}'
然后編輯穿透規(guī)則,開啟自定義腳本觸發(fā)涯鲁,把它粘貼到自定義腳本中巷查。
第二步剩余內容已經過時有序,僅留作記錄,請?zhí)恋谌?/p>
配置腳本
Lucky從2.5.1起岛请,支持STUN地址改變時調用腳本旭寿,本節(jié)內容失效。
在第二期創(chuàng)建的webhook服務器的腳本目錄下創(chuàng)建frp.sh崇败,并填入Cloudflare的郵箱盅称、Global API key、區(qū)域id后室、txt記錄的id缩膝。我的ip4p.s********n.online
域名除了txt記錄外,還添加了ip4p的aaaa記錄岸霹;如果你需要疾层,請仿照上一步手動添加一條aaaa記錄,并填入這條記錄的id贡避,如果不需要那就把對應的部分注釋掉痛黎。
#!/bin/bash
# param is ip,port,addr
domain="ip4p.s********n.online"
zone="e7***************************************fb"
ip4p_id="96************************************1b93"
txt_id="a19*********************************8a06"
email="******@qq.com"
key="f9*************************1b"
echo "change ip4p record"
array=(${ip//./ })
ip4p=2001::$(printf '%x:%x%x:%x%x\n' $port ${array[0]} ${array[1]} ${array[2]} ${array[3]})
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone/dns_records/$ip4p_id" \
-H "X-Auth-Email:$email" -H "X-Auth-Key:$key" \
-H "Content-Type: application/json" \
--data '{"type":"AAAA","name":"'$domain'","content":"'$ip4p'","ttl":60,"proxied":false}'
echo ""
echo "change txt record"
# base64 encode
addr_64=$(echo -n $addr | base64)
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone/dns_records/$txt_id" \
-H "X-Auth-Email:$email" -H "X-Auth-Key:$key" \
-H "Content-Type: application/json" \
--data '{"type":"TXT","name":"'$domain'","content":"'$addr_64'","ttl":60,"proxied":false}'
在Lucky中設置webhook
Lucky從2.5.1起,支持STUN地址改變時調用腳本刮吧,本節(jié)內容失效湖饱。
打開Lucky后臺,編輯stun的穿透規(guī)則杀捻,打開webhook井厌,將接口地址設置為http://webhookd的ip地址:wenhookd的端口/frp?ip=#{ip}&port=#{port}&addr=#{ipAddr}
(webhook服務器地址、端口和腳本名稱根據實際情況來)致讥,接口調用成功包含的字符串填"success":true
仅仆。
第三步 在異地電腦上配置frpc
異地電腦上的frpc必須使用魔改版,如需解析txt記錄拄踪,可以使用我改的版本蝇恶,但我只在Windows上編譯過,其它平臺請自行編譯惶桐。
配置frpc.ini
修改frpc.ini
撮弧,server_addr
填添加了ip4p或TXT記錄的域名,server_port
不用填姚糊,建議指定dns_server
贿衍。
[common]
server_addr = ip4p.s******n.online
token = your_token
dns_server = 8.8.8.8
# jellyfin
[vst_jellyfin]
type = stcp
role = visitor
server_name = svc_jellyfin
sk = B9jNFfUy3hDrmi
bind_ip = 127.0.0.1
bind_port = 38096
use_compression = true
# nginx
[vst_nginx]
type = stcp
role = visitor
server_name = svc_nginx
sk = x5Y6f8VBbXQ5NY
bind_ip = 127.0.0.1
bind_port = 18443
use_compression = true
# teamspeak
[vst_ts1]
type = sudp
role = visitor
server_name = svc_ts1
sk = khgtqgyCk3u3JZ
bind_ip = 127.0.0.1
bind_port = 9987
use_compression = false
[vst_ts2]
type = stcp
role = visitor
server_name = svc_ts2
sk = khgtqgyCk3u3JZ
bind_ip = 127.0.0.1
bind_port = 10011
use_compression = true
[vst_ts3]
type = stcp
role = visitor
server_name = svc_ts3
sk = khgtqgyCk3u3JZ
bind_ip = 127.0.0.1
bind_port = 30033
use_compression = true
訪問端必須手動指定role
為visitor
,必須指定連接的服務端名稱server_name
救恨,并且sk
應與服務端相同贸辈。
如果bind_ip
填為127.0.0.1
,則僅有本設備能訪問肠槽。若想讓其它設備訪問擎淤,則填為0.0.0.0
奢啥。
在Windows上將frpc注冊為服務
這一步面向零基礎使用者。(也就是你的小白朋友)
先嘗試運行一次
打開frpc.exe所在文件夾嘴拢,在資源管理器空白處右鍵
- 打開命令提示符
桩盲。
輸入.\frpc.exe
并按下回車。如果沒有出現錯誤席吴,可以嘗試訪問所有的服務赌结。
如果發(fā)現有的服務訪問不上,打開frpc.ini
孝冒,找那個服務到對應的bind_port
柬姚,記下這個數字。
創(chuàng)建文件檢查端口是否占用.ps1
庄涡,代碼如下量承。右鍵
- 使用PowerShell運行
while(1)
{
$port = Read-Host "請輸入需要查詢的端口,輸入0退出:"
IF ($port -eq 0) {exit}
$res=$(Get-NetTCPConnection | ? {$_.LocalPort -eq $port})
if ($res){
echo $res
Get-Process -Id (Get-NetTCPConnection -LocalPort $port).OwningProcess
}
else {echo "未被占用"}
}
你可以輸入剛才記下的數字,查看該端口是否被占用啼染、被什么程序占用宴合,然后選擇關閉該程序或者選擇另一個沒有被占用的端口(1025-65535之間)焕梅。
一旦關閉命令提示符窗口迹鹅,frpc就會關閉。
注冊服務
可以使用nssm將程序注冊為服務贞言。
先將frpc關閉斜棚。在資源管理器中打開nssm.exe
所在目錄。32位系統打開win32
目錄该窗,64位系統打開win64
目錄弟蚀。
在資源管理器空白處右鍵
- 打開命令提示符
,輸入.\nssm.exe install frpc
酗失。
會彈出NSSM service installer窗口义钉,Application Path
選擇frpc.exe
,Startup directory
選擇frpc.exe所在目錄规肴,Arugments不填捶闸,點擊Install service。
在任務管理器
- 服務
- 打開服務
彈出窗口中找到frpc拖刃。右鍵frpc删壮,點擊屬性
,將啟動類型改為自動兑牡,并點擊確定
央碟。再右鍵frpc,點擊啟動
均函。
魔改版frp使用問題總結
如果你的應用強制要求https連接(如BitWarden)亿虽,可以在frp中添加反向代理的端口菱涤,并在異地電腦上修改hosts劫持域名。
我尚未解決的問題記錄如下:
- 我嘗試讓frp使用QUIC協議洛勉,訪問端可以連接到服務端狸窘,可以ping通,但是幾乎收不到包坯认;
- 部分常用第三方遠程桌面無法正常使用(moonlight可以)
- RustDesk的ID服務器可以連接翻擒,但是中繼服務器無法連接;
- parsec無法打洞(不過我也不覺得能成功)牛哺。
- 安卓手機若無root陋气,開了穿透軟件就無法魔法上網。
結語
至此引润,我們補上了STUN內網穿透的最后一塊拼圖巩趁,基本解決了大內網環(huán)境下的所有痛點,近似達到了擁有公網ip的效果淳附。但使用體驗仍不能稱得上完美议慰,期待之后能有更好的方案出現。