Ubuntu和Centos系統frp內網穿透詳細教程

簡介

frp 是一個可用於內網穿透的高性能的反向代理應用,支持 tcp, udp 協議,爲 http 和 https 應用協議提供了額外的能力,且嘗試性支持了點對點穿透。

一、架構

architecture

二、使用示例

根據對應的操作系統及架構,從 Release 頁面下載最新版本的程序。

或者使用下面這樣的命令:

wget https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz

下載完成後解壓:

tar -xvf frp_0.29.0_linux_amd64.tar.gz

frpsfrps.ini放到具有公網 IP 的機器上。

frpcfrpc.ini放到處於內網環境的機器上。

①通過 ssh 訪問公司內網機器

  1. 修改 frps.ini文件,這裏使用了最簡化的配置:
# frps.ini
[common]
bind_port = 7000
  1. 啓動 frps
./frps -c ./frps.ini
  1. 修改 frpc.ini文件,假設 frps所在服務器的公網 IP 爲 x.x.x.x
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
  1. 啓動 frpc:
./frpc -c ./frpc.ini
  1. 通過 ssh 訪問內網機器,假設用戶名爲 test
ssh -oPort=6000 [email protected]

②通過自定義域名訪問部署於內網的 web 服務

有時想要讓其他人通過域名訪問或者測試我們在本地搭建的 web 服務,但是由於本地機器沒有公網 IP,無法將域名解析到本地的機器,通過 frp 就可以實現這一功能,以下示例爲 http服務,https服務配置方法相同, vhost_http_port替換爲 vhost_https_porttype設置爲 https即可。

  1. 修改 frps.ini文件,設置 http訪問端口爲 8080
# frps.ini
[common]
bind_port = 7000
vhost_http_port = 8080
  1. 啓動 frps
./frps -c ./frps.ini
  1. 修改 frpc.ini文件,假設frps所在的服務器的 IP 爲 x.x.x.xlocal_port爲本地機器上 web 服務對應的端口, 綁定自定義域名 www.yourdomain.com:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[web]
type = http
local_port = 80
custom_domains = www.yourdomain.com
  1. 啓動 frpc:
./frpc -c ./frpc.ini
  1. www.yourdomain.com的域名 A記錄解析到 IP x.x.x.x,如果服務器已經有對應的域名,也可以將 CNAME記錄解析到服務器原先的域名。

  2. 通過瀏覽器訪問 http://www.yourdomain.com:8080即可訪問到處於內網機器上的 web 服務。

③轉發 DNS 查詢請求

DNS 查詢請求通常使用 UDP協議,frp 支持對內網 UDP服務的穿透,配置方式和 TCP基本一致。

  1. 修改 frps.ini文件:
# frps.ini
[common]
bind_port = 7000
  1. 啓動 frps:
./frps -c ./frps.ini
  1. 修改 frpc.ini文件,設置 frps所在服務器的 IPx.x.x.x,轉發到 Google 的 DNS 查詢服務器 8.8.8.8udp 53端口:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[dns]
type = udp
local_ip = 8.8.8.8
local_port = 53
remote_port = 6000
  1. 啓動 frpc
./frpc -c ./frpc.ini
  1. 通過 dig測試 UDP包轉發是否成功,預期會返回 www.google.com域名的解析結果:
dig @x.x.x.x -p 6000 www.google.com

④轉發 Unix 域套接字

通過 tcp 端口訪問內網的 unix域套接字(例如和 docker daemon 通信)。

frps的部署步驟同上。

  1. 啓動 frpc,啓用 unix_domain_socket插件,配置如下:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[unix_domain_socket]
type = tcp
remote_port = 6000
plugin = unix_domain_socket
plugin_unix_path = /var/run/docker.sock
  1. 通過 curl命令查看 docker 版本信息
curl http://x.x.x.x:6000/version

⑤對外提供簡單的文件訪問服務

通過 static_file插件可以對外提供一個簡單的基於 HTTP 的文件訪問服務。

frps的部署步驟同上。

  1. 啓動 frpc,啓用 static_file插件,配置如下:
# frpc.ini
[common]
server_addr = x.x.x.x
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
  1. 通過瀏覽器訪問 http://x.x.x.x:6000/static/來查看位於 /tmp/file目錄下的文件,會要求輸入已設置好的用戶名和密碼。

⑥爲本地 HTTP 服務啓用 HTTPS

通過 https2http插件可以讓本地 HTTP服務轉換成 HTTPS服務對外提供。

  1. 啓用 frpc,啓用 https2http插件,配置如下:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[test_htts2http]
type = https
custom_domains = test.yourdomain.com

plugin = https2http
plugin_local_addr = 127.0.0.1:80

# HTTPS 證書相關的配置
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp
  1. 通過瀏覽器訪問 https://test.yourdomain.com即可。

⑦安全地暴露內網服務

對於某些服務來說如果直接暴露於公網上將會存在安全隱患。

使用 stcp(secret tcp)類型的代理可以避免讓任何人都能訪問到要穿透的服務,但是訪問者也需要運行另外一個 frpc

以下示例將會創建一個只有自己能訪問到的 ssh 服務代理。

frps的部署步驟同上。

  1. 啓動 frpc,轉發內網的 ssh服務,配置如下,不需要指定遠程端口:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[secret_ssh]
type = stcp
# 只有 sk 一致的用戶才能訪問到此服務
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
  1. 在要訪問這個服務的機器上啓動另外一個frpc,配置如下:
# frpc.ini
[common]
server_addr = x.x.x.x
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
  1. 通過 ssh訪問內網機器,假設用戶名爲 test
ssh -oPort=6000 [email protected]

⑧點對點內網穿透

frp提供了一種新的代理類型 xtcp用於應對在希望傳輸大量數據且流量不經過服務器的場景。

使用方式同 stcp類似,需要在兩邊都部署上 frpc用於建立直接的連接。

目前處於開發的初級階段,並不能穿透所有類型的 NAT設備,所以穿透成功率較低。穿透失敗時可以嘗試 stcp的方式。

  1. frps除正常配置外需要額外配置一個 udp端口用於支持該類型的客戶端:
bind_udp_port = 7001
  1. 啓動 frpc,轉發內網的 ssh 服務,配置如下,不需要指定遠程端口:
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[p2p_ssh]
type = xtcp
# 只有 sk 一致的用戶才能訪問到此服務
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
  1. 在要訪問這個服務的機器上啓動另外一個 frpc,配置如下:
# frpc.ini
[common]
server_addr = x.x.x.x
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
  1. 通過 ssh訪問內網機器,假設用戶名爲 test:
ssh -oPort=6000 [email protected]

三、功能說明

1. 配置文件

由於 frp目前支持的功能和配置項較多,未在文檔中列出的功能可以從完整的示例配置文件中發現。

frps完整配置文件

frpc 完整配置文件

2. 配置文件模版渲染

配置文件支持使用系統環境變量進行模版渲染,模版格式採用 Go 的標準格式。

示例配置如下:

# frpc.ini
[common]
server_addr = {{ .Envs.FRP_SERVER_ADDR }}
server_port = 7000

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = {{ .Envs.FRP_SSH_REMOTE_PORT }}

啓動 frpc 程序:

export FRP_SERVER_ADDR="x.x.x.x"
export FRP_SSH_REMOTE_PORT="6000"
./frpc -c ./frpc.ini

frpc會自動使用環境變量渲染配置文件模版,所有環境變量需要以 .Envs爲前綴。

3. Dashboard

通過瀏覽器查看 frp的狀態以及代理統計信息展示。

注:Dashboard 尚未針對大量的 proxy 數據展示做優化,如果出現 Dashboard 訪問較慢的情況,請不要啓用此功能。

需要在 frps.ini中指定 dashboard服務使用的端口,即可開啓此功能:

[common]
dashboard_port = 7500
# dashboard 用戶名密碼,默認都爲 admin
dashboard_user = admin
dashboard_pwd = admin

打開瀏覽器通過http://[server_addr]:7500訪問 dashboard界面,用戶名密碼默認爲 admin

dashboard

4. Admin UI

Admin UI可以幫助用戶通過瀏覽器來查詢和管理客戶端的 proxy狀態和配置。

需要在 frpc.ini中指定 admin服務使用的端口,即可開啓此功能:

[common]
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_pwd = admin

打開瀏覽器通過 http://127.0.0.1:7400訪問 Admin UI,用戶名密碼默認爲 admin

如果想要在外網環境訪問 Admin UI,將 7400端口映射出去即可,但需要重視安全風險。

5. 身份驗證

服務端和客戶端的 common配置中的 token參數一致則身份驗證通過。

6. 加密與壓縮

這兩個功能默認是不開啓的,需要在 frpc.ini中通過配置來爲指定的代理啓用加密與壓縮的功能,壓縮算法使用 snappy

# frpc.ini
[ssh]
type = tcp
local_port = 22
remote_port = 6000
use_encryption = true
use_compression = true

如果公司內網防火牆對外網訪問進行了流量識別與屏蔽,例如禁止了 ssh協議等,通過設置 use_encryption = true,將 frpcfrps之間的通信內容加密傳輸,將會有效防止流量被攔截。

如果傳輸的報文長度較長,通過設置 use_compression = true對傳輸內容進行壓縮,可以有效減小 frpcfrps之間的網絡流量,加快流量轉發速度,但是會額外消耗一些 cpu 資源。

TLS

從 v0.25.0 版本開始 frpcfrps之間支持通過 TLS 協議加密傳輸。通過在 frpc.inicommon中配置 tls_enable = true來啓用此功能,安全性更高。

爲了端口複用,frp建立 TLS 連接的第一個字節爲 0x17

注意: 啓用此功能後除 xtcp外,不需要再設置 use_encryption

7. 客戶端熱加載配置文件

當修改了 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 外目前無法被修改。

8. 客戶端查看代理狀態

frpc支持通過 frpc status -c ./frpc.ini命令查看代理的狀態信息,此功能需要在 frpc中配置 admin端口。

9. 端口白名單

爲了防止端口被濫用,可以手動指定允許哪些端口被使用,在 frps.ini中通過 allow_ports來指定:

# frps.ini
[common]
allow_ports = 2000-3000,3001,3003,4000-50000

allow_ports可以配置允許使用的某個指定端口或者是一個範圍內的所有端口,以 ,分隔,指定的範圍以 -分隔。

10. 端口複用

目前 frps中的 vhost_http_portvhost_https_port支持配置成和bind_port爲同一個端口,frps會對連接的協議進行分析,之後進行不同的處理。

例如在某些限制較嚴格的網絡環境中,可以將 bind_portvhost_https_port都設置爲 443

後續會嘗試允許多個 proxy綁定同一個遠端端口的不同協議。

11. TCP 多路複用

從 v0.10.0 版本開始,客戶端和服務器端之間的連接支持多路複用,不再需要爲每一個用戶請求創建一個連接,使連接建立的延遲降低,並且避免了大量文件描述符的佔用,使 frp可以承載更高的併發數。

該功能默認啓用,如需關閉,可以在 frps.inifrpc.ini中配置,該配置項在服務端和客戶端必須一致:

# frps.ini 和 frpc.ini 中
[common]
tcp_mux = false

12. 底層通信可選 kcp 協議

底層通信協議支持選擇 kcp 協議,在弱網環境下傳輸效率提升明顯,但是會有一些額外的流量消耗。

開啓 kcp 協議支持:

  1. 在 frps.ini 中啓用 kcp 協議支持,指定一個 udp 端口用於接收客戶端請求:
# frps.ini
[common]
bind_port = 7000
# kcp 綁定的是 udp 端口,可以和 bind_port 一樣
kcp_bind_port = 7000
  1. 在 frpc.ini 指定需要使用的協議類型,目前只支持 tcp 和 kcp。其他代理配置不需要變更:
# frpc.ini
[common]
server_addr = x.x.x.x
# server_port 指定爲 frps 的 kcp_bind_port
server_port = 7000
protocol = kcp
  1. 像之前一樣使用 frp,需要注意開放相關機器上的 udp 的端口的訪問權限。

13. 連接池

默認情況下,當用戶請求建立連接後,frps纔會請求 frpc主動與後端服務建立一個連接。當爲指定的代理啓用連接池後,frp 會預先和後端服務建立起指定數量的連接,每次接收到用戶請求後,會從連接池中取出一個連接和用戶連接關聯起來,避免了等待與後端服務建立連接以及 frpcfrps之間傳遞控制信息的時間。

這一功能比較適合有大量短連接請求時開啓。

  1. 首先可以在 frps.ini 中設置每個代理可以創建的連接池上限,避免大量資源佔用,客戶端設置超過此配置後會被調整到當前值:
# frps.ini
[common]
max_pool_count = 5
在 frpc.ini 中爲客戶端啓用連接池,指定預創建連接的數量:
# frpc.ini
[common]
pool_count = 1

14. 負載均衡

可以將多個相同類型的 proxy 加入到同一個 group 中,從而實現負載均衡的功能。

目前只支持 TCP 和 HTTP 類型的 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機器掛掉後仍然有其他節點能夠提供服務。

TCP類型代理要求 group_key相同,做權限驗證,且 remote_port相同。

HTTP類型代理要求 group_key, custom_domainssubdomainlocations相同。

15. 健康檢查

通過給 proxy加上健康檢查的功能,可以在要反向代理的服務出現故障時,將這個服務從 frps中摘除,搭配負載均衡的功能,可以用來實現高可用的架構,避免服務單點故障。

在每一個 proxy的配置下加上 health_check_type = {type}來啓用健康檢查功能。

type目前可選 tcphttp

tcp只要能夠建立連接則認爲服務正常,http會發送一個 http請求,服務需要返回 2xx的狀態碼纔會被認爲正常。

tcp 示例配置如下:

# frpc.ini
[test1]
type = tcp
local_port = 22
remote_port = 6000
# 啓用健康檢查,類型爲 tcp
health_check_type = tcp
# 建立連接超時時間爲 3 秒
health_check_timeout_s = 3
# 連續 3 次檢查失敗,此 proxy 會被摘除
health_check_max_failed = 3
# 每隔 10 秒進行一次健康檢查
health_check_interval_s = 10

http 示例配置如下:

# frpc.ini
[web]
type = http
local_ip = 127.0.0.1
local_port = 80
custom_domains = test.yourdomain.com
# 啓用健康檢查,類型爲 http
health_check_type = http
# 健康檢查發送 http 請求的 url,後端服務需要返回 2xx 的 http 狀態碼
health_check_url = /status
health_check_interval_s = 10
health_check_max_failed = 3
health_check_timeout_s = 3

16. 修改 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

17. 設置 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

18. 獲取用戶真實 IP

HTTP X-Forwarded-For

目前只有 http類型的代理支持這一功能,可以通過用戶請求的 header中的 X-Forwarded-For來獲取用戶真實 IP,默認啓用。

Proxy Protocol

frp支持通過 Proxy Protocol協議來傳遞經過 frp代理的請求的真實 IP,此功能支持所有以 TCP爲底層協議的類型,不支持 UDP

Proxy Protocol功能啓用後,frpc在和本地服務建立連接後,會先發送一段 Proxy Protocol的協議內容給本地服務,本地服務通過解析這一內容可以獲得訪問用戶的真實 IP。所以不僅僅是 HTTP服務,任何的 TCP服務,只要支持這一協議,都可以獲得用戶的真實 IP 地址。

需要注意的是,在代理配置中如果要啓用此功能,需要本地的服務能夠支持 Proxy Protocol這一協議,目前 nginxhaproxy都能夠很好的支持。

這裏以 https 類型爲例:

# frpc.ini
[web]
type = https
local_port = 443
custom_domains = test.yourdomain.com

# 目前支持 v1 和 v2 兩個版本的 proxy protocol 協議。
proxy_protocol_version = v2

只需要在代理配置中增加一行 proxy_protocol_version = v2即可開啓此功能。

本地的 https服務可以通過在 nginx的配置中啓用 Proxy Protocol的解析並將結果設置在 X-Real-IP這個 Header中就可以在自己的 Web 服務中通過 X-Real-IP獲取到用戶的真實 IP。

19. 通過密碼保護你的 web 服務

由於所有客戶端共用一個 frpshttp服務端口,任何知道你的域名和 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,需要輸入配置的用戶名和密碼才能訪問。

20. 自定義二級域名

在多人同時使用一個 frps時,通過自定義二級域名的方式來使用會更加方便。

通過在 frps的配置文件中配置 subdomain_host,就可以啓用該特性。之後在 frpchttphttps類型的代理中可以不配置 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

frpsfrpc都啓動成功後,通過 test.frps.com就可以訪問到內網的 web 服務。

注:如果 frps配置了 subdomain_host,則 custom_domains中不能是屬於 subdomain_host的子域名或者泛域名。

同一個 httphttps類型的代理中 custom_domainssubdomain可以同時配置。

21. 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

22. 通過代理連接 frps

在只能通過代理訪問外網的環境內,frpc支持通過 HTTP PROXYfrps進行通信。

可以通過設置 HTTP_PROXY系統環境變量或者通過在 frpc的配置文件中設置 http_proxy參數來使用此功能。

僅在 protocol = tcp時生效。

# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000
http_proxy = http://user:[email protected]:8080

23. 範圍端口映射

frpc的配置文件中可以指定映射多個端口,目前只支持 tcpudp的類型。

這一功能通過 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

24. 插件

默認情況下,frpc只會轉發請求到本地 tcpudp端口。

插件模式是爲了在客戶端提供更加豐富的功能,目前內置的插件有 unix_domain_sockethttp_proxysocks5static_file。具體使用方式請查看使用示例。

通過 plugin指定需要使用的插件,插件的配置參數都以 plugin_開頭。使用插件後 local_iplocal_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_userplugin_http_passwd即爲 http_proxy插件可選的配置參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章