frp 完全实战指南:内网穿透、代理类型与安全调优的全景式参考
本文基于 frp 官方 README 及配套源码、配置文件撰写,系统讲解 frp 如何将位于 NAT 或防火墙之后的本地服务暴露到公网:从 frps/frpc 部署模型、TCP/UDP/HTTP/HTTPS/STCP/P2P 各类代理的完整配置实操,到认证、TLS 加密、传输协议调优、负载均衡与健康检查、可观测性体系。读完本文,你可以独立完成一套带安全加固与运维能力的 frp 内网穿透环境,并理解其配置加载与特性开关的源码实现。
一、frp 是什么:定位与部署模型
frp 是一个快速的反向代理工具,用于将位于 NAT 或防火墙之后的本地服务器暴露到互联网。它支持 TCP 和 UDP 协议,以及 HTTP 和 HTTPS 协议(可通过域名将请求转发到内网服务),并提供基于打洞的 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-frps 与 Dockerfile-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 访问局域网内电脑
- 在 Server A 上修改
frps.toml,设置 frpc 连接端口:
# frps.toml
bindPort = 7000
- 在 Server A 上启动 frps:
./frps -c ./frps.toml
- 在 Server B 上修改
frpc.toml,serverAddr填 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 之间的控制通信端口。
- 在 Server B 上启动 frpc:
./frpc -c ./frpc.toml
- 从其他机器通过 Server A 以 SSH 访问 Server B(假设用户名为
test):
ssh -oPort=6000 test@x.x.x.x
2.2 多个 SSH 服务共享同一端口(tcpmux)
利用 tcpmux 类型代理 + HTTP CONNECT 多路复用,可以将多台内网机器的 SSH 服务暴露在同一端口上。只要客户端支持 HTTP Connect 代理方式,都能用这种方式实现端口复用:
- 在公网机器上部署 frps,简化配置如下:
bindPort = 7000
tcpmuxHTTPConnectPort = 5002
- 在内网机器 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
- 在内网机器 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
- 使用 SSH ProxyCommand 访问机器 A(假设用户名
test):
ssh -o 'proxycommand socat - PROXY:x.x.x.x:%h:%p,proxyport=5002' test@machine-a.example.com
- 访问机器 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) 服务:
- 修改
frps.toml,设置 vhost HTTP 端口(如需 HTTPS 代理则再配置vhostHTTPSPort):
# frps.toml
bindPort = 7000
vhostHTTPPort = 8080
-
启动
./frps -c ./frps.toml。 -
修改
frpc.toml,指定 Web 服务的localPort:
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["www.example.com"]
-
启动
./frpc -c ./frpc.toml。 -
将
www.example.com的 A 记录指向 frps 公网 IP,或配置 CNAME 指向你的原始域名。 -
通过
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 服务(也可用 https2https 将 localAddr 指向 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)模式要求访问方持有预共享密钥,降低服务直接暴露公网的风险。
- 在机器 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
- 在机器 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
- 在机器 C 上连接机器 B 的 SSH:
ssh -oPort=6000 127.0.0.1
2.9 P2P 模式:xtcp
xtcp 用于让客户端之间直连传输大量数据;frps 服务器仍然需要,只是实际数据传输走 P2P 通道。注意它并非对所有 NAT 类型都有效,xtcp 不通时可以回退到 stcp。
- 机器 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
- 机器 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
- 在机器 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 客户端启动流程)。
完整的参考配置(仅用于查阅参数,不建议直接运行):
- frps 完整配置示例
- frpc 完整配置示例
- 最小可运行配置可参考 conf/frps.toml(仅
bindPort = 7000)与 conf/frpc.toml - 旧 INI 格式全量示例:frps_legacy_full.ini、frpc_legacy_full.ini
使用环境变量
配置文件支持 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-6000 到 test-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 }}
从源码结构看,模板渲染发生在配置解析之前:RenderWithTemplate 将 parseNumberRange 和 parseNumberRangePair 注册为模板函数,再按扩展名(.toml/.yaml/.yml/.json)检测格式并反序列化;两个二进制默认启用 strict_config 严格模式(未知字段直接报错),格式检测见 detectFormatFromPath。
四、客户端认证
frpc 与 frps 之间的认证方式由两侧的 auth.method 决定,默认是 token。
auth.additionalScopes = ["HeartBeats"]:让每次心跳都携带并校验认证信息;auth.additionalScopes = ["NewWorkConns"]:让每条新的工作连接都携带并校验认证信息。
Token 认证
在 frpc.toml 和 frps.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.scope、auth.oidc.additionalEndpointParams、auth.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.enable 与 transport.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:
- 在 frps 开启 KCP(
kcpBindPort可与bindPort同值,因为bindPort是 TCP 端口):
# frps.toml
bindPort = 7000
# Specify a UDP port for KCP.
kcpBindPort = 7000
- 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(默认)、websocket、wss 等取值。注意:使用 kcp/quic 时,frpc 的启动逻辑 会注册 SIGINT/SIGTERM 信号处理器做优雅关闭,避免 UDP 连接被立即切断。
连接池
默认情况下 frps 在每次用户请求时新建一条到 frpc 后端的连接;连接池会让 frps 保持一定数量预建立的连接,减少连接建立耗时,适合大量短连接场景:
- 在 frps 中设置每个代理可用的池上限:
# frps.toml
transport.maxPoolCount = 5
- 在 frpc 中启用并指定池数量:
# frpc.toml
transport.poolCount = 1
带宽限制
# frpc.toml
[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6000
transport.bandwidthLimit = "1MB"
transport.bandwidthLimit 支持 KB、MB 单位;transport.bandwidthLimitMode 设为 client 或 server 决定限速在哪一端执行,默认 client。
端口复用与 frps 前置代理
vhostHTTPPort/vhostHTTPSPort可以与bindPort相同,frps 会自动探测连接协议并分别处理;注意若要让vhostHTTPSPort与bindPort同端口,需要先把transport.tls.disableCustomTLSFirstByte设为false。- frpc 可以经过 HTTP/SOCKS5/NTLM 代理连接 frps:设置环境变量
HTTP_PROXY,或在frpc.toml中配置transport.proxyURL(如http://user:pwd@192.168.1.128:8080、socks5://...),该方式仅在transport.protocol = "tcp"时生效。
七、服务端端口管控
allowPorts 用于限制 frpc 可绑定的远程端口,避免端口被滥用:
# frps.toml
allowPorts = [
{ start = 2000, end = 3000 },
{ single = 3001 },
{ single = 3003 },
{ start = 4000, end = 50000 }
]
完整示例中还提供了 maxPortsPerClient(每个客户端最多可用端口数,默认 0 表示不限制)等参数。
八、负载均衡与服务健康检查
group 负载均衡
负载均衡由 group 实现,目前支持 tcp、http、tcpmux 三种类型:
# 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 类型同组 customDomains、subdomain、locations 必须一致。
健康检查
健康检查配合负载均衡实现高可用。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 访问。
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_socket、http_proxy、socks5、static_file、http2https、https2http、https2https 等(本文第二节已给出 unix_domain_socket、static_file、https2http 的用例)。以 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.go:VirtualNet 注册为 Default: false, Stage: Alpha,SetFromMap 会拒绝未知特性名与锁定特性,KnownFeatures 隐藏 GA 特性,仅列出实验项及其默认值。
十二、源码视角:配置加载与安全控制链
以 frpc 为例,一次启动的完整链路为:
- cmd/frpc/sub/root.go 解析
-c/--config、--config_dir、--strict_config、--allow-unsafe等全局参数; - config.LoadClientConfigResult 先探测是否为 legacy INI(含
[common]段),是则走 legacy 转换,否则按模板渲染 → 格式检测 → 严格反序列化的管线解析,并加载includes引入的额外配置; - 解析结果进入 source 聚合器:文件配置、Store 持久化条目等多 source 合并,重名代理会被 validateNoDuplicateNames 显式拒绝(否则会被静默覆盖);
- FilterClientConfigurers 依次按
start白名单和各代理的enabled字段过滤(nil或true视为启用),这正是 README 中 “start在所有 source 合并后生效” 的源码依据; - validation.ValidateAllClientConfig 完成最终校验,随后 client.NewService 启动服务。frps 侧流程对称,见 cmd/frps/root.go。
安全方面,两侧命令行均提供 --allow-unsafe 参数,用于显式放行被标记为 unsafe 的特性(可选值分别来自 security.ClientUnsafeFeatures 与 security.ServerUnsafeFeatures),默认全部拒绝,体现了“危险能力默认关闭、按需开闸”的设计。
十三、相关资源与中文文档
- 中文版本 README:README_zh.md;
- 插件仓库 gofrp/plugin:基于 frp 扩展机制实现的各类插件集合;
- gofrp/tiny-frpc:基于 SSH 协议实现的轻量级 frpc(最小约 3.5MB),支持最常用功能,适合资源受限设备;
- 参与贡献:建议向 dev 分支提 PR;新增功能请先开 issue 描述方案;欢迎对本文档的改进建议。
以上参数与默认值均取自当前仓库的 frps 完整配置 与 frpc 完整配置,建议以仓库中最新示例为准核对各字段的取值范围。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00

