隧道类型介绍
2 min read
1.1 TCP & UDP #
了解 frp TCP
, UDP
类型的代理。
TCP 和 UDP 是 frp 中两种最基础的代理类型,用于代理监听在 TCP 和 UDP 端口的服务。
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000
通过 type 指定代理类型。
frp 会为本地服务的 22 端口,在 frps 所在的服务端监听 6000 端口,将 6000 端口接收到的连接和本地服务的 22 端口关联,透传流量,从而实现让用户在外部访问到内部服务。
1.2 HTTP & HTTPS #
了解 frp HTTP
, HTTPS
类型的代理。
HTTP 和 HTTPS 是 frp 中针对这两种协议额外提供了一些特殊的能力。本质上目前这两种应用层协议的底层协议都是 TCP。
如果不需要用到相关的特殊功能,可以直接使用 TCP 类型的代理,更加简单方便。
HTTP 和 HTTPS 协议的一个特点是发送的请求都具有 Host 字段,通过该字段描述要访问的服务。基于这个特点,frp 服务端只需要监听在一个端口(通过 vhostHTTPPort
和 vhostHTTPSPort
指定)。就可以根据请求的 Host 来决定需要路由给哪一个代理,而不需要像 TCP 类型那样为每一个服务绑定一个端口。
1.2.1 修改 HTTP 请求 Header #
通常情况下 frp 不会修改转发的任何数据。但有一些后端服务会根据 HTTP 请求 header 中的 Host 字段来展现不同的网站,例如 nginx 的虚拟主机服务,启用 Host Header 的修改功能可以动态修改 HTTP 请求中的 Host 字段。需要注意的是,该功能仅限于 HTTP 类型的代理。
# frpc.toml
[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["test.yourdomain.com"]
hostHeaderRewrite = "dev.yourdomain.com"
原来 HTTP 请求中的 Host 字段 test.yourdomain.com
转发到后端服务时会被替换为 dev.yourdomain.com
。
设置普通 Header
对于类型为 HTTP 的代理,可以设置在转发中动态添加的 Header 参数
# frpc.toml
[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["test.yourdomain.com"]
hostHeaderRewrite = "dev.yourdomain.com"
requestHeaders.set.x-from-where = "frp"
根据如上的配置,会在请求的 Header 中加上 x-from-where: frp
。
1.2.2 设置 BasicAuth 鉴权 #
由于所有客户端共用一个 frps 的 HTTP 服务端口,任何知道你的域名和 URL 的人都能访问到你部署在内网的服务,但是在某些场景下需要确保只有限定的用户才能访问。
frp 支持通过 HTTP Basic Auth 来保护你的 web 服务,使用户需要通过用户名和密码才能访问到你的服务。
该功能目前仅限于 HTTP 类型的代理,需要在 frpc 的代理配置中添加用户名和密码的设置。
# frpc.toml
[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["test.yourdomain.com"]
httpUser = "abc"
httpPassword = "abc"
通过浏览器访问 http://test.yourdomain.com
,需要输入配置的用户名和密码才能访问。
1.2.3 自定义二级域名 #
在多人同时使用一个 frps 时,通过自定义二级域名的方式来使用会更加方便。
通过在 frps 的配置文件中配置 subdomainHost
,就可以启用该特性。之后在 frpc 的 http、https 类型的代理中可以不配置 customDomains
,而是配置一个 subdomain
参数。
只需要将 *.{subdomainHost}
解析到 frps 所在服务器。之后用户可以通过 subdomain 自行指定自己的 web 服务所需要使用的二级域名,通过 {subdomain}.{subdomainHost}
来访问自己的 web 服务。
# frps.toml
subdomainHost = "frps.com"
将泛域名 *.frps.com
解析到 frps 所在服务器的 IP 地址。
# frpc.toml
[[proxies]]
name = "web"
type = "http"
localPort = 80
subdomain = "test"
frps 和 frpc 都启动成功后,通过 test.frps.com
就可以访问到内网的 web 服务。
注:如果 frps 配置了 subdomainHost
,则 customDomains
中不能是属于 subdomainHost
的子域名或者泛域名。
同一个 HTTP 或 HTTPS 类型的代理中 customDomains
和 subdomain
可以同时配置。
1.2.4 路由 #
URL 路由 #
frp 支持根据请求的 URL 路径路由转发到不同的后端服务。
通过配置文件中的 locations 字段指定一个或多个 proxy 能够匹配的 URL 前缀(目前仅支持最大前缀匹配,之后会考虑正则匹配)。例如指定 locations = "/news"
,则所有 URL 以 /news
开头的请求都会被转发到这个服务。
# frpc.toml
[[proxies]]
name = "web01"
type = "http"
localPort = 80
customDomains = ["web.yourdomain.com"]
locations = ["/"]
[[proxies]]
name = "web02"
type = "http"
localPort = 81
customDomains = ["web.yourdomain.com"]
locations = ["/news", "/about"]
按照上述的示例配置后,web.yourdomain.com
这个域名下所有以 /news
以及 /about
作为前缀的 URL 请求都会被转发到 web02,其余的请求会被转发到 web01。
1.3 STCP & SUDP #
了解 frp STCP
, SUDP
类型的代理。
STCP 和 SUDP 的 (S) 的含义是 Secret。其作用是为 TCP 和 UDP 类型的服务提供一种安全访问的能力,避免让端口直接暴露在公网上导致任何人都能访问到。
这两种代理要求在被访问服务的机器上以及要访问的用户的机器上都部署上 frp 的客户端。被访问的服务所在机器叫做服务端,另一端叫做访问端。
frp 会在访问端监听一个端口和服务端的端口做映射。访问端的用户需要提供相同的密钥才能连接成功,从而保证安全性。
1.4 XTCP #
了解 frp XTCP
类型的代理。
XTCP 的配置方式和 STCP 很类似。但是会采用 P2P 的方式进行打洞穿透,如果成功,后续的流量将不会经过 frps,而是直接通信,不再受到 frps 所在服务器的带宽限制。
由于打洞成功率取决于所处网络的 NAT 类型,所以 XTCP 的可用性和稳定性无法保证。在需要可靠连接的情况下,建议使用 STCP 替代。
当 visitor 配置了 keepTunnelOpen = true
时,frpc 会定期检测隧道是否打开,如果没有,则会尝试打洞建立隧道,这样可以始终保持隧道打开,在需要连接对端服务时,可以避免延迟。
默认情况下,visitor 会在接收到用户连接后尝试打洞,如果打洞失败,可以尝试多次建立连接,程序会尝试其他的打洞策略,有可能在多次重试后成功打洞。一旦打洞成功,后续新增连接不必重复打洞,而是可以复用隧道。
1.4.1 Fallback 机制 #
可以通过配置 fallback 到 stcp visitor 实现在打洞失败时,回退到 stcp 建立连接。
示例配置:
[[visitors]]
name = "stcp-visitor"
type = "stcp"
serverName = "stcp-test"
secretKey = "abc"
bindPort = -1
[[visitors]]
name = "xtcp-visitor"
type = "xtcp"
serverName = "xtcp-test"
secretKey = "abc"
bindAddr = "127.0.0.1"
bindPort = 9002
fallbackTo = "stcp-visitor"
fallbackTimeoutMs = 200
当连接 127.0.0.1:9002
超过 200ms p2p 打洞还未成功的话,会回退到使用 stcp-visitor 建立连接。fallback 后,之前触发的打洞操作仍然会继续,一般来说打洞完成需要的耗时会比较长。
如果打洞成功,下次建立新的连接时,将不需要再次打洞,会很快完成连接建立,不会触发 fallback。
需要注意根据访问端和被访问端的延迟情况来合理设置超时时间,以避免超时时间太短,即使打洞成功连接也来不及建立,而一直触发 fallback。
stcp-visitor 的 bindPort
设置为 -1 表示不需要监听物理端口,只接受 fallback 的连接即可。
1.5 TCPMUX #
了解 frp TCPMUX
类型的代理。
frp 支持将单个端口收到的连接路由到不同的代理,类似 vhostHTTPPort
和 vhostHTTPSPort
。
目前支持的复用器只有 httpconnect
。
当在 frps.toml
中设置 tcpmuxHTTPConnectPort
,frps 将会监听在这个端口,接收 HTTP CONNECT 请求。
frps 会根据 HTTP CONNECT 请求中的 host 路由到不同的后端代理。
示例配置如下:
# frps.toml
bindPort = 7000
tcpmuxHTTPConnectPort = 1337
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
[[proxies]]
name = "proxy1"
type = "tcpmux"
multiplexer = "httpconnect"
customDomains = ["test1"]
localPort = 80
[[proxies]]
name = "proxy2"
type = "tcpmux"
multiplexer = "httpconnect"
customDomains = ["test2"]
localPort = 8080
通过上面的配置,frps 如果接收到 HTTP CONNECT 请求内容:
CONNECT test1 HTTP/1.1\r\n\r\n
该连接将会被路由到 proxy1 。
Powered by BetterDocs