frp

[TOC]

frp

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。

当然还有一些其他的内网穿透工具,比如 telebit ngrok . 但效果都不太理想.

首先telebit, 服务器在国外,国内使用延迟特别高,当然可以自己搭建 telebit-relay 但是坑特别多,我提issue想让作者处理一下,得到的回复是这样的:

1
2
3
4
5
Thanks for the report.

We don’t have update install instructions for the relay server yet and we don’t have time to update and test them right now, so you’ll have to use the official server https://telebit.cloud until we do.

Right now our efforts are focused on improving the Telebit Remote client.

于是果断放弃。

再说ngrok,这个也是老断,bug多,在https方面配置很麻烦,而且不能使用三级域名(至少目前不行)。最重要的一点是,2.x版本不开源了。1.x坑当然多啦。

1
2
3
ngrok 2.x is the successor to 1.x and the focus of all current development effort. Its source code is not available.

NOTE This repository contains the code for ngrok 1.x.

frp架构

architecture

使用示例

根据对应的操作系统及架构,从 Release 页面下载最新版本的程序。

frpsfrps.ini 放到具有公网 IP 的机器上。

frpcfrpc.ini 放到处于内网环境的机器上。

通过 ssh 访问公司内网机器

  1. 修改 frps.ini 文件,这里使用了最简化的配置:
1
2
3
# frps.ini
[common]
bind_port = 7000
  1. 启动 frps:
1
./frps -c ./frps.ini
  1. 修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x;
1
2
3
4
5
6
7
8
9
10
# 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:
1
./frpc -c ./frpc.ini
  1. 通过 ssh 访问内网机器,假设用户名为 test:
1
ssh -oPort=6000 test@x.x.x.x

通过自定义域名访问部署于内网的 web 服务

有时想要让其他人通过域名访问或者测试我们在本地搭建的 web 服务,但是由于本地机器没有公网 IP,无法将域名解析到本地的机器,通过 frp 就可以实现这一功能,以下示例为 http 服务,https 服务配置方法相同, vhost_http_port 替换为 vhost_https_port, type 设置为 https 即可。我一般都用nginx反向代理。

  1. 修改 frps.ini 文件,设置 http 访问端口为 8080:
1
2
3
4
# frps.ini
[common]
bind_port = 7000
vhost_http_port = 8080
  1. 启动 frps:
1
./frps -c ./frps.ini
  1. 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 web 服务对应的端口, 绑定自定义域名 www.yourdomain.com:
1
2
3
4
5
6
7
8
9
# 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:
1
./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 文件:
1
2
3
# frps.ini
[common]
bind_port = 7000
  1. 启动 frps:
1
./frps -c ./frps.ini
  1. 修改 frpc.ini 文件,设置 frps 所在服务器的 IP 为 x.x.x.x,转发到 Google 的 DNS 查询服务器 8.8.8.8 的 udp 53 端口:
1
2
3
4
5
6
7
8
9
10
# 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:
1
./frpc -c ./frpc.ini
  1. 通过 dig 测试 UDP 包转发是否成功,预期会返回 www.google.com 域名的解析结果:
1
dig @x.x.x.x -p 6000 www.google.com

转发 Unix 域套接字

通过 tcp 端口访问内网的 unix域套接字(例如和 docker daemon 通信)。

frps 的部署步骤同上。

  1. 启动 frpc,启用 unix_domain_socket 插件,配置如下:
1
2
3
4
5
6
7
8
9
10
# 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 版本信息
1
curl http://x.x.x.x:6000/version

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

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

frps 的部署步骤同上。

  1. 启动 frpc,启用 static_file 插件,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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 插件,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 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 即可。

注意:这样的https在chrome浏览器中一般都会提醒属于不安全的https,可以通过nginx做反向代理实现。然后frp只需要是正常的http即可。

1
2
3
4
5
6
7
8
9
10
11
12
#########################  frp  #################################################
server {
# SSL configuration
server_name *.frp.domain.com frp.domain.com;
listen 443 ssl ;
ssl_certificate /etc/nginx/ssl/frp.domain.com/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/frp.domain.com/frp.domain.com.key;

location / {
proxy_pass http://0.0.0.0:8080;
}
}

安全地暴露内网服务

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

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

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

frps 的部署步骤同上。

  1. 启动 frpc,转发内网的 ssh 服务,配置如下,不需要指定远程端口:
1
2
3
4
5
6
7
8
9
10
11
# 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,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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:
1
ssh -oPort=6000 test@127.0.0.1

点对点内网穿透

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

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

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

  1. frps 除正常配置外需要额外配置一个 udp 端口用于支持该类型的客户端:
1
bind_udp_port = 7001
  1. 启动 frpc,转发内网的 ssh 服务,配置如下,不需要指定远程端口:
1
2
3
4
5
6
7
8
9
10
11
# 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,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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:
1
ssh -oPort=6000 test@127.0.0.1

更多内容参考官方地址: frp