FRP使用

概览

frp 是什么?

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

为什么使用 frp?

通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:

安装

关于如何安装 frp 的说明。

frp 采用 Golang 编写,支持跨平台,仅需下载对应平台的二进制文件即可执行,没有额外依赖。

系统需求

由于采用 Golang 编写,所以系统需求和最新的 Golang 对系统和平台的要求一致,具体可以参考 Golang System requirements

下载

目前可以在 Github 的 Release 页面中下载到最新版本的客户端和服务端二进制文件,所有文件被打包在一个压缩包中。

部署

解压缩下载的压缩包,将其中的 frpc 拷贝到内网服务所在的机器上,将 frps 拷贝到具有公网 IP 的机器上,放置在任意目录。

开始使用!

编写配置文件,先通过 ./frps -c ./frps.ini 启动服务端,再通过 ./frpc -c ./frpc.ini 启动客户端。如果需要在后台长期运行,建议结合其他工具使用,例如 systemdsupervisor

如果是 Windows 用户,需要在 cmd 终端中执行命令。

概念

一些概念,理解它们有助于您更好地了解和使用 frp。

原理

frp 主要由 客户端(frpc)服务端(frps) 组成,服务端通常部署在具有公网 IP 的机器上,客户端通常部署在需要穿透的内网服务所在的机器上。

内网服务由于没有公网 IP,不能被非局域网内的其他用户访问。

用户通过访问服务端的 frps,由 frp 负责根据请求的端口或其他信息将请求路由到对应的内网机器,从而实现通信。

代理

在 frp 中一个代理对应一个需要暴露的内网服务。一个客户端支持同时配置多个代理。

代理类型

frp 支持多种代理类型来适配不同的使用场景。

类型 描述
tcp 单纯的 TCP 端口映射,服务端会根据不同的端口路由到不同的内网服务。
udp 单纯的 UDP 端口映射,服务端会根据不同的端口路由到不同的内网服务。
http 针对 HTTP 应用定制了一些额外的功能,例如修改 Host Header,增加鉴权。
https 针对 HTTPS 应用定制了一些额外的功能。
stcp 安全的 TCP 内网代理,需要在被访问者和访问者的机器上都部署 frpc,不需要在服务端暴露端口。
sudp 安全的 UDP 内网代理,需要在被访问者和访问者的机器上都部署 frpc,不需要在服务端暴露端口。
xtcp 点对点内网穿透代理,功能同 stcp,但是流量不需要经过服务器中转。
tcpmux 支持服务端 TCP 端口的多路复用,通过同一个端口访问不同的内网服务。

示例

这里包括多个常见的使用场景和配置示例,你可以用来亲自部署和体验这些示例。

通过 SSH 访问内网机器

这个示例通过简单配置 TCP 类型的代理让用户访问到内网的服务器。

  1. 在具有公网 IP 的机器上部署 frps,修改 frps.ini 文件,这里使用了最简化的配置,设置了 frp 服务器用户接收客户端连接的端口:

    [common]
    bind_port = 7000
    
  2. 在需要被访问的内网机器上(SSH 服务通常监听在 22 端口)部署 frpc,修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x:

    [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
    

    local_iplocal_port 配置为本地需要暴露到公网的服务地址和端口。remote_port 表示在 frp 服务端监听的端口,访问此端口的流量将会被转发到本地服务对应的端口。

  3. 分别启动 frps 和 frpc。

  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@x.x.x.x

    frp 会将请求 x.x.x.x:6000 的流量转发到内网机器的 22 端口。

通过自定义域名访问内网的 Web 服务

这个示例通过简单配置 HTTP 类型的代理让用户访问到内网的 Web 服务。

HTTP 类型的代理相比于 TCP 类型,不仅在服务端只需要监听一个额外的端口 vhost_http_port 用于接收 HTTP 请求,还额外提供了基于 HTTP 协议的诸多功能。

  1. 修改 frps.ini 文件,设置监听 HTTP 请求端口为 8080:

    [common]
    bind_port = 7000
    vhost_http_port = 8080
    
  2. 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 Web 服务监听的端口, 绑定自定义域名为 custom_domains

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [web]
    type = http
    local_port = 80
    custom_domains = www.yourdomain.com
    
    [web2]
    type = http
    local_port = 8080
    custom_domains = www.yourdomain2.com
    
  3. 分别启动 frps 和 frpc。

  4. www.yourdomain.comwww.yourdomain2.com 的域名 A 记录解析到 IP x.x.x.x,如果服务器已经有对应的域名,也可以将 CNAME 记录解析到服务器原先的域名。或者可以通过修改 HTTP 请求的 Host 字段来实现同样的效果。

  5. 通过浏览器访问 http://www.yourdomain.com:8080 即可访问到处于内网机器上 80 端口的服务,访问 http://www.yourdomain2.com:8080 则访问到内网机器上 8080 端口的服务。

转发 DNS 查询请求

这个示例通过简单配置 UDP 类型的代理转发 DNS 查询请求。

DNS 查询请求通常使用 UDP 协议,frp 支持对内网 UDP 服务的穿透,配置方式和 TCP 基本一致。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. 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
    

    这里反代了 Google 的 DNS 查询服务器的地址,仅仅用于测试 UDP 代理,并无实际意义。

  3. 分别启动 frps 和 frpc。

  4. 通过 dig 测试 UDP 包转发是否成功,预期会返回 www.baidu.com 域名的解析结果。

    dig @x.x.x.x -p 6000 www.baidu.com

转发 Unix 域套接字

这个示例通过配置 Unix域套接字客户端插件来通过 TCP 端口访问内网的 Unix域套接字服务,例如 Docker Daemon。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. 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
    
  3. 分别启动 frps 和 frpc。

  4. 通过 curl 命令查看 docker 版本信息

    curl http://x.x.x.x:6000/version

对外提供简单的文件访问服务

这个示例通过配置 static_file 客户端插件来将本地文件暴露在公网上供其他人访问。

通过 static_file 插件可以对外提供一个简单的基于 HTTP 的文件访问服务。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. 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
    
  3. 分别启动 frps 和 frpc。

  4. 通过浏览器访问 http://x.x.x.x:6000/static/ 来查看位于 /tmp/file 目录下的文件,会要求输入已设置好的用户名和密码。

为本地 HTTP 服务启用 HTTPS

通过 https2http 插件可以让本地 HTTP 服务转换成 HTTPS 服务对外提供。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. 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
    
  3. 分别启动 frps 和 frpc。

  4. 通过浏览器访问 https://test.yourdomain.com

安全地暴露内网服务

这个示例将会创建一个只有自己能访问到的 SSH 服务代理。

对于某些服务来说如果直接暴露于公网上将会存在安全隐患。

使用 stcp(secret tcp) 类型的代理可以避免让任何人都能访问到要穿透的服务,但是访问者也需要运行另外一个 frpc 客户端。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. 在需要暴露到内网的机器上部署 frpc,且配置如下:

    [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
    
  3. 在想要访问内网服务的机器上也部署 frpc,且配置如下:

    [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
    
  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@127.0.0.1

点对点内网穿透

这个示例将会演示一种不通过服务器中转流量的方式来访问内网服务。

frp 提供了一种新的代理类型 xtcp 用于应对在希望传输大量数据且流量不经过服务器的场景。

使用方式同 stcp 类似,需要在两边都部署上 frpc 用于建立直接的连接。

目前处于开发的初级阶段,并不能穿透所有类型的 NAT 设备,所以穿透成功率较低。穿透失败时可以尝试 stcp 的方式。

  1. frps.ini 内容如下,需要额外配置监听一个 UDP 端口用于支持该类型的客户端:

    [common]
    bind_port = 7000
    bind_udp_port = 7000
    
  2. 在需要暴露到内网的机器上部署 frpc,且配置如下:

    [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
    
  3. 在想要访问内网服务的机器上也部署 frpc,且配置如下:

    [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
    
  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@127.0.0.1

参考

服务端配置

frp 服务端详细配置说明。

基础配置

参数 类型 说明 默认值 可选值 备注
bind_addr string 服务端监听地址 0.0.0.0
bind_port int 服务端监听端口 7000 接收 frpc 的连接
bind_udp_port int 服务端监听 UDP 端口 0 用于辅助创建 P2P 连接
kcp_bind_port int 服务端监听 KCP 协议端口 0 用于接收采用 KCP 连接的 frpc
proxy_bind_addr string 代理监听地址 同 bind_addr 可以使代理监听在不同的网卡地址
log_file string 日志文件地址 ./frps.log 如果设置为 console,会将日志打印在标准输出中
log_level string 日志等级 info trace, debug, info, warn, error
log_max_days int 日志文件保留天数 3
disable_log_color bool 禁用标准输出中的日志颜色 false
detailed_errors_to_client bool 服务端返回详细错误信息给客户端 true
heart_beat_timeout int 服务端和客户端心跳连接的超时时间 90 单位:秒
user_conn_timeout int 用户建立连接后等待客户端响应的超时时间 10 单位:秒
udp_packet_size int 代理 UDP 服务时支持的最大包长度 1500 服务端和客户端的值需要一致
tls_cert_file string TLS 服务端证书文件路径
tls_key_file string TLS 服务端密钥文件路径
tls_trusted_ca_file string TLS CA 证书路径

权限验证

参数 类型 说明 默认值 可选值 备注
authentication_method string 鉴权方式 token token, oidc
authenticate_heartbeats bool 开启心跳消息鉴权 false
authenticate_new_work_conns bool 开启建立工作连接的鉴权 false
token string 鉴权使用的 token 值 客户端需要设置一样的值才能鉴权通过
oidc_issuer string oidc_issuer
oidc_audience string oidc_audience
oidc_skip_expiry_check bool oidc_skip_expiry_check
oidc_skip_issuer_check bool oidc_skip_issuer_check

管理配置

参数 类型 说明 默认值 可选值 备注
allow_ports string 允许代理绑定的服务端端口 格式为 1000-2000,2001,3000-4000
max_pool_count int 最大连接池大小 5
max_ports_per_client int 限制单个客户端最大同时存在的代理数 0 0 表示没有限制
tls_only bool 只接受启用了 TLS 的客户端连接 false

Dashboard, 监控

参数 类型 说明 默认值 可选值 备注
dashboard_addr string 启用 Dashboard 监听的本地地址 0.0.0.0
dashboard_port int 启用 Dashboard 监听的本地端口 0
dashboard_user string HTTP BasicAuth 用户名
dashboard_pwd string HTTP BasicAuth 密码
enable_prometheus bool 是否提供 Prometheus 监控接口 false 需要同时启用了 Dashboard 才会生效
asserts_dir string 静态资源目录 Dashboard 使用的资源默认打包在二进制文件中,通过指定此参数使用自定义的静态资源

HTTP & HTTPS

参数 类型 说明 默认值 可选值 备注
vhost_http_port int 为 HTTP 类型代理监听的端口 0 启用后才支持 HTTP 类型的代理,默认不启用
vhost_https_port int 为 HTTPS 类型代理监听的端口 0 启用后才支持 HTTPS 类型的代理,默认不启用
vhost_http_timeout int HTTP 类型代理在服务端的 ResponseHeader 超时时间 60
subdomain_host string 二级域名后缀
custom_404_page string 自定义 404 错误页面地址

TCPMUX

参数 类型 说明 默认值 可选值 备注
tcpmux_httpconnect_port int 为 TCPMUX 类型代理监听的端口 0 启用后才支持 TCPMUX 类型的代理,默认不启用

客户端配置

frp 客户端的详细配置说明。

基础配置

参数 类型 说明 默认值 可选值 备注
server_addr string 连接服务端的地址 0.0.0.0
server_port int 连接服务端的端口 7000
http_proxy string 连接服务端使用的代理地址 格式为 {protocol}://user:passwd@192.168.1.128:8080 protocol 目前支持 http、socks5、ntlm
log_file string 日志文件地址 ./frpc.log 如果设置为 console,会将日志打印在标准输出中
log_level string 日志等级 info trace, debug, info, warn, error
log_max_days int 日志文件保留天数 3
disable_log_color bool 禁用标准输出中的日志颜色 false
pool_count int 连接池大小 0
user string 用户名 设置此参数后,代理名称会被修改为 {user}.{proxyName},避免代理名称和其他用户冲突
dns_server string 使用 DNS 服务器地址 默认使用系统配置的 DNS 服务器,指定此参数可以强制替换为自定义的 DNS 服务器地址
login_fail_exit bool 第一次登陆失败后是否退出 true
protocol string 连接服务端的通信协议 tcp tcp, kcp, websocket
tls_enable bool 启用 TLS 协议加密连接 false
tls_cert_file string TLS 客户端证书文件路径
tls_key_file string TLS 客户端密钥文件路径
tls_trusted_ca_file string TLS CA 证书路径
tls_server_name string TLS Server 名称 为空则使用 server_addr
heartbeat_interval int 向服务端发送心跳包的间隔时间 30
heartbeat_timeout int 和服务端心跳的超时时间 90
udp_packet_size int 代理 UDP 服务时支持的最大包长度 1500 服务端和客户端的值需要一致
start string 指定启用部分代理 当配置了较多代理,但是只希望启用其中部分时可以通过此参数指定,默认为全部启用

权限验证

参数 类型 说明 默认值 可选值 备注
authentication_method string 鉴权方式 token token, oidc 需要和服务端一致
authenticate_heartbeats bool 开启心跳消息鉴权 false 需要和服务端一致
authenticate_new_work_conns bool 开启建立工作连接的鉴权 false 需要和服务端一致
token string 鉴权使用的 token 值 需要和服务端设置一样的值才能鉴权通过
oidc_client_id string oidc_client_id
oidc_client_secret string oidc_client_secret
oidc_audience string oidc_audience
oidc_token_endpoint_url string oidc_token_endpoint_url

UI

参数 类型 说明 默认值 可选值 备注
admin_addr string 启用 AdminUI 监听的本地地址 0.0.0.0
admin_port int 启用 AdminUI 监听的本地端口 0
admin_user string HTTP BasicAuth 用户名
admin_pwd string HTTP BasicAuth 密码
asserts_dir string 静态资源目录 AdminUI 使用的资源默认打包在二进制文件中,通过指定此参数使用自定义的静态资源

代理配置

frp 代理的详细配置说明。

通用配置

通用配置是指不同类型的代理共同使用的一些配置参数。

基础配置

参数 类型 说明 是否必须 默认值 可选值 备注
type string 代理类型 tcp tcp, udp, http, https, stcp, sudp, xtcp, tcpmux
use_encryption bool 是否启用加密功能 false 启用后该代理和服务端之间的通信内容都会被加密传输
use_compression bool 是否启用压缩功能 false 启用后该代理和服务端之间的通信内容都会被压缩传输
proxy_protocol_version string 启用 proxy protocol 协议的版本 v1, v2 如果启用,则 frpc 和本地服务建立连接后会发送 proxy protocol 的协议,包含了原请求的 IP 地址和端口等内容
bandwidth_limit string 设置单个 proxy 的带宽限流 单位为 MB 或 KB,0 表示不限制,如果启用,会作用于对应的 frpc

本地服务配置

local_ipplugin 的配置必须配置一个,且只能生效一个,如果配置了 plugin,则 local_ip 配置无效。

参数 类型 说明 是否必须 默认值 可选值 备注
local_ip string 本地服务 IP 127.0.0.1 需要被代理的本地服务的 IP 地址,可以为所在 frpc 能访问到的任意 IP 地址
local_port int 本地服务端口 配合 local_ip
plugin string 客户端插件名称 见客户端插件的功能说明 用于扩展 frpc 的能力,能够提供一些简单的本地服务,如果配置了 plugin,则 local_ip 和 local_port 无效,两者只能配置一个
plugin_params map 客户端插件参数 map 结构,key 需要都以 "plugin_" 开头,每一个 plugin 需要的参数也不一样,具体见客户端插件参数中的内容

负载均衡和健康检查

参数 类型 说明 是否必须 默认值 可选值 备注
group string 负载均衡分组名称 用户请求会以轮询的方式发送给同一个 group 中的代理
group_key string 负载均衡分组密钥 用于对负载均衡分组进行鉴权,group_key 相同的代理才会被加入到同一个分组中
health_check_type string 健康检查类型 tcp,http 配置后启用健康检查功能,tcp 是连接成功则认为服务健康,http 要求接口返回 2xx 的状态码则认为服务健康
health_check_timeout_s int 健康检查超时时间(秒) 3 执行检查任务的超时时间
health_check_max_failed int 健康检查连续错误次数 1 连续检查错误多少次认为服务不健康
health_check_interval_s int 健康检查周期(秒) 10 每隔多长时间进行一次健康检查
health_check_url string 健康检查的 HTTP 接口 如果 health_check_type 类型是 http,则需要配置此参数,指定发送 http 请求的 url,例如 "/health"

TCP

参数 类型 说明 是否必须 默认值 可选值 备注
remote_port int 服务端绑定的端口 用户访问此端口的请求会被转发到 local_ip:local_port

UDP

参数 类型 说明 是否必须 默认值 可选值 备注
remote_port int 服务端绑定的端口 用户访问此端口的请求会被转发到 local_ip:local_port

HTTP

custom_domainssubdomain 必须要配置其中一个,两者可以同时生效。

参数 类型 说明 是否必须 默认值 可选值 备注
custom_domains []string 服务器绑定自定义域名 是(和 subdomain 两者必须配置一个) 用户通过 vhost_http_port 访问的 HTTP 请求如果 Host 在 custom_domains 配置的域名中,则会被路由到此代理配置的本地服务
subdomain string 自定义子域名 是(和 custom_domains 两者必须配置一个) 和 custom_domains 作用相同,但是只需要指定子域名前缀,会结合服务端的 subdomain_host 生成最终绑定的域名
locations []string URL 路由配置 采用最大前缀匹配的规则,用户请求匹配响应的 location 配置,则会被路由到此代理
http_user string 用户名 如果配置此参数,暴露出去的 HTTP 服务需要采用 Basic Auth 的鉴权才能访问
http_pwd string 密码 结合 http_user 使用
host_header_rewrite string 替换 Host header 替换发送到本地服务 HTTP 请求中的 Host 字段
headers map 替换 header map 中的 key 是要替换的 header 的 key,value 是替换后的内容

HTTPS

custom_domainssubdomain 必须要配置其中一个,两者可以同时生效。

参数 类型 说明 是否必须 默认值 可选值 备注
custom_domains []string 服务器绑定自定义域名 是(和 subdomain 两者必须配置一个) 用户通过 vhost_http_port 访问的 HTTP 请求如果 Host 在 custom_domains 配置的域名中,则会被路由到此代理配置的本地服务
subdomain string 自定义子域名 是(和 custom_domains 两者必须配置一个) 和 custom_domains 作用相同,但是只需要指定子域名前缀,会结合服务端的 subdomain_host 生成最终绑定的域名

STCP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

SUDP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

XTCP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

Revision #3
Created 27 September 2021 04:46:15 by 吴壮壮
Updated 27 September 2021 05:04:17 by 吴壮壮