frp 高性能反代程序,轻松实现多平台内网穿透,网站穿透实例记录
关于反代和穿透工具,之前在 XTunnel 介绍 的一文中提及过frp,和项目已经被商用的xtunnel相比,frp仍然秉持开源精神,在Github上的项目至今依旧活跃,虽然没有提供GUI,但只需简单配置客户端与服务端,一行命令就能完成内网穿透,今天简单介绍一下,并记录一个frp的普通应用场景:frp Windows 客户端+frp Linux 服务端+域名,实现无公网IP PC内网网站映射外网访问
如果你是第一次接触frp,可以看下面引用自frp的官方说明文档,官方教程已经足够详细了,本文只对场景做简单记录,程序涉及到的更多配置参数见 frp Github 中文文档
frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, udp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发。
frp 的作用
利用处于内网或防火墙后的机器,对外网环境提供 http 或 https 服务。
对于 http 服务支持基于域名的虚拟主机,支持自定义域名绑定,使多个域名可以共用一个80端口。
利用处于内网或防火墙后的机器,对外网环境提供 tcp 服务,例如在家里通过 ssh 访问处于公司内网环境内的主机。
可查看通过代理的所有 http 请求和响应的详细信息。(待开发)
开始前
需要用到的工具:1台能访问外网的Windows PC电脑,1台带有公网IP的Linux VPS,1个可自主解析的域名。
服务端配置(Linux)
1.根据系统版本,从Releases 页面选择对应的程序包,登陆VPS SSH并上传或wget至服务器。
- wget --no-check-certificate https://github.com/fatedier/frp/releases/download/v0.9.3/frp_0.9.3_linux_amd64.tar.gz
- tar zxvf frp_0.9.3_linux_amd64.tar.gz
- cd frp_0.9.3_linux_amd64
本次以Ubuntu 14.04 64bit为例,截止博客发文为止最新版本为0.9.3
2.删除默认服务端配置文件frps.ini,重新创建并编辑
- rm frps.ini && vi frps.ini
注意:官方下载过来的压缩包内包含2个配置文件,客户端(frpc.ini)和服务端(frps.ini),本次使用Linux作为服务端,所以需要修改frps.ini,不要搞混了!
3.进入vi编辑界面,添加一个配置
- [common]
- bind_port = 7000
- vhost_http_port = 80
- [web]
- type = http
- custom_domains = frp.1w.nz
- auth_token = 123
以上配置简单来说就是定义一个http反向代理,名为: web ,设置 http 访问端口:80,绑定自定义域名 frp.1w.nz ,其中bind_port是服务端与客户端握手时的端口,auth_token相当于验证密码,https 服务配置方法相同, vhost_http_port 替换为 vhost_https_port, type 设置为 https 即可。
4.保存退出vi界面,安装 Screen,为运行frp新建一个名为frp的终端会话:
Debian & ubuntu:
- apt-get -y install screen && screen -S frp
CentOS:
- yum -y install screen && screen -S frp
为了方便执行其他操作,保证frp服务不被中断,需要新建一个会话,让frp保持后台运行。
5.最后启动 frp 服务端,即可完成服务端操作。
- ./frps -c ./frps.ini
域名绑定
将服务端配置文件中设置的域名解析至Linux VPS 的公网IP
客户端配置(Windows)
1.根据系统版本,从Releases 页面选择对应的Windows 程序包,下载解压。
- https://github.com/fatedier/frp/releases/download/v0.9.3/frp_0.9.3_windows_amd64.zip
本次以Windows 10 64位为例,截止博客发文为止最新版本为0.9.3
2.清空默认客户端配置文件frpc.ini,重新添加一个客户端配置
- [common]
- server_addr = 104.1xx.xx.xx
- server_port = 7000
- auth_token = 123
- [web]
- type = http
- local_port = 80
依然要注意服务端和客户端的配置文件区别,本次使用Windows作为客户端,所以需要修改frpc.ini,以上配置基本根据服务端相对应地填写即可,参数必须一致,需要修改的主要是server_addr(填写Linux VPS 公网 IP)和local_port(填写本地网站应用的端口),最后再确认一下客户端服务端的握手端口、以及验证码是否一致,
3.确认无误后,运行程序目录下的frpc.exe,看到成功提示即表示连接成功。
4.再来看看服务端的运行日志
其他参数与功能
frp也同样支持多条反代记录,如果你需要和朋友共用frp,也可以在配置文件中添加一个自定义二级域名,还有更多的应用场景需要用到的参数与配置,详见 frp Github 中文文档,这里不赘述。
frp
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 为 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
- 启动 frpc:
./frpc -c ./frpc.ini
- 通过 ssh 访问内网机器,假设用户名为 test:
ssh -o Port=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 为 x.x.x.x,local_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
- 启动 frpc:
./frpc -c ./frpc.ini
-
将 www.yourdomain.com 的域名 A 记录解析到 IP x.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 为 x.x.x.x ,转发到 Google 的 DNS 查询服务器 8.8.8.8 的 udp 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
- 启动 frpc:
./frpc -c ./frpc.ini
- 通过 dig 测试 UDP 包转发是否成功,预期会返回 www.google.com 域名的解析结果:dig @x.x.x.x -p 6000 www.goolge.com
功能说明
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 配置中的 privilege_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 资源。
服务器端热加载配置文件
由于从 v0.10.0 版本开始,所有 proxy 都在客户端配置,这个功能暂时移除。
特权模式
由于从 v0.10.0 版本开始,所有 proxy 都在客户端配置,原先的特权模式是目前唯一支持的模式。
端口白名单
为了防止端口被滥用,可以手动指定允许哪些端口被使用,在 frps.ini 中通过 privilege_allow_ports 来指定:
- # frps.ini
- [common]
- privilege_allow_ports = 2000-3000,3001,3003,4000-50000
privilege_allow_ports 可以配置允许使用的某个指定端口或者是一个范围内的所有端口,以 , 分隔,指定的范围以 - 分隔。
TCP 多路复用
从 v0.10.0 版本开始,客户端和服务器端之间的连接支持多路复用,不再需要为每一个用户请求创建一个连接,使连接建立的延迟降低,并且避免了大量文件描述符的占用,使 frp 可以承载更高的并发数。
该功能默认启用,如需关闭,可以在 frps.ini 和 frpc.ini 中配置,该配置项在服务端和客户端必须一致:
- # frps.ini 和 frpc.ini 中
- [common]
- tcp_mux = false
连接池
默认情况下,当用户请求建立连接后,frps 才会请求 frpc 主动与后端服务建立一个连接。当为指定的代理启用连接池后,frp 会预先和后端服务建立起指定数量的连接,每次接收到用户请求后,会从连接池中取出一个连接和用户连接关联起来,避免了等待与后端服务建立连接以及 frpc 和 frps 之间传递控制信息的时间。
这一功能比较适合有大量短连接请求时开启。
- 首先可以在 frps.ini 中设置每个代理可以创建的连接池上限,避免大量资源占用,客户端设置超过此配置后会被调整到当前值:
- # frps.ini
- [common] max_pool_count = 5
- 在 frpc.ini 中为客户端启用连接池,指定预创建连接的数量:
- # frpc.ini
- [common]
- pool_count = 1
修改 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 。
通过密码保护你的 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 和 fprc 都启动成功后,通过 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 参数来使用此功能。
- # frpc.ini
- server_addr = x.x.x.x
- server_port = 7000
- httphttp_proxy = http://user:pwd@192.168.1.128:8080
开发计划
计划在后续版本中加入的功能与优化,排名不分先后,如果有其他功能建议欢迎在 issues 中反馈。
- frps 记录 http 请求日志。
- frps 支持直接反向代理,类似 haproxy。
- frpc 支持负载均衡到后端不同服务。
- frpc 支持直接作为 webserver 访问指定静态页面。
- frpc 完全控制模式,通过 dashboard 对 frpc 进行在线操作。
- 支持 udp 打洞的方式,提供两边内网机器直接通信,流量不经过服务器转发。
- 支持 plugin,frpc 获取到的连接可以交给指定 plugin 处理,例如 http 代理,简单的 web server。
- 集成对 k8s 等平台的支持。
为 frp 做贡献
frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进步贡献力量。
- 在使用过程中出现任何问题,可以通过 issues 来反馈。
- Bug 的修复可以直接提交 Pull Request 到 dev 分支。
- 如果是增加新的功能特性,请先创建一个 issue 并做简单描述以及大致的实现方法,提议被采纳后,就可以创建一个实现新特性的 Pull Request。
- 欢迎对说明文档做出改善,帮助更多的人使用 frp,特别是英文文档。
- 贡献代码请提交 PR 至 dev 分支,master 分支仅用于发布稳定可用版本。
- 如果你有任何其他方面的问题,欢迎反馈至 fatedier@gmail.com 共同交流。
提醒:和项目相关的问题最好在 issues 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。
捐助
如果您觉得 frp 对你有帮助,欢迎给予我们一定的捐助来维持项目的长期发展。
frp 交流群:606194980 (QQ 群号)