首页
/ frp 完全实战指南:内网穿透、代理类型与安全调优的全景式参考

frp 完全实战指南:内网穿透、代理类型与安全调优的全景式参考

2026-09-04 09:52:11作者:谭伦延

本文基于 frp 官方 README 及配套源码、配置文件撰写,系统讲解 frp 如何将位于 NAT 或防火墙之后的本地服务暴露到公网:从 frps/frpc 部署模型、TCP/UDP/HTTP/HTTPS/STCP/P2P 各类代理的完整配置实操,到认证、TLS 加密、传输协议调优、负载均衡与健康检查、可观测性体系。读完本文,你可以独立完成一套带安全加固与运维能力的 frp 内网穿透环境,并理解其配置加载与特性开关的源码实现。

frp 架构示意图

一、frp 是什么:定位与部署模型

frp 是一个快速的反向代理工具,用于将位于 NAT 或防火墙之后的本地服务器暴露到互联网。它支持 TCPUDP 协议,以及 HTTPHTTPS 协议(可通过域名将请求转发到内网服务),并提供基于打洞的 P2P 直连模式

从架构上看,frp 由两个独立进程组成:

  • frps(server):部署在拥有公网 IP 的机器(如 Server A)上,负责对外监听端口、接收 frpc 的注册、代理用户流量;
  • frpc(client):部署在局域网内无法被公网直接访问的机器(Server B)上,主动连接 frps 并上报本地服务。

使用方式:从项目的 Release 页面下载对应操作系统与架构的最新程序,将 frps 二进制与服务器配置文件放到 Server A,将 frpc 二进制与客户端配置文件放到 Server B。仓库中的 frps 入口frpc 入口 分别基于 cobra 构建命令行,也提供 Dockerfile-for-frpsDockerfile-for-frpc 用于容器化部署。

一个常见的注意事项:部分杀毒软件会将 frpc 误报为恶意软件并删除。原因是 frp 作为网络工具可以创建反向代理、绕过防火墙端口限制,这类特征容易被误判。如果你使用了杀毒软件,需要在设置中将 frpc 加入白名单。

开发状态与 V2 规划

frp 当前处于持续开发中:master 分支对应最新 release 版本,dev 分支对应开发中版本。作者正在规划 V2 版本,核心是基于云原生领域(K8s、ServiceMesh)经验重构出一个现代化的四层/七层代理内核(类似 envoy),使 frp 本身成为一个高度可扩展的平台,并提供类似 K8s 的扩展能力(CRD、controller、webhook 等);同时 v2 将与 v1 不兼容。在 V2 完成之前,当前 v1 版本会持续接受优化迭代。

二、典型场景部署实操

2.1 通过 SSH 访问局域网内电脑

  1. 在 Server A 上修改 frps.toml,设置 frpc 连接端口:
# frps.toml
bindPort = 7000
  1. 在 Server A 上启动 frps:
./frps -c ./frps.toml
  1. 在 Server B 上修改 frpc.tomlserverAddr 填 frps 的公网 IP:
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

注意三个端口的角色区别:localPort(客户端监听的本地端口)和 remotePort(frps 上暴露的端口)是业务流量进出 frp 体系的端口,而 serverPort 是 frps 与 frpc 之间的控制通信端口。

  1. 在 Server B 上启动 frpc:
./frpc -c ./frpc.toml
  1. 从其他机器通过 Server A 以 SSH 访问 Server B(假设用户名为 test):
ssh -oPort=6000 test@x.x.x.x

2.2 多个 SSH 服务共享同一端口(tcpmux)

利用 tcpmux 类型代理 + HTTP CONNECT 多路复用,可以将多台内网机器的 SSH 服务暴露在同一端口上。只要客户端支持 HTTP Connect 代理方式,都能用这种方式实现端口复用:

  1. 在公网机器上部署 frps,简化配置如下:
bindPort = 7000
tcpmuxHTTPConnectPort = 5002
  1. 在内网机器 A 上部署 frpc:
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "ssh1"
type = "tcpmux"
multiplexer = "httpconnect"
customDomains = ["machine-a.example.com"]
localIP = "127.0.0.1"
localPort = 22
  1. 在内网机器 B 上部署另一个 frpc,仅域名不同:
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "ssh2"
type = "tcpmux"
multiplexer = "httpconnect"
customDomains = ["machine-b.example.com"]
localIP = "127.0.0.1"
localPort = 22
  1. 使用 SSH ProxyCommand 访问机器 A(假设用户名 test):
ssh -o 'proxycommand socat - PROXY:x.x.x.x:%h:%p,proxyport=5002' test@machine-a.example.com
  1. 访问机器 B 只是换域名:
ssh -o 'proxycommand socat - PROXY:x.x.x.x:%h:%p,proxyport=5002' test@machine-b.example.com

2.3 用自定义域名访问内网 Web 服务

由于域名无法解析到本地 IP,可以用 frp 暴露 HTTP(S) 服务:

  1. 修改 frps.toml,设置 vhost HTTP 端口(如需 HTTPS 代理则再配置 vhostHTTPSPort):
# frps.toml
bindPort = 7000
vhostHTTPPort = 8080
  1. 启动 ./frps -c ./frps.toml

  2. 修改 frpc.toml,指定 Web 服务的 localPort

# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["www.example.com"]
  1. 启动 ./frpc -c ./frpc.toml

  2. www.example.com 的 A 记录指向 frps 公网 IP,或配置 CNAME 指向你的原始域名。

  3. 通过 http://www.example.com:8080 访问本地 Web 服务。

2.4 转发 DNS 查询请求(UDP)

frps.toml 配置 bindPort = 7000 后启动,frpc.toml 中将 DNS 查询转发到 8.8.8.8:53

# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "dns"
type = "udp"
localIP = "8.8.8.8"
localPort = 53
remotePort = 6000

启动 frpc 后,用 dig 命令测试解析:

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

2.5 转发 Unix Domain Socket

将 Unix domain socket(例如 Docker 守护进程 socket)以 TCP 形式暴露:

# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "unix_domain_socket"
type = "tcp"
remotePort = 6000
[proxies.plugin]
type = "unix_domain_socket"
unixPath = "/var/run/docker.sock"

curl 验证(获取 docker version):

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

2.6 暴露一个简单的 HTTP 文件服务器

# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "test_static_file"
type = "tcp"
remotePort = 6000
[proxies.plugin]
type = "static_file"
localPath = "/tmp/files"
stripPrefix = "static"
httpUser = "abc"
httpPassword = "abc"

在浏览器访问 http://x.x.x.x:6000/static/,输入正确用户名和密码即可查看 frpc 机器上 /tmp/files 目录的文件。

2.7 为本地 HTTP(S) 服务启用 HTTPS

使用 https2http 插件在 frps 侧终止 TLS,转发到内网 HTTP 服务(也可用 https2httpslocalAddr 指向 HTTPS 端点):

# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "test_https2http"
type = "https"
customDomains = ["test.example.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"

之后访问 https://test.example.com 即可。

2.8 私有暴露服务:STCP 模式

STCP(Secret TCP)模式要求访问方持有预共享密钥,降低服务直接暴露公网的风险。

  1. 在机器 B 上以 stcp 类型暴露 SSH(注意 secretKey 字段,且此时没有 remotePort):
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "secret_ssh"
type = "stcp"
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22
  1. 在机器 C 上再运行一个 frpc,通过 [[visitors]] 段以安全密钥访问:
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[visitors]]
name = "secret_ssh_visitor"
type = "stcp"
serverName = "secret_ssh"
secretKey = "abcdefg"
bindAddr = "127.0.0.1"
bindPort = 6000
  1. 在机器 C 上连接机器 B 的 SSH:
ssh -oPort=6000 127.0.0.1

2.9 P2P 模式:xtcp

xtcp 用于让客户端之间直连传输大量数据;frps 服务器仍然需要,只是实际数据传输走 P2P 通道。注意它并非对所有 NAT 类型都有效,xtcp 不通时可以回退到 stcp。

  1. 机器 B 上暴露 SSH 端口(natHoleStunServer 可在默认 STUN 服务不可用时自行部署):
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
# set up a new stun server if the default one is not available.
# natHoleStunServer = "xxx"

[[proxies]]
name = "p2p_ssh"
type = "xtcp"
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22
  1. 机器 C 上以 P2P 模式访问:
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
# set up a new stun server if the default one is not available.
# natHoleStunServer = "xxx"

[[visitors]]
name = "p2p_ssh_visitor"
type = "xtcp"
serverName = "p2p_ssh"
secretKey = "abcdefg"
bindAddr = "127.0.0.1"
bindPort = 6000
# when automatic tunnel persistence is required, set it to true
keepTunnelOpen = false
  1. 在机器 C 上执行 ssh -oPort=6000 127.0.0.1 即可连接机器 B 的 SSH。打洞相关的 NAT 类型分析逻辑位于 nathole 模块

三、配置文件体系

自 v0.52.0 起,frp 支持 TOML、YAML 和 JSON 三种配置格式;INI 已废弃并将在未来版本移除——新特性只会在 TOML/YAML/JSON 中提供,需要新特性的用户应迁移配置格式。INI 旧配置仍可通过 legacy 转换层 自动转换,运行时控制台会打印迁移警告(见 frpc 客户端启动流程)。

完整的参考配置(仅用于查阅参数,不建议直接运行):

使用环境变量

配置文件支持 Go 标准模板语法引用环境变量,引用必须带 .Envs 前缀:

# frpc.toml
serverAddr = "{{ .Envs.FRP_SERVER_ADDR }}"
serverPort = 7000

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = {{ .Envs.FRP_SSH_REMOTE_PORT }}

以环境变量方式传入并运行:

export FRP_SERVER_ADDR=x.x.x.x
export FRP_SSH_REMOTE_PORT=6000
./frpc -c ./frpc.toml

拆分配置到多个文件

主文件通过 includes 引入目录下的多个代理配置(支持通配符),实现在 配置加载器 中:

# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
includes = ["./confd/*.toml"]
# ./confd/test.toml
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

端口区间批量映射

利用 Go 模板的 range 语法与内置函数 parseNumberRangePair,一条模板可展开出多个代理(以下示例生成 test-6000test-6007 共 8 个代理,远程端口映射到本地同端口):

{{- range $_, $v := parseNumberRangePair "6000-6006,6007" "6000-6006,6007" }}
[[proxies]]
name = "tcp-{{ $v.First }}"
type = "tcp"
localPort = {{ $v.First }}
remotePort = {{ $v.Second }}
{{- end }}

从源码结构看,模板渲染发生在配置解析之前:RenderWithTemplateparseNumberRangeparseNumberRangePair 注册为模板函数,再按扩展名(.toml/.yaml/.yml/.json)检测格式并反序列化;两个二进制默认启用 strict_config 严格模式(未知字段直接报错),格式检测见 detectFormatFromPath

四、客户端认证

frpc 与 frps 之间的认证方式由两侧的 auth.method 决定,默认是 token。

  • auth.additionalScopes = ["HeartBeats"]:让每次心跳都携带并校验认证信息;
  • auth.additionalScopes = ["NewWorkConns"]:让每条新的工作连接都携带并校验认证信息。

Token 认证

frpc.tomlfrps.toml 中同时指定 auth.method = "token" 和相同的 auth.token,frpc 即可通过 frps 校验。

Token Source:支持通过 tokenSource 从外部来源读取 token,目前支持文件方式,适用于 token 由外部系统管理或需要与配置文件分离的场景:

# frpc.toml
auth.method = "token"
auth.tokenSource.type = "file"
auth.tokenSource.file.path = "/path/to/token/file"

token 在启动时从指定文件读取,与 auth.token 互斥。

OIDC 认证

在两侧指定 auth.method = "oidc" 后启用 OIDC(OpenID Connect)认证,使用的授权流程是 Client Credentials Grant。服务端配置 issuer 与 audience,客户端配置 clientID、clientSecret 等:

# frps.toml
auth.method = "oidc"
auth.oidc.issuer = "https://example-oidc-issuer.com/"
auth.oidc.audience = "https://oidc-audience.com/.default"
# frpc.toml
auth.method = "oidc"
auth.oidc.clientID = "98692467-37de-409a-9fac-bb2585826f18" # 替换为你的 OIDC client ID
auth.oidc.clientSecret = "oidc_secret"
auth.oidc.audience = "https://oidc-audience.com/.default"
auth.oidc.tokenEndpointURL = "https://example-oidc-endpoint.com/oauth2/v2.0/token"

frpc 侧还支持 auth.oidc.scopeauth.oidc.additionalEndpointParamsauth.oidc.trustedCaFile(自定义 CA)、auth.oidc.proxyURL(token 端点走代理,支持 http/https/socks5/socks5h)等扩展参数,详见 frpc 完整配置示例。OIDC 的客户端凭据签发与令牌校验实现位于 pkg/auth/oidc.go

五、加密与 TLS

数据加密与压缩

业务流量加密/压缩默认关闭,可按代理开启:

# frpc.toml
[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6000
transport.useEncryption = true
transport.useCompression = true

控制连接 TLS

自 v0.50.0 起,transport.tls.enabletransport.tls.disableCustomTLSFirstByte 的默认值均改为 true,即 frpc→frps 的控制连接默认走 TLS。

  • 端口复用场景下,frp 通过发送首字节 0x17 来拨号 TLS 连接,仅在 transport.tls.disableCustomTLSFirstByte = false 时生效;
  • 若希望 frps 只接受 TLS 连接,在 frps.toml 中配置 transport.tls.force = true(可选);
  • 双向认证需要一个根 CA 证书至少一张 SSL/TLS 证书,自签或 Let's Encrypt 均可;若通过 IP(而非主机名)访问,生成证书时务必把 IP 写入 SAN。

frpc 与 frps 的 TLS 配置:

# frpc
transport.tls.enable = true
transport.tls.certFile = "certificate.crt"
transport.tls.keyFile = "certificate.key"
transport.tls.trustedCaFile = "ca.crt"
# frps
transport.tls.force = true
transport.tls.certFile = "certificate.crt"
transport.tls.keyFile = "certificate.key"
transport.tls.trustedCaFile = "ca.crt"

用 openssl 生成一套证书的操作步骤(Linux 上可直接复用 /etc/pki/tls/openssl.cnf,macOS 为 /System/Library/OpenSSL/openssl.cnf,也可自建如下配置):

cat > my-openssl.cnf << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
x509_extensions = usr_cert
[ req ]
default_bits        = 2048
default_md          = sha256
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
attributes          = req_attributes
x509_extensions     = v3_ca
string_mask         = utf8only
[ req_distinguished_name ]
[ req_attributes ]
[ usr_cert ]
basicConstraints       = CA:FALSE
nsComment              = "OpenSSL Generated Certificate"
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
[ v3_ca ]
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints       = CA:true
EOF

生成 CA:

openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=example.ca.com" -days 5000 -out ca.crt

生成 frps 证书(SAN 中含 IP 与域名):

openssl genrsa -out server.key 2048

openssl req -new -sha256 -key server.key \
    -subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=server.com" \
    -reqexts SAN \
    -config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.server.com")) \
    -out server.csr

openssl x509 -req -days 365 -sha256 \
	-in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
	-extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.server.com") \
	-out server.crt

生成 frpc 证书:

openssl genrsa -out client.key 2048
openssl req -new -sha256 -key client.key \
    -subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=client.com" \
    -reqexts SAN \
    -config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:client.com,DNS:example.client.com")) \
    -out client.csr

openssl x509 -req -days 365 -sha256 \
    -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -extfile <(printf "subjectAltName=DNS:client.com,DNS:example.client.com") \
    -out client.crt

六、传输层调优

TCP 流多路复用

自 v0.10.0 起,frp 支持类似 HTTP/2 的 TCP 流多路复用:到同一 frpc 的所有逻辑连接被复用进同一条 TCP 连接。若需关闭,在 frps 与 frpc 两侧(必须一致)配置:

# frps.toml 和 frpc.toml,两者必须相同
transport.tcpMux = false

KCP 协议

KCP 是一种快速可靠协议,官方描述其代价是比 TCP 多消耗 10%~20% 带宽,换来平均时延降低 30%~40%、最大时延降低到约三分之一。KCP 底层使用 UDP:

  1. 在 frps 开启 KCP(kcpBindPort 可与 bindPort 同值,因为 bindPort 是 TCP 端口):
# frps.toml
bindPort = 7000
# Specify a UDP port for KCP.
kcpBindPort = 7000
  1. frpc 以 KCP 连接 frps:
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
transport.protocol = "kcp"

QUIC 协议

QUIC 是构建在 UDP 之上的新型多路复用传输协议:

# frps.toml
bindPort = 7000
quicBindPort = 7000
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
transport.protocol = "quic"

transport.protocol 还支持 tcp(默认)、websocketwss 等取值。注意:使用 kcp/quic 时,frpc 的启动逻辑 会注册 SIGINT/SIGTERM 信号处理器做优雅关闭,避免 UDP 连接被立即切断。

连接池

默认情况下 frps 在每次用户请求时新建一条到 frpc 后端的连接;连接池会让 frps 保持一定数量预建立的连接,减少连接建立耗时,适合大量短连接场景:

  1. 在 frps 中设置每个代理可用的池上限:
# frps.toml
transport.maxPoolCount = 5
  1. 在 frpc 中启用并指定池数量:
# frpc.toml
transport.poolCount = 1

带宽限制

# frpc.toml
[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6000
transport.bandwidthLimit = "1MB"

transport.bandwidthLimit 支持 KBMB 单位;transport.bandwidthLimitMode 设为 clientserver 决定限速在哪一端执行,默认 client

端口复用与 frps 前置代理

  • vhostHTTPPort / vhostHTTPSPort 可以与 bindPort 相同,frps 会自动探测连接协议并分别处理;注意若要让 vhostHTTPSPortbindPort 同端口,需要先把 transport.tls.disableCustomTLSFirstByte 设为 false
  • frpc 可以经过 HTTP/SOCKS5/NTLM 代理连接 frps:设置环境变量 HTTP_PROXY,或在 frpc.toml 中配置 transport.proxyURL(如 http://user:pwd@192.168.1.128:8080socks5://...),该方式仅在 transport.protocol = "tcp" 时生效。

七、服务端端口管控

allowPorts 用于限制 frpc 可绑定的远程端口,避免端口被滥用:

# frps.toml
allowPorts = [
  { start = 2000, end = 3000 },
  { single = 3001 },
  { single = 3003 },
  { start = 4000, end = 50000 }
]

完整示例中还提供了 maxPortsPerClient(每个客户端最多可用端口数,默认 0 表示不限制)等参数。

八、负载均衡与服务健康检查

group 负载均衡

负载均衡由 group 实现,目前支持 tcphttptcpmux 三种类型:

# frpc.toml
[[proxies]]
name = "test1"
type = "tcp"
localPort = 8080
remotePort = 80
loadBalancer.group = "web"
loadBalancer.groupKey = "123"

[[proxies]]
name = "test2"
type = "tcp"
localPort = 8081
remotePort = 80
loadBalancer.group = "web"
loadBalancer.groupKey = "123"

loadBalancer.groupKey 用于组内认证;到达 80 端口的连接会被随机分发到同组代理。约束:tcp 类型同组 remotePort 必须一致;http 类型同组 customDomainssubdomainlocations 必须一致。

健康检查

健康检查配合负载均衡实现高可用。healthCheck.type = "tcp" 时对服务端口做 TCPing:

[[proxies]]
name = "test1"
type = "tcp"
localPort = 22
remotePort = 6000
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 3
# 连续 3 次失败后该代理会被 frps 摘除
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10

healthCheck.type = "http" 时发送 HTTP 请求并期望 2xx 响应,可用 path 指定探测路径:

[[proxies]]
name = "web"
type = "http"
localIP = "127.0.0.1"
localPort = 80
customDomains = ["test.example.com"]
healthCheck.type = "http"
# frpc 将 GET 请求发往 '/status',期望 HTTP 2xx
healthCheck.path = "/status"
healthCheck.timeoutSeconds = 3
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10

客户端侧的健康检查探测实现见 client/health 模块

九、HTTP 路由与头部处理

重写 Host 头

frp 默认对 HTTP 请求逐字节透传不做修改。若后端 Web 服务器依赖 Host 头做虚拟主机路由,可用 hostHeaderRewrite 重写:

[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["test.example.com"]
hostHeaderRewrite = "dev.example.com"

浏览器请求带 Host: test.example.com,到达后端时变为 Host: dev.example.com

设置其他 HTTP 头

[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["test.example.com"]
hostHeaderRewrite = "dev.example.com"
requestHeaders.set.x-from-where = "frp"
responseHeaders.set.foo = "bar"

该示例会在请求上设置 x-from-where: frp,在响应上设置 foo: bar

获取真实 IP

  • HTTP X-Forwarded-For:适用于 http 代理,或启用了 https2http/https2https 插件的代理,从请求头 X-Forwarded-For 读取用户真实 IP。
  • Proxy Protocol:frp 支持向本地服务发送 Proxy Protocol 携带真实 IP(v1/v2 均支持):
[[proxies]]
name = "web"
type = "https"
localPort = 443
customDomains = ["test.example.com"]

# now v1 and v2 are supported
transport.proxyProtocolVersion = "v2"

配合 nginx 的 Proxy Protocol 支持可把真实 IP 暴露在 HTTP 头 X-Real-IP 中,供 Web 服务读取。协议实现位于 pkg/util/net/proxyprotocol.go

HTTP Basic Auth

对 Web 服务强制 Basic 认证(仅限 http 类型代理),防止他人猜出隧道 URL 后直接访问:

[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["test.example.com"]
httpUser = "abc"
httpPassword = "abc"

访问 http://test.example.com 时浏览器会弹出用户名密码输入框。

自定义子域名

多人共享一个 frps 时,用 subdomain 更方便。frps 端配置 subDomainHost = "frps.com",并将 *.frps.com 泛解析(Wildcard DNS)到 frps IP;frpc 端:

[[proxies]]
name = "web"
type = "http"
localPort = 80
subdomain = "test"

即可通过 test.frps.com 访问。注意:subDomainHost 非空时,customDomains 不应设置为 subDomainHost 的子域名。

URL 路由(locations)

同一域名下按 URL 前缀路由到不同后端,frps 优先匹配最具体的字面前缀(与列出顺序无关):

[[proxies]]
name = "web01"
type = "http"
localPort = 80
customDomains = ["web.example.com"]
locations = ["/"]

[[proxies]]
name = "web02"
type = "http"
localPort = 81
customDomains = ["web.example.com"]
locations = ["/news", "/about"]

URL 前缀为 /news/about 的请求转发到 web02,其余请求转发到 web01

十、运维与可观测性

Server Dashboard

配置 webServer.port 后启用,用于查看 frp 状态与各代理统计:

# 默认 127.0.0.1,公网访问需改为 0.0.0.0
webServer.addr = "0.0.0.0"
webServer.port = 7500
# 用户名与密码均为可选
webServer.user = "admin"
webServer.password = "admin"

访问 http://[serverAddr]:7500(admin/admin)。也可用通配符域名或常规证书启用 HTTPS:

webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin"
webServer.tls.certFile = "server.crt"
webServer.tls.keyFile = "server.key"

此时通过 https://[serverAddr]:7500 访问。

frp server dashboard 界面

Client Admin UI 与动态代理管理(Store)

frpc 侧同样可以开启管理界面,用于查看与管理 frpc 配置和代理:

webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "admin"

访问 http://127.0.0.1:7400

动态代理管理:配置 store.path 指定持久化文件后,可以在不重启 frpc 的情况下,通过 Web UI 或 API 动态创建、更新、删除代理和访问者:

[store]
path = "./db.json"

Store 管理的条目会落盘,frpc 重启后自动恢复,并与配置文件定义的代理并存——名称冲突时 Store 条目优先。从源码结构看,配置来源由 source.Aggregator 统一合并:文件配置、includes 与 Store 是并列的多个 source,frpc 启动时(见 runClientWithAggregator)加载并聚合后再做校验与服务启动。

监控与 Prometheus

启用 web server 后,frps 会将监控数据缓存在内存中保留 7 天,进程重启后清空。启用 Dashboard 后在 frps.toml 设置 enablePrometheus = true,即可从 http://{dashboard_addr}/metrics 抓取 Prometheus 指标。

热加载与状态查询

webServer 字段是启用 HTTP API 的前提。修改 frpc.toml 后执行:

frpc reload -c ./frpc.toml

等待约 10 秒让 frpc 完成代理的创建/更新/删除。注意:start 外,全局客户端参数不会被修改start 是一个在全局层面、所有配置源合并之后生效的白名单:非空时,未被列出的代理/访问者(包括 Store API 创建的条目)都不会启动。官方建议新配置优先使用每个代理/访问者的 enabled 字段做粒度控制,保持 start 为空。

重载前可先用 frpc verify -c ./frpc.toml 预检配置错误;用 frpc status -c ./frpc.toml 查询所有代理的运行状态。

十一、插件与高级特性

客户端插件

frpc 默认只把请求转发到本地 TCP/UDP 端口,插件提供富化能力。内置插件包括 unix_domain_sockethttp_proxysocks5static_filehttp2httpshttps2httphttps2https 等(本文第二节已给出 unix_domain_socketstatic_filehttps2http 的用例)。以 http_proxy 为例:

# frpc.toml
[[proxies]]
name = "http_proxy"
type = "tcp"
remotePort = 6000
[proxies.plugin]
type = "http_proxy"
httpUser = "abc"
httpPassword = "abc"

其中 httpUser/httpPassword 是该插件自身的参数。客户端插件实现位于 pkg/plugin/client

Server 管理插件

frps 支持通过 HTTP 管理插件在登录、新建代理等操作时回调外部服务(如用户管理、端口管理),完整说明见 server 插件文档,完整配置见 frps 完整示例 中的 [[httpPlugins]] 段。

SSH 隧道网关(v0.53.0 引入)

frps 可监听一个 SSH 端口,通过 SSH -R 协议实现 TCP 代理转发,完全不需要 frpc:

# frps.toml
sshTunnelGateway.bindPort = 2200

运行 ./frps -c frps.toml 后,会在当前工作目录自动生成私钥文件 .autogen_ssh_key 供 frps 内置 SSH 服务器使用。执行:

ssh -R :80:127.0.0.1:8080 v0@{frp地址} -p 2200 tcp --proxy_name "test-tcp" --remote_port 9090

即在 frps 上建立一个代理,把远端的 9090 端口转发到发起端本地的 8080 服务,输出类似:

frp (via SSH) (Ctrl+C to quit)

User:
ProxyName: test-tcp
Type: tcp
RemoteAddress: :9090

其等价于:

frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote_port 9090

更多细节见 SSH 隧道网关文档

虚拟网络(VirtualNet,v0.62.0 引入的 Alpha 特性)

VirtualNet 通过 TUN 接口在客户端与访问者之间建立并管理虚拟网络连接,实现 IP 层路由,把 frp 从端口转发扩展到完整的网络互通。详细配置见 VirtualNet 文档,实现位于 pkg/vnet

Feature Gates(特性开关)

frp 借鉴 K8s 风格的 feature gates 管理实验特性,当前可用的特性开关:

名称 阶段 默认值 说明
VirtualNet ALPHA false frp 虚拟网络能力

启用方式:

featureGates = { VirtualNet = true }

特性生命周期分三阶段:ALPHA(默认关闭,可能不稳定)→ BETA(可能默认开启,更稳定但仍在演进)→ GA(默认开启,可用于生产)。实现位于 feature_gate.goVirtualNet 注册为 Default: false, Stage: AlphaSetFromMap 会拒绝未知特性名与锁定特性,KnownFeatures 隐藏 GA 特性,仅列出实验项及其默认值。

十二、源码视角:配置加载与安全控制链

以 frpc 为例,一次启动的完整链路为:

  1. cmd/frpc/sub/root.go 解析 -c/--config--config_dir--strict_config--allow-unsafe 等全局参数;
  2. config.LoadClientConfigResult 先探测是否为 legacy INI(含 [common] 段),是则走 legacy 转换,否则按模板渲染 → 格式检测 → 严格反序列化的管线解析,并加载 includes 引入的额外配置;
  3. 解析结果进入 source 聚合器:文件配置、Store 持久化条目等多 source 合并,重名代理会被 validateNoDuplicateNames 显式拒绝(否则会被静默覆盖);
  4. FilterClientConfigurers 依次按 start 白名单和各代理的 enabled 字段过滤(niltrue 视为启用),这正是 README 中 “start 在所有 source 合并后生效” 的源码依据;
  5. validation.ValidateAllClientConfig 完成最终校验,随后 client.NewService 启动服务。frps 侧流程对称,见 cmd/frps/root.go

安全方面,两侧命令行均提供 --allow-unsafe 参数,用于显式放行被标记为 unsafe 的特性(可选值分别来自 security.ClientUnsafeFeaturessecurity.ServerUnsafeFeatures),默认全部拒绝,体现了“危险能力默认关闭、按需开闸”的设计。

十三、相关资源与中文文档

  • 中文版本 README:README_zh.md
  • 插件仓库 gofrp/plugin:基于 frp 扩展机制实现的各类插件集合;
  • gofrp/tiny-frpc:基于 SSH 协议实现的轻量级 frpc(最小约 3.5MB),支持最常用功能,适合资源受限设备;
  • 参与贡献:建议向 dev 分支提 PR;新增功能请先开 issue 描述方案;欢迎对本文档的改进建议。

以上参数与默认值均取自当前仓库的 frps 完整配置frpc 完整配置,建议以仓库中最新示例为准核对各字段的取值范围。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384