概述

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。frp 采用 Golang 编写,所以只需要下载对应的客户端即可,麻烦一些的是需要自己编写适合自己的配置文件。

地址

项目地址:https://github.com/fatedier/frp

中文文档地址:https://gofrp.org/docs/examples/vhost-http/

下载地址:https://github.com/fatedier/frp/releases

文件说明

下载解压完成后

1
2
3
4
5
6
frpc                    # 客户端二进制文件
frpc_full.ini # 客户端配置文件完整示例
frpc.ini # 客户端配置文件
frps # 服务端二进制文件
frps_full.ini # 服务端配置文件完整示例
frps.in1 # 服务端配置文件

frps_full.ini

有需要的时候方便查阅用,如无需要可以跳过文件说明这一段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
[common]
# 服务端监听地址
bind_addr = 0.0.0.0
# 服务端监听端口,用于接收 frpc 的连接
bind_port = 7000

# 服务端监听 UDP 端口,用于辅助创建 P2P 连接
bind_udp_port = 7001

# 服务端监听 KCP 协议端口,用于接收采用 KCP 连接的 frpc,相当于“bind_port”功能
# 如果不设置,frps中kcp是禁用状态
kcp_bind_port = 7000

# 指定代理监听地址,默认值与“bind_addr”相同
# 配置的话可以使代理监听在不同的网卡地址
# proxy_bind_addr = 127.0.0.1

# 如果希望支持虚拟主机,必须设置侦听的http端口(可选)
# 注意:http端口和https端口可以与“bind_port”相同
vhost_http_port = 80
vhost_https_port = 4433

# 虚拟主机的http服务响应头超时时间(秒),默认是60秒
# vhost_http_timeout = 60

# 为 TCPMUX 类型代理监听的端口,默认不启用
# tcpmux_httpconnect_port = 1337

# 是否透传 CONNECT 请求,通常在本地服务是 HTTP Proxy 时使用
# tcpmux_passthrough = false

# 设置查看frps服务的仪表盘(运行数据)
# dashboard_addr(仪表盘地址)和 dashboard_port(仪表盘端口)
# 就是可以通过网页查看服务的运行状态
dashboard_addr = 0.0.0.0
dashboard_port = 7500

# 用于登录验证dashboard的账号和密码,默认都为admin
dashboard_user = admin
dashboard_pwd = admin

# Prometheus是一个开源监控解决方案,用于收集和聚合指标作为时间序列数据
# 需要同时启用了 Dashboard 才会生效
enable_prometheus = true

# 仪表板资产目录(仅用于调试模式)
# assets_dir = ./static

# 日志文件路径
# 如果设置为 console,会将日志打印在标准输出中
log_file = ./frps.log

# 日志等级
# trace, debug, info, warn, error
log_level = info

# 日志文件保留天数
log_max_days = 3

# 禁用标准输出中的日志颜色
disable_log_color = false

# 服务端返回详细错误信息给客户端
detailed_errors_to_client = true

# 鉴权方式
# authentication_method 参数指定使用何种验证方法,对frpc(客户端)和frps(服务端)进行验证
# 可选值:token, oidc,默认token
authentication_method = token

# 心跳消息鉴权
# 是否在发送到 fps 的心跳中包含身份验证令牌。 默认情况下,此值为 false。
authenticate_heartbeats = false

# 开启建立工作连接的鉴权
# 是否在发送到 frps 的新工作连接中包含身份验证令牌
authenticate_new_work_conns = false

# 鉴权使用的 token 值
token = 12345678

# 用来验证 OIDC 令牌的发行者
# 默认值为""
oidc_issuer =

# 指定验证时应包含的受众 OIDC 令牌。
# 默认值为""
oidc_audience =

# 是否跳过检查 OIDC 令牌是否过期
# 默认为false
oidc_skip_expiry_check = false

# 是否跳过检查 OIDC 令牌的颁发者声明是否与 OidcIssuer 中指定的颁发者匹配
# 默认为false
oidc_skip_issuer_check = false

# 服务端和客户端心跳连接的超时时间,单位:秒
# heartbeat_timeout = 90

# 用户建立连接后等待客户端响应的超时时间,单位:秒
# user_conn_timeout = 10

# 只允许frpc(客户端)绑定列出的端口,如果不设置,将不会被限制
allow_ports = 2000-3000,3001,3003,4000-50000

# 最大连接池大小
max_pool_count = 5

# 限制单个客户端最大同时存在的代理数,0 表示没有限制
max_ports_per_client = 0

# 只接受启用了 TLS 的客户端连接
tls_only = false

# TLS 服务端证书文件路径
# tls_cert_file = server.crt
# TLS 服务端密钥文件路径
# tls_key_file = server.key
# TLS 服务端密钥文件路径
# tls_trusted_ca_file = ca.crt

# 如果subdomain_host参数不为空,可以在frpc(客户端)的配置文件(frpc.ini)中的type=http或者type=https的项目中设置子域名
# 例如,subdomain为test时,主机会路由到test.frps.com网址。
subdomain_host = frps.com

# 如果使用 tcp 流多路复用,默认为 true
# tcp_mux = true

# tcp_mux 的心跳检查间隔时间
# 只有在 tcp_mux = true 时才会生效
# tcp_mux_keepalive_interval = 60

# frpc 和 frps 之间底层 TCP 连接的 keepalive 间隔时间,单位秒
# tcp_keepalive = 7200

# 自定义 HTTP 请求的404页面
# custom_404_page = /path/to/404.html

# 代理 UDP 服务时支持的最大包长度
udp_packet_size = 1500

# 启动 Go HTTP pprof,用于应用调试
pprof_enable = false

[plugin.user-manager]
addr = 127.0.0.1:9000
path = /handler
ops = Login

[plugin.port-manager]
addr = 127.0.0.1:9001
path = /handler
ops = NewProxy

frpc_full.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
[common]
# 连接frps服务器的地址
server_addr = 0.0.0.0
# 连接frps服务器的端口
server_port = 7000

# 连接服务端的超时时间,默认10s
# dial_server_timeout = 10

# 和服务端底层 TCP 连接的 keepalive 间隔时间,单位秒
# dial_server_keepalive = 7200

# 如果你想通过http代理或者socks5代理或者ntlm代理来连接frps,你可以在这里或者在全局环境变量中设置http_proxy
# http_proxy = http://user:passwd@192.168.1.128:8080
# http_proxy = socks5://user:passwd@192.168.1.128:1080
# http_proxy = ntlm://user:passwd@192.168.1.128:2080

# 日志文件路径
log_file = ./frpc.log
# # 日志等级
# trace, debug, info, warn, error
log_level = info
# 日志文件保留天数
log_max_days = 3

# 禁用标准输出中的日志颜色
disable_log_color = false

# 身份验证方式必须与frps服务器端的配置相同
# 是否在发送到 fps 的心跳中包含身份验证令牌。 默认情况下,此值为 false。
authenticate_heartbeats = false

# 开启建立工作连接的鉴权
# 是否在发送到 frps 的新工作连接中包含身份验证令牌
authenticate_new_work_conns = false

# 鉴权使用的 token 值
token = 12345678

# 如果frps中配置 AuthenticationMethod == "oidc"
# oidc_client_id 指定用于在 OIDC 身份验证中获取令牌的客户端 ID。
# 默认值为""
oidc_client_id =

# oidc_client_secret 指定用于在 OIDC 身份验证中获取令牌的客户端密码
# 默认值为""
oidc_client_secret =

# oidc_audience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
oidc_audience =

# oidc_audience 指定 OIDC 身份验证中令牌的受众
# 默认情况下,此值为“”
oidc_token_endpoint_url =

# oidc_additional_xxx 指定要发送到 OIDC 令牌端点的附加参数
# 例如,如果要指定“audience”参数,可以设置如下
# frp 会将 "audience=<value>" "var1=<value>" 添加到附加参数中
# oidc_additional_audience = https://dev.auth.com/api/v2/
# oidc_additional_var1 = foobar

# frpc操作设置的管理地址
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_pwd = admin
# 管理资产目录。 默认情况下,这些资产与 frpc 捆绑在一起。
# assets_dir = ./static

# 最大连接池大小
pool_count = 5

# 如果使用tcp流多路复用,默认为true,必须和frps一样
# tcp_mux = true

# tcp_mux 的心跳检查间隔时间
# 只有在 tcp_mux = true 时才会生效
# tcp_mux_keepalive_interval = 60

# 您的代理名称将更改为 {user}.{proxy}
user = your_name

# 第一次登陆失败后是否退出
login_fail_exit = true

# 连接服务端的通信协议
# 可选tcp, kcp websocket, 默认为 tcp
# now it supports tcp, kcp and websocket, default is tcp
protocol = tcp

# 连接服务端时所绑定的本地 IP
connect_server_local_ip = 0.0.0.0

# 启用 TLS 协议加密连接
tls_enable = true

# TLS 客户端密钥文件路径
# tls_cert_file = client.crt
# TLS 客户端密钥文件路径
# tls_key_file = client.key
# TLS Server 名称
# tls_trusted_ca_file = ca.crt
# TLS Server 名称
# tls_server_name = example.com

# 使用 DNS 服务器地址
# 默认使用系统配置的 DNS 服务器,指定此参数可以强制替换为自定义的 DNS 服务器地址
# dns_server = 8.8.8.8

# 指定启用部分代理
# 当配置了较多代理,但是只希望启用其中部分时可以通过此参数指定,默认为全部启用
# start = ssh,dns

# 向服务端发送心跳包的间隔时间
# 建议启用 tcp_mux_keepalive_interval,将此值设置为 -1
# heartbeat_interval = 30
# 和服务端心跳的超时时间
# heartbeat_timeout = 90

# meta_xxx
# 客户端的的附加元数据
# 会传递给服务端插件,提供附加能力
meta_var1 = 123
meta_var2 = 234

# 代理 UDP 服务时支持的最大包长度
# 服务端和客户端的值需要一致
udp_packet_size = 1500

# 包括代理的其他配置文件。
# includes = ./confd/*.ini

# 默认情况下,如果启用了 tls,则 frpc 将使用第一个自定义字节连接 frps。
# 如果 DisableCustomTLSFirstByte = true,frpc 将不会发送该自定义字节。
disable_custom_tls_first_byte = false

# 启动 Go HTTP pprof,必须先设置管理端口。
# 用于应用调试
pprof_enable = false

# “ssh”是唯一标识符的代理名称
# [ssh]这里的ssh可以自定义,但需要保证唯一性
# 如果在[common]部分user参数不为空,这里将会变为{user}.{proxy}的形式,例如“your_name.ssh”
[ssh]
# 类型包括 tcp | udp | http | https | stcp | xtcp, 默认是tcp
type = tcp
local_ip = 127.0.0.1
local_port = 22
# 限制此代理的带宽,单位为 KB 和 MB
bandwidth_limit = 1MB
# true 或 false,如果为 true,则 frps 和 frpc 之间的消息将被加密,默认为 false
use_encryption = false
# 如果为true,消息将被压缩
use_compression = false
# 通过 frps 侦听远程端口
remote_port = 6001
# frps 将为同一组中的代理负载平衡连接
group = test_group
# 组应该具有相同的组密钥
group_key = 123456
# 启用后端服务的健康检查,支持'tcp'和'http'
# frpc 将连接本地服务的端口以检测它的健康状态
health_check_type = tcp
# 健康检查连接超时
health_check_timeout_s = 3
# 如果连续3次失败,代理将从frps中删除
health_check_max_failed = 3
# 每 10 秒将进行一次健康检查
health_check_interval_s = 10
# 每个代理的附加元数据
meta_var1 = 123
meta_var2 = 234

[ssh_random]
type = tcp
local_ip = 127.0.0.1
local_port = 22
# 如果 remote_port 为 0,frps 会为你分配一个随机端口
remote_port = 0

# if you want to expose multiple ports, add 'range:' prefix to the section name
# frpc will generate multiple proxies such as 'tcp_port_6010', 'tcp_port_6011' and so on.
# 如果要公开多个端口,添加'range:自定义前缀'
# frpc 会生成多个代理,如 'tcp_port_6010'、'tcp_port_6011' 等。
[range:tcp_port]
type = tcp
local_ip = 127.0.0.1
local_port = 6010-6020,6022,6024-6028
remote_port = 6010-6020,6022,6024-6028
use_encryption = false
use_compression = false

[dns]
type = udp
local_ip = 114.114.114.114
local_port = 53
remote_port = 6002
use_encryption = false
use_compression = false

[range:udp_port]
type = udp
local_ip = 127.0.0.1
local_port = 6010-6020
remote_port = 6010-6020
use_encryption = false
use_compression = false

# 解析域名到[server_addr]后,就可以使用http://web001.yourdomain.com访问web01
# 此处的“http://web001.yourdomain.com”中的“web001”的值是对应下面的subdomain = web001
# 如果配置了subdomain = web001,就不需要配置custom_domains了,两者二选一
# 如果使用subdomain = web001来配置,必须要在frps服务端配置subdomain_host=yourdomain.com
[web01]
type = http
local_ip = 127.0.0.1
local_port = 80
use_encryption = false
use_compression = true
# 对http协议来讲,使用用户名和密码访问http是一种安全验证机制
# 如果不设置,你将无需认证即可访问custom_domains的地址
http_user = admin
http_pwd = admin
# 如果frps服务端的frps.ini配置中subdomain_host=frps.com
# 你可以使用http://web001.frps.com访问web01代理
subdomain = web001
custom_domains = web001.yourdomain.com
# locations参数只有在应用类型type=http时可用
locations = /,/pic
# 如果 http 基本自动用户是 abc,则将请求路由到此服务
# route_by_http_user = abc
host_header_rewrite = example.com
# 带有前缀“header_”的参数将用于更新http请求头
header_X-From-Where = frp
health_check_type = http
# frpc 将发送一个 http GET 请求 '/status' 到本地 http 服务
# 当http响应码为 2xx 时,说明服务存活
health_check_url = /status
health_check_interval_s = 10
health_check_max_failed = 3
health_check_timeout_s = 3

[web02]
type = https
local_ip = 127.0.0.1
local_port = 8000
use_encryption = false
use_compression = false
subdomain = web002
custom_domains = web02.yourdomain.com
# 如果不为空,frpc 将使用代理协议将连接信息传输到您的本地服务
# v1 或 v2 或为空
proxy_protocol_version = v2

[plugin_unix_domain_socket]
type = tcp
remote_port = 6003
# 如果定义了插件,local_ip 和 local_port 将会失效
# 插件将处理从 frps 获得的连接
plugin = unix_domain_socket
# 插件需要的带有前缀“plugin_”的参数
plugin_unix_path = /var/run/docker.sock

[plugin_http_proxy]
type = tcp
remote_port = 6004
plugin = http_proxy
plugin_http_user = abc
plugin_http_passwd = abc

[plugin_socks5]
type = tcp
remote_port = 6005
plugin = socks5
plugin_user = abc
plugin_passwd = abc

[plugin_static_file]
type = tcp
remote_port = 6006
plugin = static_file
plugin_local_path = /var/www/blog
plugin_strip_prefix = static
plugin_http_user = abc
plugin_http_passwd = abc

[plugin_https2http]
type = https
custom_domains = test.yourdomain.com
plugin = https2http
plugin_local_addr = 127.0.0.1:80
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp

[plugin_https2https]
type = https
custom_domains = test.yourdomain.com
plugin = https2https
plugin_local_addr = 127.0.0.1:443
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp

[plugin_http2https]
type = http
custom_domains = test.yourdomain.com
plugin = http2https
plugin_local_addr = 127.0.0.1:443
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp

[secret_tcp]
# 如果类型是secret tcp,remote_port将会失效
# 如果要连接本地端口的话,应该部署另一个带有stcp代理的frpc,并且角色是visitor
type = stcp
# sk 用于对访问者进行身份验证
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
use_encryption = false
use_compression = false

# frpc 的用户在 stcp 服务器和 stcp 访问者中应该是相同的
[secret_tcp_visitor]
# frpc role visitor -> frps -> frpc role server
role = visitor
type = stcp
# 要访问的服务名称
server_name = secret_tcp
sk = abcdefg
# 将此地址连接到访问者 stcp 服务器
bind_addr = 127.0.0.1
bind_port = 9000
use_encryption = false
use_compression = false

[p2p_tcp]
type = xtcp
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
use_encryption = false
use_compression = false

[p2p_tcp_visitor]
role = visitor
type = xtcp
server_name = p2p_tcp
sk = abcdefg
bind_addr = 127.0.0.1
bind_port = 9001
use_encryption = false
use_compression = false

[tcpmuxhttpconnect]
type = tcpmux
multiplexer = httpconnect
local_ip = 127.0.0.1
local_port = 10701
custom_domains = tunnel1
# route_by_http_user = user1

简单的配置

使用二级域名解析的前提条件,主域名和指定的二级域名都要指向服务器

比如主域名:365day.top,再加一条泛解析:*.365day.top,这两条记录全部解析到服务器,这样就可以在客户端随意配置 subdomain

配置 frp sever

实际使用肯定不需要那么麻烦,只需要简单的配置一下服务端和客户端即可

frps.ini 的配置示例,注意放通对应的防火墙端口

1
2
3
4
5
6
7
8
9
10
11
12
13
[common]
bind_addr = 0.0.0.0
# 自己设定的frp服务端端口
bind_port = 7000

# 自己设定的http访问端口
vhost_http_port = 80

# 认证密钥
token = 12345678

# 设置二级域名后缀,为了方便下面的解析
subdomain_host = 365day.top

我将 frpsfrps.ini 放到了 /opt/frp 目录下,将其注册为系统服务(注意给 frps 可执行权限)

1
vim /etc/systemd/system/frps.service

配置文件内容如下

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description = frp server
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /opt/frp/frps -c /opt/frp/frps.ini

[Install]
WantedBy = multi-user.target

重新载入服务的配置文件

1
systemctl daemon-reload

运行服务,并查看运行状态,没问题的话设置开机启动

1
2
3
systemctl start frps.service
systemctl status frps.service
systemctl enable frps.service

配置 frp client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[common]
# 远程frp服务器ip,也可以是域名
server_addr = 365day.top
# 端口,与服务端配置的相同
server_port = 7000
# 认证密钥,与上面配置的服务端相同
token = 12345678

#随意起个唯一的应用名
[alist_server]
type = http
local_ip = 127.0.0.1
local_port = 80
subdomain = alist

配置完成后和 frpc 放到一起,运行后就可以使用:alist.365day.top 访问 alist 服务了(我在本地开启了 alist 的服务,占用的 80 端口)

总结

这里只是简单的配置并实现了正常使用,如果需要启用 https,简单一些的还是需要配置 nginx,这里暂时不做研究。