FRP內網穿透工具+配置教程
GitHub地址:https://github.com/fatedier/frp
FRP工具下載地址:https://github.com/fatedier/frp/releases
frp 是一個可用於內網穿透的高性能的反向代理應用,支持tcp, udp, http, https 協議。
配置教程
frp 的作用
利用處於內網或防火牆後的機器,對外網環境提供http或https服務。
對於http, https服務支持基於域名的虛擬主機,支持自定義域名綁定,使多個域名可以共用一個80端口。
利用處於內網或防火牆後的機器,對外網環境提供tcp和udp服務,例如在家里通過ssh訪問處於公司內網環境內的主機。
開發狀態
frp 仍然處於前期開發階段,未經充分測試與驗證,不推薦用於生產環境。
master 分支用於發布穩定版本,dev 分支用於開發,您可以嘗試下載最新的release 版本進行測試。
目前的交互協議可能隨時改變,不保證向後兼容,升級新版本時需要注意公告說明同時升級服務端和客戶端。
架構
使用示例
根據對應的操作系統及架構,從Release頁面下載最新版本的程序。
將frps及frps.ini放到具有公網IP的機器上。
將frpc及frpc.ini放到處於內網環境的機器上。
通過ssh 訪問公司內網機器
- 修改frps.ini 文件,這裡使用了最簡化的配置:
# frps.ini [common] bind_port = 7000
- 啟動frps:
./frps -c ./frps.ini
- 修改frpc.ini 文件,假設frps 所在服務器的公網IP 為xxxx;
# frpc.ini [common] server_addr = xxxx server_port = 7000 [ssh] type = tcp local_ip = 127.0.0.1 local_port = 22 remote_port = 6000
- 啟動frpc:
./frpc -c ./frpc.ini
- 通過ssh 訪問內網機器,假設用戶名為test:
ssh -oPort=6000 test@x.x.x.x
通過自定義域名訪問部署於內網的web 服務
有時想要讓其他人通過域名訪問或者測試我們在本地搭建的web 服務,但是由於本地機器沒有公網IP,無法將域名解析到本地的機器,通過frp 就可以實現這一功能,以下示例為http服務,https 服務配置方法相同, vhost_http_port 替換為vhost_https_port, type 設置為https 即可。
- 修改frps.ini 文件,設置http 訪問端口為8080:
# frps.ini [common] bind_port = 7000 vhost_http_port = 8080
- 啟動frps;
./frps -c ./frps.ini
- 修改frpc.ini文件,假設frps所在的服務器的IP為xxxx,local_port為本地機器上web服務對應的端口,綁定自定義域名
www.yourdomain.com
:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [web] type = http local_port = 80 custom_domains = www.yourdomain.com
- 啟動frpc:
./frpc -c ./frpc.ini
- 將
www.yourdomain.com
的域名A記錄解析到IPx.x.x.x
,如果服務器已經有對應的域名,也可以將CNAME記錄解析到服務器原先的域名。 - 通過瀏覽器訪問
http://www.yourdomain.com:8080
即可訪問到處於內網機器上的web服務。
轉發DNS 查詢請求
DNS 查詢請求通常使用UDP 協議,frp 支持對內網UDP 服務的穿透,配置方式和TCP 基本一致。
- 修改frps.ini 文件:
# frps.ini [common] bind_port = 7000
- 啟動frps:
./frps -c ./frps.ini
- 修改frpc.ini文件,設置frps所在服務器的IP為xxxx,轉發到Google的DNS查詢服務器
8.8.8.8
的udp 53端口:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [dns] type = udp local_ip = 8.8.8.8 local_port = 53 remote_port = 6000
- 啟動frpc:
./frpc -c ./frpc.ini
- 通過dig測試UDP包轉發是否成功,預期會返回
www.google.com
域名的解析結果:
dig @x.x.x.x -p 6000 www.google.com
轉發Unix域套接字
通過tcp 端口訪問內網的unix域套接字(例如和docker daemon 通信)。
frps 的部署步驟同上。
- 啟動frpc,啟用
unix_domain_socket
插件,配置如下:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [unix_domain_socket] type = tcp remote_port = 6000 plugin = unix_domain_socket plugin_unix_path = /var/run/docker.sock
- 通過curl 命令查看docker 版本信息
curl http://x.x.x.x:6000/version
對外提供簡單的文件訪問服務
通過static_file
插件可以對外提供一個簡單的基於HTTP的文件訪問服務。
frps 的部署步驟同上。
- 啟動frpc,啟用
static_file
插件,配置如下:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [test_static_file] type = tcp remote_port = 6000 plugin = static_file #要對外暴露的文件目錄 plugin_local_path = /tmp/file #訪問url中會被去除的前綴,保留的內容即為要訪問的文件路徑 plugin_strip_prefix = static plugin_http_user = abc plugin_http_passwd = abc
- 通過瀏覽器訪問
http://x.x.x.x:6000/static/
來查看位於/tmp/file
目錄下的文件,會要求輸入已設置好的用戶名和密碼。
安全地暴露內網服務
對於某些服務來說如果直接暴露於公網上將會存在安全隱患。
使用stcp(secret tcp)類型的代理可以避免讓任何人都能訪問到要穿透的服務,但是訪問者也需要運行另外一個frpc。
以下示例將會創建一個只有自己能訪問到的ssh 服務代理。
frps 的部署步驟同上。
- 啟動frpc,轉發內網的ssh 服務,配置如下,不需要指定遠程端口:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [secret_ssh] type = stcp #只有sk一致的用戶才能訪問到此服務 sk = abcdefg local_ip = 127.0.0.1 local_port = 22
- 在要訪問這個服務的機器上啟動另外一個frpc,配置如下:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [secret_ssh_visitor] type = stcp # stcp的訪問者 role = visitor #要訪問的stcp代理的名字 server_name = secret_ssh sk = abcdefg #綁定本地端口用於訪問ssh服務 bind_addr = 127.0.0.1 bind_port = 6000
- 通過ssh 訪問內網機器,假設用戶名為test:
ssh -oPort=6000 test@127.0.0.1
點對點內網穿透
frp提供了一種新的代理類型xtcp用於應對在希望傳輸大量數據且流量不經過服務器的場景。
使用方式同stcp類似,需要在兩邊都部署上frpc用於建立直接的連接。
目前處於開發的初級階段,並不能穿透所有類型的NAT設備,所以穿透成功率較低。穿透失敗時可以嘗試stcp的方式。
- frps 除正常配置外需要額外配置一個udp 端口用於支持該類型的客戶端:
bind_udp_port = 7001
- 啟動frpc,轉發內網的ssh 服務,配置如下,不需要指定遠程端口:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [p2p_ssh] type = xtcp #只有sk一致的用戶才能訪問到此服務 sk = abcdefg local_ip = 127.0.0.1 local_port = 22
- 在要訪問這個服務的機器上啟動另外一個frpc,配置如下:
# frpc.ini [common] server_addr = xxxx server_port = 7000 [p2p_ssh_visitor] type = xtcp # xtcp的訪問者 role = visitor #要訪問的xtcp代理的名字 server_name = p2p_ssh sk = abcdefg #綁定本地端口用於訪問ssh服務 bind_addr = 127.0.0.1 bind_port = 6000
- 通過ssh 訪問內網機器,假設用戶名為test:
ssh -oPort=6000 test@127.0.0.1
功能說明
配置文件
由於frp 目前支持的功能和配置項較多,未在文檔中列出的功能可以從完整的示例配置文件中發現。
Dashboard
通過瀏覽器查看frp 的狀態以及代理統計信息展示。
需要在frps.ini 中指定dashboard 服務使用的端口,即可開啟此功能:
[common] dashboard_port = 7500 # dashboard用戶名密碼,默認都為admin dashboard_user = admin dashboard_pwd = admin
打開瀏覽器通過http://[server_addr]:7500
訪問dashboard界面,用戶名密碼默認為admin
。
身份驗證
從v0.10.0版本開始,所有proxy配置全部放在客戶端(也就是之前版本的特權模式),服務端和客戶端的common配置中的token
參數一致則身份驗證通過。
需要注意的是frpc 所在機器和frps 所在機器的時間相差不能超過15 分鐘,因為時間戳會被用於加密驗證中,防止報文被劫持後被其他人利用。
這個超時時間可以在配置文件中通過authentication_timeout
這個參數來修改,單位為秒,默認值為900,即15分鐘。如果修改為0,則frps將不對身份驗證報文的時間戳進行超時校驗。
加密與壓縮
這兩個功能默認是不開啟的,需要在frpc.ini 中通過配置來為指定的代理啟用加密與壓縮的功能,壓縮算法使用snappy:
# frpc.ini [ssh] type = tcp local_port = 22 remote_port = 6000 use_encryption = true use_compression = true
如果公司內網防火牆對外網訪問進行了流量識別與屏蔽,例如禁止了ssh協議等,通過設置use_encryption = true
,將frpc與frps之間的通信內容加密傳輸,將會有效防止流量被攔截。
如果傳輸的報文長度較長,通過設置use_compression = true
對傳輸內容進行壓縮,可以有效減小frpc與frps之間的網絡流量,加快流量轉發速度,但是會額外消耗一些cpu資源。
客戶端熱加載配置文件
當修改了frpc中的代理配置,可以通過frpc reload
命令來動態加載配置文件,通常會在10秒內完成代理的更新。
啟用此功能需要在frpc 中啟用admin 端口,用於提供API 服務。配置如下:
# frpc.ini [common] admin_addr = 127.0.0.1 admin_port = 7400
之後執行重啟命令:
frpc reload -c ./frpc.ini
等待一段時間後客戶端會根據新的配置文件創建、更新、刪除代理。
需要注意的是,[common] 中的參數除了start 外目前無法被修改。
客戶端查看代理狀態
frpc支持通過frpc status -c ./frpc.ini
命令查看代理的狀態信息,此功能需要在frpc中配置admin端口。
端口白名單
為了防止端口被濫用,可以手動指定允許哪些端口被使用,在frps.ini中通過allow_ports
來指定:
# frps.ini [common] allow_ports = 2000-3000,3001,3003,4000-50000
allow_ports
可以配置允許使用的某個指定端口或者是一個範圍內的所有端口,以,
分隔,指定的範圍以-
分隔。
端口復用
目前frps中的vhost_http_port
和vhost_https_port
支持配置成和bind_port
為同一個端口,frps會對連接的協議進行分析,之後進行不同的處理。
例如在某些限制較嚴格的網絡環境中,可以將bind_port
和vhost_https_port
都設置為443。
後續會嘗試允許多個proxy 綁定同一個遠端端口的不同協議。
TCP 多路復用
從v0.10.0 版本開始,客戶端和服務器端之間的連接支持多路復用,不再需要為每一個用戶請求創建一個連接,使連接建立的延遲降低,並且避免了大量文件描述符的佔用,使frp 可以承載更高的並發數。
該功能默認啟用,如需關閉,可以在frps.ini 和frpc.ini 中配置,該配置項在服務端和客戶端必須一致:
# frps.ini和frpc.ini中 [common] tcp_mux = false
底層通信可選kcp 協議
從v0.12.0 版本開始,底層通信協議支持選擇kcp 協議,在弱網環境下傳輸效率提昇明顯,但是會有一些額外的流量消耗。
開啟kcp 協議支持:
- 在frps.ini 中啟用kcp 協議支持,指定一個udp 端口用於接收客戶端請求:
# frps.ini [common] bind_port = 7000 # kcp綁定的是udp端口,可以和bind_port一樣 kcp_bind_port = 7000
- 在frpc.ini 指定需要使用的協議類型,目前只支持tcp 和kcp。其他代理配置不需要變更:
# frpc.ini [common] server_addr = xxxx # server_port指定為frps的kcp_bind_port server_port = 7000 protocol = kcp
- 像之前一樣使用frp,需要注意開放相關機器上的udp 的端口的訪問權限。
連接池
默認情況下,當用戶請求建立連接後,frps 才會請求frpc 主動與後端服務建立一個連接。當為指定的代理啟用連接池後,frp 會預先和後端服務建立起指定數量的連接,每次接收到用戶請求後,會從連接池中取出一個連接和用戶連接關聯起來,避免了等待與後端服務建立連接以及frpc 和frps 之間傳遞控制信息的時間。
這一功能比較適合有大量短連接請求時開啟。
- 首先可以在frps.ini 中設置每個代理可以創建的連接池上限,避免大量資源佔用,客戶端設置超過此配置後會被調整到當前值:
# frps.ini [common] max_pool_count = 5
- 在frpc.ini 中為客戶端啟用連接池,指定預創建連接的數量:
# frpc.ini [common] pool_count = 1
負載均衡
可以將多個相同類型的proxy 加入到同一個group 中,從而實現負載均衡的功能。目前只支持tcp 類型的proxy。
# frpc.ini [test1] type = tcp local_port = 8080 remote_port = 80 group = web group_key = 123 [test2] type = tcp local_port = 8081 remote_port = 80 group = web group_key = 123
用戶連接frps 服務器的80 端口,frps 會將接收到的用戶連接隨機分發給其中一個存活的proxy。這樣可以在一台frpc 機器掛掉後仍然有其他節點能夠提供服務。
要求group_key
相同,做權限驗證,且remote_port
相同。
修改Host Header
通常情況下frp 不會修改轉發的任何數據。但有一些後端服務會根據http 請求header 中的host 字段來展現不同的網站,例如nginx 的虛擬主機服務,啟用host-header 的修改功能可以動態修改http 請求中的host 字段。該功能僅限於http 類型的代理。
# frpc.ini [web] type = http local_port = 80 custom_domains = test.yourdomain.com host_header_rewrite = dev.yourdomain.com
原來http請求中的host字段test.yourdomain.com
轉發到後端服務時會被替換為dev.yourdomain.com
。
設置HTTP 請求的header
對於type = http
的代理,可以設置在轉發中動態添加的header參數。
# frpc.ini [web] type = http local_port = 80 custom_domains = test.yourdomain.com host_header_rewrite = dev.yourdomain.com header_X-From-Where = frp
對於參數配置中所有以header_
開頭的參數(支持同時配置多個),都會被添加到http請求的header中,根據如上的配置,會在請求的header中加上X-From-Where: frp
。
獲取用戶真實IP
目前只有http類型的代理支持這一功能,可以通過用戶請求的header中的X-Forwarded-For
和X-Real-IP
來獲取用戶真實IP。
需要注意的是,目前只在每一個用戶連接的第一個HTTP 請求中添加了這兩個header。
通過密碼保護你的web 服務
由於所有客戶端共用一個frps 的http 服務端口,任何知道你的域名和url 的人都能訪問到你部署在內網的web 服務,但是在某些場景下需要確保只有限定的用戶才能訪問。
frp 支持通過HTTP Basic Auth 來保護你的web 服務,使用戶需要通過用戶名和密碼才能訪問到你的服務。
該功能目前僅限於http 類型的代理,需要在frpc 的代理配置中添加用戶名和密碼的設置。
# frpc.ini [web] type = http local_port = 80 custom_domains = test.yourdomain.com http_user = abc http_pwd = abc
通過瀏覽器訪問http://test.yourdomain.com
,需要輸入配置的用戶名和密碼才能訪問。
自定義二級域名
在多人同時使用一個frps 時,通過自定義二級域名的方式來使用會更加方便。
通過在frps的配置文件中配置subdomain_host
,就可以啟用該特性。之後在frpc的http、https類型的代理中可以不配置custom_domains
,而是配置一個subdomain
參數。
只需要將*.{subdomain_host}
解析到frps所在服務器。之後用戶可以通過subdomain
自行指定自己的web服務所需要使用的二級域名,通過{subdomain}.{subdomain_host}
來訪問自己的web服務。
# frps.ini [common] subdomain_host = frps.com
將泛域名*.frps.com
解析到frps所在服務器的IP地址。
# frpc.ini [web] type = http local_port = 80 subdomain = test
frps和frpc都啟動成功後,通過test.frps.com
就可以訪問到內網的web服務。
需要注意的是如果frps配置了subdomain_host
,則custom_domains
中不能是屬於subdomain_host
的子域名或者泛域名。
同一個http或https類型的代理中custom_domains
和subdomain
可以同時配置。
URL 路由
frp 支持根據請求的URL 路徑路由轉發到不同的後端服務。
通過配置文件中的locations
字段指定一個或多個proxy能夠匹配的URL前綴(目前僅支持最大前綴匹配,之後會考慮正則匹配)。例如指定locations = /news
,則所有URL以/news
開頭的請求都會被轉發到這個服務。
# frpc.ini [web01] type = http local_port = 80 custom_domains = web.yourdomain.com locations = / [web02] type = http local_port = 81 custom_domains = web.yourdomain.com locations = /news,/about
按照上述的示例配置後,web.yourdomain.com
這個域名下所有以/news
以及/about
作為前綴的URL請求都會被轉發到web02,其餘的請求會被轉發到web01。
通過代理連接frps
在只能通過代理訪問外網的環境內,frpc 支持通過HTTP PROXY 和frps 進行通信。
可以通過設置HTTP_PROXY
系統環境變量或者通過在frpc的配置文件中設置http_proxy
參數來使用此功能。
僅在protocol = tcp
時生效。
# frpc.ini [common] server_addr = xxxx server_port = 7000 http_proxy = http://user:pwd@192.168.1.128:8080
範圍端口映射
在frpc 的配置文件中可以指定映射多個端口,目前只支持tcp 和udp 的類型。
這一功能通過range:
段落標記來實現,客戶端會解析這個標記中的配置,將其拆分成多個proxy,每一個proxy以數字為後綴命名。
例如要映射本地6000-6005, 6007 這6個端口,主要配置如下:
# frpc.ini [range:test_tcp] type = tcp local_ip = 127.0.0.1 local_port = 6000-6006,6007 remote_port = 6000-6006,6007
實際連接成功後會創建8個proxy,命名為test_tcp_0, test_tcp_1 ... test_tcp_7
。
插件
默認情況下,frpc 只會轉發請求到本地tcp 或udp 端口。
插件模式是為了在客戶端提供更加豐富的功能,目前內置的插件有unix_domain_socket
、http_proxy
、socks5
、static_file
。具體使用方式請查看使用示例。
通過plugin
指定需要使用的插件,插件的配置參數都以plugin_
開頭。使用插件後local_ip
和local_port
不再需要配置。
使用http_proxy插件的示例:
# frpc.ini [http_proxy] type = tcp remote_port = 6000 plugin = http_proxy plugin_http_user = abc plugin_http_passwd = abc
plugin_http_user
和plugin_http_passwd
即為http_proxy
插件可選的配置參數。
開發計劃
計劃在後續版本中加入的功能與優化,排名不分先後,如果有其他功能建議歡迎在issues中反饋。
- frps 記錄http 請求日誌。
- frps 支持直接反向代理,類似haproxy。
- 集成對k8s 等平台的支持。