FRP (fast reverse proxy )

证书创建

完整详细解释

第一步:创建 CA 根证书

CA(Certificate Authority)是证书颁发机构,相当于一个”公证处”,用它来签发服务端和客户端证书,建立信任链。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ============================================================
# 第一步:生成 CA 私钥
# ============================================================
openssl genrsa \
-out ca.key \ # 输出私钥文件名
4096 # 密钥长度 4096 位,比 2048 更安全,CA 用大一点没问题

# ============================================================
# 第二步:用 CA 私钥自签一张 CA 证书
# ============================================================
openssl req \
-new \ # 创建新的证书请求
-x509 \ # 直接输出自签证书(不是 CSR 请求文件)
-days 3650 \ # 有效期 3650 天(约10年),CA 证书可以长一点
-key ca.key \ # 用刚才生成的 CA 私钥签名
-out ca.crt \ # 输出 CA 证书文件
-subj "/CN=FRP CA/O=MyOrg/C=CN"
# │ │ └─ C = Country,国家代码(CN 是中国)
# │ └────────── O = Organization,组织名,随便填
# └──────────────────── CN = Common Name,证书名称,随便填

第二步:创建服务端证书

服务端证书安装在 frps 上,frpc 连接时会验证这张证书是不是由受信任的 CA 签发的。

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
# ============================================================
# 第三步:生成服务端私钥
# ============================================================
openssl genrsa \
-out server.key \ # 输出服务端私钥
2048 # 2048 位足够,普通证书用这个就行

# ============================================================
# 第四步:生成服务端 CSR(证书签名请求)
# CSR 相当于去公证处办证的"申请表",包含公钥和身份信息
# ============================================================
openssl req \
-new \ # 创建新请求
-key server.key \ # 用服务端私钥生成(CSR 里会包含对应公钥)
-out server.csr \ # 输出 CSR 文件(临时文件,签完可以删)
-subj "/CN=frps-server/O=MyOrg/C=CN" \
# └─────── CN 填服务器标识,frpc 端可能会验证这个
-addext "subjectAltName = IP:192.168.61.27"
# -subj "/C=CN/ST=Guangdong/L=Guangzhou Huangpu District/O=Self-signed Certificate/OU=Private Use/CN=yukifuhane.cn.eu.org" \
#-addext "subjectAltName = DNS:yukifuhane.cn.eu.org, DNS:192.168.6.3, IP:192.168.6.3"

# ============================================================
# 第五步:CA 用自己的私钥给服务端 CSR 签名,生成服务端证书
# ============================================================
openssl x509 \
-req \ # 输入是一个 CSR 请求文件
-days 3650 \ # 证书有效期
-in server.csr \ # 输入刚才的 CSR 文件
-CA ca.crt \ # 用 CA 证书签发(体现签发者信息)
-CAkey ca.key \ # 用 CA 私钥做签名(证明是 CA 签的)
-CAcreateserial \ # 自动创建序列号文件 ca.srl(每张证书序列号唯一)
-out server.crt # 输出最终的服务端证书
-copy_extensions copy # 复制 csr的信息,如果没有addext也是没有复制生效

1
2
3
4
5
openssl req -new -x509 -days 3650 \
-key server.key \
-out server.crt \
-subj "/C=CN/ST=Guangdong/L=Guangzhou Huangpu District/O=Self-signed Certificate/OU=Private Use/CN=yukifuhane.cn.eu.org" \
-addext "subjectAltName = DNS:yukifuhane.cn.eu.org, DNS:192.168.6.3, IP:192.168.6.3"

第三步:创建客户端证书

客户端证书安装在 frpc 上,用于双向认证(mTLS)。frps 会验证连接过来的 frpc 是否持有合法证书,防止陌生客户端接入。

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
# ============================================================
# 第六步:生成客户端私钥
# ============================================================
openssl genrsa \
-out client.key \
2048

# ============================================================
# 第七步:生成客户端 CSR
# ============================================================
openssl req \
-new \
-key client.key \
-out client.csr \
-subj "/CN=frpc-client/O=MyOrg/C=CN"
# └─────── CN 填客户端标识

# ============================================================
# 第八步:CA 签发客户端证书
# ============================================================
openssl x509 \
-req \
-days 3650 \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \ # ca.srl 已存在时会自动递增序列号
-out client.crt

信任链原理

1
2
3
4
5
6
7
8
ca.key + ca.crt  (自签,顶层信任锚)
│
├── 签发 ──▶ server.crt (frps 持有)
│ frpc 验证:这张证书是我信任的 CA 签的 ✅
│
└── 签发 ──▶ client.crt (frpc 持有)
frps 验证:这张证书是我信任的 CA 签的 ✅

双方都拿着同一个 ca.crt,谁的证书是这个 CA 签的,谁就可信。

各文件说明

1
2
3
4
5
6
[transport.tls]
force = true # 强制只接受 TLS 连接,拒绝明文
certFile = "server.crt" # 服务端证书,发给 frpc 验证
keyFile = "server.key" # 服务端私钥,用于 TLS 握手解密
trustedCaFile = "ca.crt" # 用这个 CA 验证客户端证书(双向认证)

没啥关系,下面内容

自建CA证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
default_md = sha256

[req_distinguished_name]
C = CN
ST = Shanghai
L = Shanghai
O = MyCompanyCA
OU = Security_Dept
CN = My_Private_Root_CA

[v3_ca]
# 🔴 关键联动参数:声明这是一个真正的 CA 根证书,有权去签发别人
basicConstraints = critical, CA:TRUE

# CA 证书的标配用途:允许签发证书(keyCertSign)和签发吊销列表(cRLSign)
keyUsage = critical, keyCertSign, cRLSign

subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
1
2
3
4
5
6
# 1. 生成 CA 的私钥
openssl genrsa -out ca.key 4048

# 2. 直接生成自签名的 CA 根证书 (ca.crt)
openssl req -x509 -new -nodes -key ca.key -sha256 -days 36500 \
-out ca.crt -config ca.cnf

标准服务器证书

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
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
default_md = sha256

[req_distinguished_name]
# 证书的主体信息,现代浏览器其实不校验这些,但规范上建议填写
C = CN
ST = Shanghai
L = Shanghai
O = MyCompany
OU = IT
CN = my-service.local

[v3_req]
# 基础约束:明确声明这不是一个 CA 证书,只是一个最终节点证书
basicConstraints = critical, CA:FALSE

# 密钥用途:支持数字签名和密钥加密(完美兼容 TLS 1.2 和 TLS 1.3)
keyUsage = critical, digitalSignature, keyEncipherment

# 扩展密钥用途:同时支持作为服务端和客户端(一套证书可用于双向认证 mTLS)
extendedKeyUsage = serverAuth, clientAuth

# 密钥标识符:方便客户端追踪证书链
subjectKeyIdentifier = hash

# 核心:指向下方的域名和 IP 列表
subjectAltName = @alt_names

[alt_names]
# 🔴 根据你的实际情况修改下方的域名和 IP
DNS.1 = www.example.com
DNS.2 = api.example.com
DNS.3 = *.test.internal # 支持泛域名
IP.1 = 192.168.1.100 # 支持内网 IP
IP.2 = 10.0.0.1
1
2
3
4
5
6
7
8
9
# 1. 生成服务器私钥
openssl genrsa -out server.key 2048

# 2. 生成证书请求 (CSR)
openssl req -new -key server.key -out server.csr -config server.cnf

# 3. 使用自建 CA 签发最终的服务器证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 3650 -extensions v3_req -extfile server.cnf

frps_example

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
# 此配置文件仅供参考。请勿直接使用此配置运行程序,可能存在各种问题。

# IPv6 的字面地址或主机名必须用方括号括起来,
# 例如 "[::1]:80"、"[ipv6-host]:http" 或 "[ipv6-host%zone]:80"
# 对于单独的 "bindAddr" 字段,不需要方括号,如 `bindAddr = "::"`.
bindAddr = "0.0.0.0"
bindPort = 7000

# 用于 kcp 协议的 udp 端口,可以与 'bindPort' 相同。
# 如果不设置,frps 中的 kcp 将被禁用。
kcpBindPort = 7000

# 用于 quic 协议的 udp 端口。
# 如果不设置,quic 将被禁用。
# quicBindPort = 7002

# 指定代理监听的地址,默认值与 bindAddr 相同
# proxyBindAddr = "127.0.0.1"

# quic 协议选项
# transport.quic.keepalivePeriod = 10
# transport.quic.maxIdleTimeout = 30
# transport.quic.maxIncomingStreams = 100000

# 心跳配置,不建议修改默认值
# heartbeatTimeout 的默认值为 90,设置为负值可禁用。
# transport.heartbeatTimeout = 90

# 每个代理连接池保持的连接数不超过 maxPoolCount。
transport.maxPoolCount = 5

# 是否使用 tcp 流多路复用,默认为 true
# transport.tcpMux = true

# 指定 tcp 多路复用的保活间隔。
# 仅在 tcpMux 为 true 时有效。
# transport.tcpMuxKeepaliveInterval = 30

# tcpKeepalive 指定 frpc 与 frps 之间活跃网络连接的保活探测间隔。
# 如果为负值,则禁用保活探测。
# transport.tcpKeepalive = 7200

# transport.tls.force 指定是否只接受 TLS 加密连接。默认值为 false。
transport.tls.force = false

# transport.tls.certFile = "server.crt"
# transport.tls.keyFile = "server.key"
# transport.tls.trustedCaFile = "ca.crt"

# 如果需要支持虚拟主机,必须设置 http 监听端口(可选)
# 注意:http 端口和 https 端口可以与 bindPort 相同
vhostHTTPPort = 80
vhostHTTPSPort = 443

# 虚拟主机 http 服务器的响应头超时时间(秒),默认为 60s
# vhostHTTPTimeout = 60

# tcpmuxHTTPConnectPort 指定服务器监听 TCP HTTP CONNECT 请求的端口。
# 如果值为 0,服务器不会在单个端口上多路复用 TCP 请求。
# 如果不为 0,则会在此端口监听 HTTP CONNECT 请求。默认值为 0。
# tcpmuxHTTPConnectPort = 1337

# 如果 tcpmuxPassthrough 为 true,frps 不会对流量做任何处理。
# tcpmuxPassthrough = false

# 配置 Web 服务器以启用 frps 的控制台。
# 只有设置了 webServer.port 才能使用控制台。
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin"
# webServer.tls.certFile = "server.crt"
# webServer.tls.keyFile = "server.key"
# 控制台静态资源目录(仅用于调试模式)
# webServer.assetsDir = "./static"

# 在控制台监听器中启用 golang pprof 处理器。
# 必须先设置控制台端口
webServer.pprofEnable = false

# enablePrometheus 将在 webServer 的 /metrics 接口导出 prometheus 指标。
enablePrometheus = true

# 日志输出为 console 或实际日志文件路径,如 ./frps.log
log.to = "./frps.log"
# 日志级别:trace、debug、info、warn、error
log.level = "info"
log.maxDays = 3
# 当 log.to 为 console 时禁用日志颜色,默认为 false
log.disablePrintColor = false

# detailedErrorsToClient 定义是否将具体错误信息(含调试信息)发送给 frpc。默认值为 true。
detailedErrorsToClient = true

# auth.method 指定用于 frpc 与 frps 认证的方式。
# 如果指定 "token",token 将被读入登录消息。
# 如果指定 "oidc",将使用 OIDC 设置签发 OIDC(Open ID Connect)token。默认值为 "token"。
auth.method = "token"

# auth.additionalScopes 指定认证信息中包含的额外作用域。
# 可选值为 HeartBeats、NewWorkConns。
# auth.additionalScopes = ["HeartBeats", "NewWorkConns"]

# 认证 token
auth.token = "12345678"

# 也可以使用 tokenSource 从文件加载 token
# 与 auth.token 互斥
# auth.tokenSource.type = "file"
# auth.tokenSource.file.path = "/etc/frp/token"

# oidc issuer 指定用于验证 OIDC token 的签发者。
auth.oidc.issuer = ""
# oidc audience 指定验证时 OIDC token 应包含的受众。
auth.oidc.audience = ""
# oidc skipExpiryCheck 指定是否跳过 OIDC token 过期检查。
auth.oidc.skipExpiryCheck = false
# oidc skipIssuerCheck 指定是否跳过 OIDC token 签发者与 OidcIssuer 的匹配检查。
auth.oidc.skipIssuerCheck = false

# userConnTimeout 指定等待工作连接的最长时间。
# userConnTimeout = 10

# 只允许 frpc 绑定列出的端口。默认情况下没有任何限制。
allowPorts = [
{ start = 2000, end = 3000 },
{ single = 3001 },
{ single = 3003 },
{ start = 4000, end = 50000 }
]

# 每个客户端可使用的最大端口数,默认值为 0 表示不限制
maxPortsPerClient = 0

# 如果 subDomainHost 不为空,可在 frpc 配置文件中为 http 或 https 类型设置子域名
# 当子域名为 test 时,路由使用的主机为 test.frps.com
subDomainHost = "frps.com"

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

# 指定 udp 数据包大小,单位为字节。如果不设置,默认值为 1500。
# 此参数在客户端和服务端应保持一致。
# 影响 udp 和 sudp 代理。
udpPacketSize = 1500

# NAT 打洞策略数据的保留时间。
natholeAnalysisDataReserveHours = 168

# ssh 隧道网关
# 如果要启用此功能,bindPort 参数是必须的,其他参数可选。
# 默认情况下此功能禁用,当 bindPort 大于 0 时将启用。
# sshTunnelGateway.bindPort = 2200
# sshTunnelGateway.privateKeyFile = "/home/frp-user/.ssh/id_rsa"
# sshTunnelGateway.autoGenPrivateKeyPath = ""
# sshTunnelGateway.authorizedKeysFile = "/home/frp-user/.ssh/authorized_keys"

[[httpPlugins]]
name = "user-manager"
addr = "127.0.0.1:9000"
path = "/handler"
ops = ["Login"]

[[httpPlugins]]
name = "port-manager"
addr = "127.0.0.1:9001"
path = "/handler"
ops = ["NewProxy"]

frpc_example

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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# 此配置文件仅供参考。请勿直接使用此配置运行程序,因为可能存在各种问题。

# 此 frpc 实例的可选唯一标识符。
clientID = "your_client_id"
# 你的代理名称将被更改为 {user}.{proxy}
user = "your_name"

# IPv6 的字面地址或主机名必须用方括号括起来,
# 例如 "[::1]:80"、"[ipv6-host]:http" 或 "[ipv6-host%zone]:80"
# 对于单独的 serverAddr 字段,无需方括号,如 serverAddr = "::"。
serverAddr = "0.0.0.0"
serverPort = 7000

# 用于帮助穿透 NAT 的 STUN 服务器。
# natHoleStunServer = "stun.easyvoip.com:3478"

# 决定首次登录失败时是否退出程序,否则持续重新登录到 frps
# 默认值为 true
loginFailExit = true

# console 或实际日志文件路径,如 ./frpc.log
log.to = "./frpc.log"
# trace, debug, info, warn, error
log.level = "info"
log.maxDays = 3
# 当 log.to 为 console 时禁用日志颜色,默认值为 false
log.disablePrintColor = false

auth.method = "token"
# auth.additionalScopes 指定包含认证信息的附加作用域。
# 可选值为 HeartBeats、NewWorkConns。
# auth.additionalScopes = ["HeartBeats", "NewWorkConns"]

# 认证 token
auth.token = "12345678"

# 或者,你可以使用 tokenSource 从文件加载 token
# 这与 auth.token 互斥
# auth.tokenSource.type = "file"
# auth.tokenSource.file.path = "/etc/frp/token"

# oidc.clientID 指定在 OIDC 认证中用于获取 token 的客户端 ID。
# auth.oidc.clientID = ""
# oidc.clientSecret 指定在 OIDC 认证中用于获取 token 的客户端密钥。
# auth.oidc.clientSecret = ""
# oidc.audience 指定 OIDC 认证中 token 的受众。
# auth.oidc.audience = ""
# oidc.scope 在 AuthenticationMethod == "oidc" 时指定 OIDC 认证中 token 的权限。默认值为 ""。
# auth.oidc.scope = ""
# oidc.tokenEndpointURL 指定实现 OIDC Token 端点的 URL。
# 将用于获取 OIDC token。
# auth.oidc.tokenEndpointURL = ""

# oidc.additionalEndpointParams 指定发送到 OIDC Token 端点的附加参数。
# 例如,如果要指定 "audience" 参数,可以如下设置。
# frp 将把 "audience=<value>" "var1=<value>" 添加到附加参数中。
# auth.oidc.additionalEndpointParams.audience = "https://dev.auth.com/api/v2/"
# auth.oidc.additionalEndpointParams.var1 = "foobar"

# OIDC TLS 和代理配置
# 指定用于验证 OIDC token 端点 TLS 证书的自定义 CA 证书文件。
# 当 OIDC 提供商使用自签名证书或自定义 CA 时非常有用。
# auth.oidc.trustedCaFile = "/path/to/ca.crt"

# 跳过 OIDC token 端点的 TLS 证书验证。
# 不安全:仅用于调试目的,不建议在生产环境中使用。
# auth.oidc.insecureSkipVerify = false

# 为 OIDC token 端点连接指定代理服务器。
# 支持 http、https、socks5 和 socks5h 代理协议。
# 如果未指定,OIDC 连接不使用代理。
# auth.oidc.proxyURL = "http://proxy.example.com:8080"

# 设置管理地址,用于通过 http api 控制 frpc 的操作,如重新加载
webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "admin"
# 管理资源目录。默认情况下,这些资源与 frpc 打包在一起。
# webServer.assetsDir = "./static"

# 在管理监听器中启用 golang pprof 处理器。
webServer.pprofEnable = false

# 连接服务器的最长等待时间。默认值为 10 秒。
# transport.dialServerTimeout = 10

# dialServerKeepalive 指定 frpc 和 frps 之间活跃网络连接的保活探测间隔。
# 如果为负值,则禁用保活探测。
# transport.dialServerKeepalive = 7200

# 预先建立的连接数,默认值为 0
transport.poolCount = 5

# 是否使用 TCP 流多路复用,默认为 true,必须与 frps 保持一致
# transport.tcpMux = true

# 指定 TCP 多路复用的保活间隔。
# 仅在启用 tcpMux 时有效。
# transport.tcpMuxKeepaliveInterval = 30

# 连接服务器使用的通信协议
# 目前支持 tcp、kcp、quic、websocket 和 wss,默认为 tcp
transport.protocol = "tcp"

# 在所选传输层内使用的 FRP 线协议。
# 支持 v1 和 v2,默认为 v1。v2 需要 frps 支持且必须显式启用。
# transport.wireProtocol = "v1"

# 连接服务器时设置客户端绑定 IP,默认为空。
# 仅当 protocol = tcp 或 websocket 时,该值才会生效。
transport.connectServerLocalIP = "0.0.0.0"

# 如果想通过 http 代理、socks5 代理或 ntlm 代理连接 frps,可以在此处或全局环境变量中设置 proxyURL
# 仅在协议为 tcp 时有效
# transport.proxyURL = "http://user:passwd@192.168.1.128:8080"
# transport.proxyURL = "socks5://user:passwd@192.168.1.128:1080"
# transport.proxyURL = "ntlm://user:passwd@192.168.1.128:2080"

# quic 协议选项
# transport.quic.keepalivePeriod = 10
# transport.quic.maxIdleTimeout = 30
# transport.quic.maxIncomingStreams = 100000

# 如果 tls.enable 为 true,frpc 将通过 TLS 连接 frps。
# 自 v0.50.0 起,默认值已更改为 true,默认启用 TLS。
transport.tls.enable = true

# transport.tls.certFile = "client.crt"
# transport.tls.keyFile = "client.key"
# transport.tls.trustedCaFile = "ca.crt"
# transport.tls.serverName = "example.com"

# 如果 disableCustomTLSFirstByte 设置为 false,则在启用 TLS 时,
# frpc 将使用第一个自定义字节与 frps 建立连接。
# 自 v0.50.0 起,默认值已更改为 true,默认禁用第一个自定义字节。
# transport.tls.disableCustomTLSFirstByte = true

# 心跳配置,不建议修改默认值。
# heartbeatInterval 默认值为 10,heartbeatTimeout 默认值为 90。设置负值
# 可禁用心跳。
# transport.heartbeatInterval = 30
# transport.heartbeatTimeout = 90

# 指定 DNS 服务器,frpc 将使用此服务器而非默认服务器
# dnsServer = "8.8.8.8"

# 要启动的代理名称列表。
# 默认为空,表示启动所有代理。
# 此列表是配置与存储合并后的全局允许列表,因此通过 Store API 创建的条目也会被此列表过滤。
# 如果 start 非空,任何未在此列出的代理/访问者都不会被启动。
# start = ["ssh", "dns"]

# 'start' 的替代方案:你可以使用 'enabled' 字段单独控制每个代理。
# 在代理配置中设置 'enabled = false' 可禁用该代理。
# 如果未设置 'enabled' 或设置为 true,则默认启用该代理。
# 'enabled' 字段提供更精细的控制,推荐使用而非 'start'。

# 指定 UDP 数据包大小,单位为字节。如果未设置,默认值为 1500。
# 此参数在客户端和服务端之间应保持一致。
# 影响 udp 和 sudp 代理。
udpPacketSize = 1500

# 功能开关允许你启用或禁用实验性功能
# 格式为功能名称到布尔值的映射
# 你可以启用特定功能:
#featureGates = { VirtualNet = true }

# 实验性虚拟网络功能的 VirtualNet 设置
# 虚拟网络功能需要启用上方的 VirtualNet 功能开关
# virtualNet.address = "100.86.1.1/24"

# 客户端的附加元数据。
metadatas.var1 = "abc"
metadatas.var2 = "123"

# 引入其他代理配置文件。
# includes = ["./confd/*.ini"]

[[proxies]]
# 'ssh' 是唯一的代理名称
# 如果全局 user 不为空,将被更改为 {user}.{proxy},如 'your_name.ssh'
name = "ssh"
type = "tcp"
# 启用或禁用此代理。true 或省略此字段表示启用,false 表示禁用。
# enabled = true
localIP = "127.0.0.1"
localPort = 22
# 限制此代理的带宽,单位为 KB 和 MB
transport.bandwidthLimit = "1MB"
# 限制带宽的位置,可以是 'client' 或 'server',默认为 'client'
transport.bandwidthLimitMode = "client"
# 如果为 true,此代理的流量将被加密,默认为 false
transport.useEncryption = false
# 如果为 true,流量将被压缩
transport.useCompression = false
# frps 监听的远程端口
remotePort = 6001
# frps 将对同一组中的代理进行负载均衡
loadBalancer.group = "test_group"
# 同组代理应具有相同的组密钥
loadBalancer.groupKey = "123456"
# 为后端服务启用健康检查,目前支持 'tcp' 和 'http'。
# frpc 将连接本地服务端口以检测其健康状态
healthCheck.type = "tcp"
# 健康检查连接超时时间
healthCheck.timeoutSeconds = 3
# 如果连续失败 3 次,该代理将从 frps 中移除
healthCheck.maxFailed = 3
# 每 10 秒执行一次健康检查
healthCheck.intervalSeconds = 10
# 每个代理的附加元信息。将传递给服务端插件使用。
metadatas.var1 = "abc"
metadatas.var2 = "123"
# 你可以通过注解为代理添加一些额外信息。
# 这些注解将显示在 frps 控制面板上。
[proxies.annotations]
key1 = "value1"
"prefix/key2" = "value2"

[[proxies]]
name = "ssh_random"
type = "tcp"
localIP = "192.168.31.100"
localPort = 22
# 如果 remotePort 为 0,frps 将为你分配一个随机端口
remotePort = 0

[[proxies]]
name = "dns"
type = "udp"
localIP = "114.114.114.114"
localPort = 53
remotePort = 6002

# 将你的域名解析到 [serverAddr],这样你就可以通过 http://web01.yourdomain.com 访问 web01,通过 http://web02.yourdomain.com 访问 web02
[[proxies]]
name = "web01"
type = "http"
localIP = "127.0.0.1"
localPort = 80
# http 用户名和密码是 http 协议的安全认证
# 如果未设置,可以不经认证访问此 customDomains
httpUser = "admin"
httpPassword = "admin"
# 如果 frps 的域名是 frps.com,则可以通过 URL http://web01.frps.com 访问 [web01] 代理
subdomain = "web01"
customDomains = ["web01.yourdomain.com"]
# locations 仅适用于 http 类型
locations = ["/", "/pic"]
# 如果 http 基础认证用户为 abc,则将请求路由到此服务
# routeByHTTPUser = abc
hostHeaderRewrite = "example.com"
requestHeaders.set.x-from-where = "frp"
responseHeaders.set.foo = "bar"
healthCheck.type = "http"
# frpc 将向本地 http 服务发送 GET 请求 '/status'
# 当返回 2xx HTTP 响应码时,认为 http 服务存活
healthCheck.path = "/status"
healthCheck.intervalSeconds = 10
healthCheck.maxFailed = 3
healthCheck.timeoutSeconds = 3
# 设置健康检查请求头
healthCheck.httpHeaders=[
{ name = "x-from-where", value = "frp" }
]

[[proxies]]
name = "web02"
type = "https"
# 通过将 enabled 设置为 false 来禁用此代理
# enabled = false
localIP = "127.0.0.1"
localPort = 8000
subdomain = "web02"
customDomains = ["web02.yourdomain.com"]
# 如果不为空,frpc 将使用代理协议将连接信息传输到本地服务
# v1 或 v2 或空
transport.proxyProtocolVersion = "v2"

[[proxies]]
name = "tcpmuxhttpconnect"
type = "tcpmux"
multiplexer = "httpconnect"
localIP = "127.0.0.1"
localPort = 10701
customDomains = ["tunnel1"]
# routeByHTTPUser = "user1"

[[proxies]]
name = "plugin_unix_domain_socket"
type = "tcp"
remotePort = 6003
# 如果定义了 plugin,localIP 和 localPort 将不起作用
# plugin 将处理从 frps 获取的连接
[proxies.plugin]
type = "unix_domain_socket"
unixPath = "/var/run/docker.sock"

[[proxies]]
name = "plugin_http_proxy"
type = "tcp"
remotePort = 6004
[proxies.plugin]
type = "http_proxy"
httpUser = "abc"
httpPassword = "abc"

[[proxies]]
name = "plugin_socks5"
type = "tcp"
remotePort = 6005
[proxies.plugin]
type = "socks5"
username = "abc"
password = "abc"

[[proxies]]
name = "plugin_static_file"
type = "tcp"
remotePort = 6006
[proxies.plugin]
type = "static_file"
localPath = "/var/www/blog"
stripPrefix = "static"
httpUser = "abc"
httpPassword = "abc"

[[proxies]]
name = "plugin_https2http"
type = "https"
customDomains = ["test.yourdomain.com"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:80"
crtPath = "./server.crt"
keyPath = "./server.key"
hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp"

[[proxies]]
name = "plugin_https2https"
type = "https"
customDomains = ["test.yourdomain.com"]
[proxies.plugin]
type = "https2https"
localAddr = "127.0.0.1:443"
crtPath = "./server.crt"
keyPath = "./server.key"
hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp"

[[proxies]]
name = "plugin_http2https"
type = "http"
customDomains = ["test.yourdomain.com"]
[proxies.plugin]
type = "http2https"
localAddr = "127.0.0.1:443"
hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp"

[[proxies]]
name = "plugin_http2http"
type = "tcp"
remotePort = 6007
[proxies.plugin]
type = "http2http"
localAddr = "127.0.0.1:80"
hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp"

[[proxies]]
name = "plugin_tls2raw"
type = "tcp"
remotePort = 6008
[proxies.plugin]
type = "tls2raw"
localAddr = "127.0.0.1:80"
crtPath = "./server.crt"
keyPath = "./server.key"

[[proxies]]
name = "secret_tcp"
# 如果类型为 secret tcp,remotePort 将不起作用
# 想要连接本地端口的人应部署另一个 frpc,配置 stcp 代理且角色为 visitor
type = "stcp"
# secretKey 用于对访问者进行身份验证
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22
# 如果不为空,则只有来自指定用户的访问者才能连接。
# 否则,来自同一用户的访问者可以连接。'*' 表示允许所有用户。
allowUsers = ["*"]

[[proxies]]
name = "p2p_tcp"
type = "xtcp"
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22
# 如果不为空,则只有来自指定用户的访问者才能连接。
# 否则,来自同一用户的访问者可以连接。'*' 表示允许所有用户。
allowUsers = ["user1", "user2"]

# NAT 穿透配置(可选)
[proxies.natTraversal]
# 禁止使用本地网络接口(辅助地址)进行 NAT 穿透。
# 启用后,将只使用 STUN 发现的公共地址。
# 当你有较慢的 VPN 连接时,这可以提升性能。
# 默认值:false
disableAssistedAddrs = false

[[proxies]]
name = "vnet-server"
type = "stcp"
secretKey = "your-secret-key"
[proxies.plugin]
type = "virtual_net"

# frpc 角色 visitor -> frps -> frpc 角色 server
[[visitors]]
name = "secret_tcp_visitor"
type = "stcp"
# 你想要访问的服务名称
serverName = "secret_tcp"
secretKey = "abcdefg"
# 连接此地址以访问 stcp 服务端
bindAddr = "127.0.0.1"
# bindPort 可以小于 0,表示不绑定到该端口,仅接收从其他访问者重定向的连接。
# (目前 SUDP 不支持此功能)
bindPort = 9000

[[visitors]]
name = "p2p_tcp_visitor"
type = "xtcp"
# 如果未设置服务端用户,默认为当前用户
serverUser = "user1"
serverName = "p2p_tcp"
secretKey = "abcdefg"
bindAddr = "127.0.0.1"
# bindPort 可以小于 0,表示不绑定到该端口,仅接收从其他访问者重定向的连接。
# (目前 SUDP 不支持此功能)
bindPort = 9001
# 当需要自动保持隧道持久连接时,设置为 true
keepTunnelOpen = false
# 当 keepTunnelOpen 设置为 true 时生效,每小时尝试打洞的次数
maxRetriesAnHour = 8
minRetryInterval = 90
# fallbackTo = "stcp_visitor"
# fallbackTimeoutMs = 500

# NAT 穿透配置(可选)
[visitors.natTraversal]
# 禁止使用本地网络接口(辅助地址)进行 NAT 穿透。
# 启用后,将只使用 STUN 发现的公共地址。
# 默认值:false
disableAssistedAddrs = false

[[visitors]]
name = "vnet-visitor"
type = "stcp"
serverName = "vnet-server"
secretKey = "your-secret-key"
bindPort = -1
[visitors.plugin]
type = "virtual_net"
destinationIP = "100.86.0.1"