frp 自建反向代理与公网暴露治理手册
选择 frp 等于接过整条公网链路
frp 由公网主机上的 frps 和内网或开发机上的 frpc 组成。frpc 主动连接 frps,注册代理,再由 frps 接收公网流量并转发到本地服务。这个模型不依赖第三方隧道平台的托管 Endpoint,却把公网主机、带宽、证书、升级、日志、滥用处置、DDoS 风险和 on-call 一并交给自建团队。
Linux amd64 的固定基线为 frp 0.68.1。普通用户从官方发行页获取对应的 Linux amd64 发行包;网络允许直达 GitHub 时可执行下列下载,受限内网可由批准渠道传入同一资产。先核对 GitHub 发行资产给出的 SHA-256,再解压;ARM64 须另选对应资产及其摘要,不使用 amd64 包:
FRP_DL_DIR="$(mktemp -d /tmp/frp-download.XXXXXX)"
FRP_BIN_DIR="$HOME/.local/frp/0.68.1"
if test -e "$FRP_BIN_DIR"; then
printf '目标版本目录已存在,停止覆盖并核对:%s\n' "$FRP_BIN_DIR" >&2
elif curl -q --fail-with-body --location --connect-timeout 10 --max-time 120 \
--output "$FRP_DL_DIR/frp_0.68.1_linux_amd64.tar.gz" \
https://github.com/fatedier/frp/releases/download/v0.68.1/frp_0.68.1_linux_amd64.tar.gz &&
(cd "$FRP_DL_DIR" && printf '%s %s\n' \
'4a4e88987d39561e1b3b3b23d0ede48a457eebf76a87231999957e870f5f02b6' \
'frp_0.68.1_linux_amd64.tar.gz' | sha256sum --check) &&
tar -xzf "$FRP_DL_DIR/frp_0.68.1_linux_amd64.tar.gz" -C "$FRP_DL_DIR"; then
mkdir -p "$FRP_BIN_DIR"
install -m 0755 "$FRP_DL_DIR/frp_0.68.1_linux_amd64/frpc" "$FRP_BIN_DIR/frpc"
install -m 0755 "$FRP_DL_DIR/frp_0.68.1_linux_amd64/frps" "$FRP_BIN_DIR/frps"
export PATH="$FRP_BIN_DIR:$PATH"
else
printf '下载、摘要或解压失败,停止安装;核对网络和发行资产\n' >&2
fi从官方下载、解压到启动的路径见 frp 安装。实验先在一台 Linux 主机做回环转发,三个终端分别运行 upstream、frps、frpc;通过后才把 frps 移到获准的公网主机。upstream 使用本次独占目录并运行在 18080,避免与 frps 的 HTTP 入口 8080 冲突。终端一保留打印的目录路径,实验结束时只清理这个目录:
FRP_WEB_DIR="$(mktemp -d /tmp/frp-web.XXXXXX)"
printf 'FRP_WEB_DIR=%s\n' "$FRP_WEB_DIR"
printf 'frp-ok\n' >"$FRP_WEB_DIR/health"
python3 -m http.server 18080 --bind 127.0.0.1 --directory "$FRP_WEB_DIR"另一个终端确认 upstream 与二进制:
curl -q --noproxy '*' --fail-with-body -i http://127.0.0.1:18080/health
frps --version
frpc --version版本差异可能表现为字段不识别、认证失败或传输能力不一致。升级时应把服务端与客户端兼容范围写进变更记录,不要让个人电脑自动更新 frpc,而长期无人升级 frps。新配置优先采用 TOML、YAML 或 JSON;INI 已进入弃用路径,新能力不会持续补充到旧格式。
配置先验证,再接触公网端口
先保存后面的两份 TOML 与证书、token,再执行配置校验。它能在启动前发现语法与字段问题,网络和实际认证另用请求验证:
frps verify -c frps.toml
frpc verify -c frpc.toml把下面配置保存为 frps.toml。先按 OpenSSL 测试身份生成测试根和叶子,停止其中的 s_server,然后在该 tls-lab 目录执行 frp 命令;该叶子的 DNS SAN 为 dev.local.test。执行 umask 077; openssl rand -hex 32 >.local/frp-token 生成一次实验 token。回环实验配置如下:
bindAddr = "127.0.0.1"
bindPort = 7000
vhostHTTPPort = 8080
proxyBindAddr = "127.0.0.1"
auth.method = "token"
auth.tokenSource.type = "file"
auth.tokenSource.file.path = ".local/frp-token"
auth.additionalScopes = ["HeartBeats", "NewWorkConns"]
allowPorts = [{ start = 20000, end = 20100 }]
maxPortsPerClient = 4
transport.maxPoolCount = 5
transport.heartbeatTimeout = 90
transport.tls.force = true
transport.tls.certFile = "certs/dev.local.test.pem"
transport.tls.keyFile = "certs/dev.local.test-key.pem"
log.to = "console"
log.level = "info"bindPort 接收 frpc 控制连接,不是业务 HTTP 端口;vhostHTTPPort 承载按 Host 路由的 HTTP 代理;proxyBindAddr 决定业务代理监听在哪些网卡。云安全组和主机防火墙应只放行真实需要的端口,不能因为 frp 会动态代理就开放整个端口范围。
allowPorts 限制客户端可申请的 TCP 或 UDP 远端端口;本例 HTTP 虚拟主机使用服务端预设的 8080,不经过 allowPorts 的 20000–20100 范围。maxPortsPerClient 限制单客户端代理数量,transport.maxPoolCount 抑制过大的预建连接池。它们分别约束不同资源,不能把一个端口范围当成 HTTP 入口的访客限流。没有这类限制时,一枚共享 token 不只授予“连接”能力,也可能间接授予大量端口与连接资源。
认证控制客户端,不控制公网访客
auth.method = "token" 让 frps 验证 frpc。tokenSource 从文件读取凭证,避免把 token 写进可共享配置;additionalScopes 让心跳和新工作连接也携带认证。transport.tls.force = true 则要求客户端使用 TLS 建立控制连接。这些配置保护的是 frpc 到 frps 的控制与工作通道。
它们不保护访问公网业务端口的访客。一个陌生人请求 webhook.example.test 时,并不会提交 frpc token。HTTP 服务仍应依靠应用签名、前置身份代理、受控 Basic Auth、mTLS 或其他适合业务的访问策略。把 frp token 当作 Webhook 鉴权,会留下一个完全公开的业务入口。
共享 token 还会扩大故障影响。按环境或租户拆分 frps 实例、网络与凭证,避免个人开发机、CI 和长期演示共用一个 token。单个 token 配置没有双凭证并存字段:轮换前暂停入口流量、停止所属 frpc,在受控窗口同步替换两端 secret,再重启 frps 与 frpc,验证新 token 可连接、旧 token 被拒绝。无中断需求应设计并验证独立实例切换或受支持的身份系统,不能靠写两份 token 文件实现。
客户端只声明自己需要的代理
在同一实验目录保存 frpc.toml:
serverAddr = "127.0.0.1"
serverPort = 7000
user = "team-a"
auth.method = "token"
auth.tokenSource.type = "file"
auth.tokenSource.file.path = ".local/frp-token"
auth.additionalScopes = ["HeartBeats", "NewWorkConns"]
transport.tls.enable = true
transport.tls.trustedCaFile = "certs/dev-root.pem"
transport.tls.serverName = "dev.local.test"
[[proxies]]
name = "webhook-dev"
type = "http"
localIP = "127.0.0.1"
localPort = 18080
customDomains = ["webhook.example.test"]
transport.bandwidthLimit = "1MB"
transport.bandwidthLimitMode = "server"serverAddr 与 serverPort 指向 frps 控制入口,localIP 与 localPort 是内网 upstream。customDomains 要求域名解析到 frps,并由请求 Host 选择代理。user 会为代理名称增加租户前缀,便于隔离名称和观察日志,但它不是完整的多租户授权系统。
bandwidthLimitMode = "server" 让带宽限制在 frps 侧执行,避免完全依赖客户端自律。带宽限制仍不能替代连接数限制、请求体上限、应用超时、应用限流和云主机出站预算。若配置多个代理,应逐个说明 owner、用途、数据级别、开放端口或域名以及到期时间,不能把一台开发机上的全部服务打包暴露。
字段语义与版本变化应分别核对官方的 frp 客户端配置、frp 服务端配置和认证说明。团队模板应固定责任边界与验证步骤,具体字段仍跟随受控版本复核。
用正反实验定位 TLS、认证与转发失败
transport.tls.force 只要求加密连接;客户端的 trustedCaFile 与 serverName 才使它验证 frps 的证书链和名称。生产需换成批准 CA 签发的 frps 服务证书,不使用实验私钥。两端 TLS 字段见 frp TLS 身份校验。
先分别执行前面的 verify。终端一运行 frps -c ./frps.toml,终端二运行 frpc -c ./frpc.toml;看到客户端登录和代理启动成功后,从第三个终端请求:
curl -q --noproxy '*' --fail-with-body \
--resolve webhook.example.test:8080:127.0.0.1 \
http://webhook.example.test:8080/health预期正文为 frp-ok。这一入口只绑定回环,所以没有访客认证也不暴露到公网。
随后执行受控反例。先停止本次 frpc,保留配置和 token 备份;将 serverName 改为 wrong.test 后启动,预期控制连接失败。对同一叶子证书再执行 openssl verify -CAfile certs/dev-root.pem -verify_hostname wrong.test certs/dev.local.test.pem,预期非零且报告 hostname mismatch;恢复 serverName = "dev.local.test" 后成功登录,才可把这组差异归到证书名称。frpc 若只打印 session shutdown,该日志本身并未说出具体证书错误。恢复名称,把 frpc token 文件换成错误值并重启,预期登录被 frps 拒绝,代理不应上线;恢复 token 后重新注册。停止本地 upstream 但保留 frpc,预期入口可达而 origin 失败。正常停止 frpc 后观察 frps 何时注销该代理,预期请求不再返回 frp-ok;控制连接突然中断时,transport.heartbeatTimeout 才是排查迟迟未清理状态的服务端超时参数,不能把两种退出都写成固定等待 90 秒。每次只改一项,避免残留正常 frpc 让负例仍然成功。
| 现象 | 优先查看 | 责任边界 |
|---|---|---|
| frpc 无法登录 | 两端版本、控制端口、TLS、token 与时间 | 控制连接 |
| 代理已注册但公网连接拒绝 | frps 监听、防火墙、安全组、DNS | 公网入口 |
| 公网可达但返回上游错误 | frpc 日志、本地 curl、localPort | 本地 upstream |
| 未授权访客能访问业务 | 前置身份与应用鉴权 | 业务访问控制 |
| 停止当前 frpc 后仍可访问 | 重复进程、systemd、容器、同名代理 | 生命周期 |
这组实验比“页面能打开”更有意义。它证明控制认证、代理注册、公网监听、upstream 和访客权限是五个不同边界,任何一层的成功都不能替代另一层。
回环实验结束后,在终端一用 Ctrl+C 停止 HTTP 服务,在运行 frpc、frps 的终端也分别用 Ctrl+C 停止进程。确认 ss -ltn 不再显示本次 7000、8080、18080 监听,再核对终端一打印的目录确实属于本次实验,删除其中唯一的合成文件并移除空目录:
if [[ "${FRP_WEB_DIR:-}" == /tmp/frp-web.* ]] && test -O "$FRP_WEB_DIR"; then
rm -- "$FRP_WEB_DIR/health" && rmdir -- "$FRP_WEB_DIR"
else
printf '拒绝清理:先核对本次临时目录\n' >&2
fi实验 token、测试根和叶子证书仍在前面创建的 tls-lab 中,按 OpenSSL 测试身份的退出步骤核对后回收;不要误删已安装到其他进程信任库的证书。
双机常驻:先让内网控制面与本机业务入口各就其位
两台已授权的 Linux 主机分别承担不同角色。A 运行 frps,私网地址在下例中写作 10.0.0.10;B 运行 frpc 和监听 127.0.0.1:18080 的受控 HTTP 服务。实际地址必须换成两台机器的私网地址。frps.internal.example 是 B 用来连接 A 并验证控制通道证书的内网 DNS 名;webhook.example.test 是访问业务的 Host,实际对外域名应指向 A 上另行配置的 HTTPS 网关。A 只允许 B 的来源连接 TCP 7000,frps 的 HTTP 8080 继续只绑定 A 的回环地址。公网访客不能直接访问 7000、8080;网关的 443、证书和访客身份必须另行配置完成。没有这些网络与身份条件时,停在回环实验,不把 A 的绑定地址直接改成 0.0.0.0。
控制连接:B/frpc ──私网 TLS:7000──> A/frps
访客请求:外部 HTTPS:443 ──> A/Nginx ──127.0.0.1:8080──> A/frps
└──已有控制/工作通道──> B/frpc ──127.0.0.1:18080──> upstream公网入口的安装、证书与反代配置按 Nginx 两端 TLS完成;A 上反代目标为 http://127.0.0.1:8080,proxy_set_header Host webhook.example.test 要与 B 的 customDomains 相同,正式域名替换时两侧一起改。组织身份代理未接入且调用方支持 Basic Auth 时,可按 frp HTTP Basic Auth在那条 [[proxies]] 下配置 httpUser 与 httpPassword。真实密码会进入 B 的 frpc 配置文件,只给 root 与 frp 组读权限;访客只走 HTTPS 入口,匿名请求应被拒绝,受权请求才返回业务结果。Webhook 调用方不支持 Basic Auth 时,使用其签名机制或独立入口身份方案,不取消全部认证。8080 保持回环绑定,因此外网不能拿不加密的直连探针代替 HTTPS 网关验证。
把回环配置换成各自主机的绝对路径
先复制前面的完整 frps.toml 和 frpc.toml,只改与位置有关的键。A 的 frps 将 bindAddr 设为自身实际私网 IP,proxyBindAddr 仍为 127.0.0.1;B 的 frpc 将 serverAddr 指向 A 的内网 DNS 名,并将 customDomains 改为真实业务域名,Nginx 转发的 Host 也必须与它相同。两机 token 文件内容必须一致,分别由获准的秘密分发渠道写入,不能把值放进 TOML、命令行参数或 Git。控制通道证书的 SAN 必须含 frps.internal.example,B 的 trustedCaFile 是签发这张证书的批准 CA;不复用前面 dev.local.test 的实验私钥。生产版需要替换的字段为:
# A:frps.toml 中对应键的生产值
bindAddr = "10.0.0.10"
proxyBindAddr = "127.0.0.1"
auth.tokenSource.file.path = "/etc/frp/secrets/token"
transport.tls.certFile = "/etc/frp/certs/frps.pem"
transport.tls.keyFile = "/etc/frp/certs/frps-key.pem"
# B:frpc.toml 中对应键的生产值;在另一份文件中修改
serverAddr = "frps.internal.example"
auth.tokenSource.file.path = "/etc/frp/secrets/token"
transport.tls.trustedCaFile = "/etc/frp/certs/control-root.pem"
transport.tls.serverName = "frps.internal.example"
# B 的 [[proxies]] 中同时修改:customDomains = ["实际业务域名"]这段是两份文件的替换字段,不要把 A、B 合并为一份 TOML,也不要把同名键追加成重复定义。B 上的 localIP = "127.0.0.1"、localPort = 18080 指向本机 upstream;先用 curl -q --noproxy '*' --fail-with-body http://127.0.0.1:18080/health 确认它已运行。若 upstream 有稳定返回 2xx 的 /health,可按 frp 官方健康检查在 B 的那条 [[proxies]] 中加入:
healthCheck.type = "http"
healthCheck.path = "/health"
healthCheck.intervalSeconds = 10
healthCheck.timeoutSeconds = 3
healthCheck.maxFailed = 3连续失败后 frpc 会把不健康的代理从 frps 撤下;因此“frpc 进程仍运行”并不等于业务代理仍可用。没有可用健康端点时不要把需要身份的业务接口随意填进 healthCheck.path,先由应用提供无敏感内容、语义稳定的探针。
用专用账号安装二进制、配置和秘密
A、B 均由具有 sudo 权限的部署操作者创建独立服务账号和目录。先用 sudo ls -ld /etc/frp /opt/frp/0.68.1 核对是否已有部署;新机提示路径不存在是正常的。已有配置、token、证书或同版本二进制时,停止下面的新装步骤,转入受控变更,不覆盖旧实例。下列命令分别在两台新主机执行一次;已有 frp 用户或组时先核对归属与用途,不复用不明身份:
if sudo test -e /etc/frp || sudo test -e /opt/frp/0.68.1; then
printf '发现既有 frp 目录:停止新装并核对原服务归属\n' >&2
else
getent group frp >/dev/null || sudo groupadd --system frp
id frp >/dev/null 2>&1 || sudo useradd --system --gid frp --home-dir /var/lib/frp --shell /usr/sbin/nologin frp
if id -nG frp | tr ' ' '\n' | grep -qx frp; then
sudo install -d -o root -g frp -m 0750 /etc/frp /etc/frp/secrets /etc/frp/certs
sudo install -d -o root -g root -m 0755 /opt/frp/0.68.1
else
printf 'frp 用户不属于预期组,停止安装\n' >&2
fi
fi把已核对摘要的官方发行包分别送到两机的受控部署目录,部署操作者在各自目录确认压缩包和解压目标没有与旧部署混用:
if test -e frp_0.68.1_linux_amd64; then
printf '解压目标已存在,停止覆盖\n' >&2
elif printf '%s %s\n' \
'4a4e88987d39561e1b3b3b23d0ede48a457eebf76a87231999957e870f5f02b6' \
'frp_0.68.1_linux_amd64.tar.gz' | sha256sum --check; then
tar -xzf frp_0.68.1_linux_amd64.tar.gz
else
printf '摘要检查失败,停止解压\n' >&2
fi没有打印成功的摘要检查结果与完整解压目录时,不执行后面的安装。A 只安装 frps,B 只安装 frpc;/opt/frp/0.68.1 保留版本号,后续换版不覆盖原二进制。部署操作者将各自编辑好的配置和证书材料安装到上面约定的绝对路径,配置、token 与私钥只允许 root 和 frp 组读取:
# A 上执行;源文件位于本次受控部署目录
sudo install -o root -g root -m 0755 frp_0.68.1_linux_amd64/frps /opt/frp/0.68.1/frps
sudo install -o root -g frp -m 0640 frps.toml /etc/frp/frps.toml
sudo install -o root -g frp -m 0640 approved-token /etc/frp/secrets/token
sudo install -o root -g frp -m 0640 approved-frps.pem /etc/frp/certs/frps.pem
sudo install -o root -g frp -m 0640 approved-frps-key.pem /etc/frp/certs/frps-key.pem
sudo -u frp test -r /etc/frp/secrets/token &&
sudo -u frp test -r /etc/frp/certs/frps.pem &&
sudo -u frp test -r /etc/frp/certs/frps-key.pem &&
sudo -u frp /opt/frp/0.68.1/frps verify -c /etc/frp/frps.toml# B 上执行;token 内容须与 A 一致,CA 是签发 A 证书的批准根
sudo install -o root -g root -m 0755 frp_0.68.1_linux_amd64/frpc /opt/frp/0.68.1/frpc
sudo install -o root -g frp -m 0640 frpc.toml /etc/frp/frpc.toml
sudo install -o root -g frp -m 0640 approved-token /etc/frp/secrets/token
sudo install -o root -g frp -m 0640 approved-control-root.pem /etc/frp/certs/control-root.pem
sudo -u frp test -r /etc/frp/secrets/token &&
sudo -u frp test -r /etc/frp/certs/control-root.pem &&
sudo -u frp /opt/frp/0.68.1/frpc verify -c /etc/frp/frpc.toml源文件名是待交付材料的示意名,执行前必须换成实际路径;这些命令不生成证书、不传递秘密,也不替读者修改云安全组。部署前在同时持有公开证书和批准 CA 的受控环境执行 openssl verify -CAfile approved-control-root.pem -purpose sslserver -verify_hostname frps.internal.example approved-frps.pem,预期 approved-frps.pem: OK,并按 证书与私钥配对检查核对 frps 私钥。名称、链或配对不合格时停止,不能靠关闭客户端校验上线。两机以 frp 用户检查文件可读后,verify 应报告配置语法有效;它不能代替实际连接验证。私钥或 token 传错主机应按泄露流程轮换,不靠 chmod 放宽到全用户可读。
启动两份 systemd 服务并验证路由
按 frp 官方 systemd 用法在 A 保存 /etc/systemd/system/frps.service:
[Unit]
Description=frp server
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=frp
Group=frp
WorkingDirectory=/etc/frp
ExecStartPre=/opt/frp/0.68.1/frps verify -c /etc/frp/frps.toml
ExecStart=/opt/frp/0.68.1/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.targetB 的 /etc/systemd/system/frpc.service 使用相同的非 root 边界,但命令指向客户端:
[Unit]
Description=frp client
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=frp
Group=frp
WorkingDirectory=/etc/frp
ExecStartPre=/opt/frp/0.68.1/frpc verify -c /etc/frp/frpc.toml
ExecStart=/opt/frp/0.68.1/frpc -c /etc/frp/frpc.toml
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target服务只把日志写到 stdout/journald,不依赖可写工作目录;若将来启用文件日志、持久配置或插件,必须重新核对 ProtectSystem=strict 下的写入路径,不能悄悄删去隔离选项。保存 unit 后先在 A 启动 frps,再在 B 确认 upstream 后启动 frpc:
# A:frps 主机
sudo systemd-analyze verify /etc/systemd/system/frps.service
sudo systemctl daemon-reload
sudo systemctl enable --now frps
systemctl is-active frps
sudo ss -ltnp# B:frpc 与 upstream 主机
curl -q --noproxy '*' --fail-with-body http://127.0.0.1:18080/health
sudo systemd-analyze verify /etc/systemd/system/frpc.service
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
systemctl is-active frpcA 应显示 active,ss 中有 A 私网地址的 7000 和 127.0.0.1:8080;B 应显示本机 /health 为 2xx、frpc 为 active。任何一步失败都用对应主机的 sudo journalctl -u frps -b -n 100 或 sudo journalctl -u frpc -b -n 100 看本次启动日志,不先开放公网端口试错。
两机都 active 后,在 A 本机用与 B 的 customDomains 相同的 Host 探测本地 vhost:
PUBLIC_HOST=webhook.example.test
curl -q --noproxy '*' --fail-with-body \
--resolve "$PUBLIC_HOST:8080:127.0.0.1" \
"http://$PUBLIC_HOST:8080/health"同一受控 upstream 应返回 frp-ok;正式业务域名要替换 PUBLIC_HOST,若额外启用了 frp Basic Auth,还须使用实验时已验证的访客凭据。B 本机正常而 A 返回 404 时,先查代理注册、Host 与 customDomains;A 连接 8080 被拒绝时,先查 frps 监听与 proxyBindAddr;代理注册但上游失败时,查 B 的 upstream 与健康检查。最后才从外部网络走已配置身份的 HTTPS 网关验证域名;这一步的成功不能由 A 上的本机 curl 代替。不要在尚未完成双机与网关验证时改变正式 DNS 或接入真实 Webhook。
配置变更与回退要保留正在运行的那份状态
调整 B 的 frpc.toml 时,先留下原配置并在另一文件准备新配置。下例只针对已经确认归属的本机 frpc 服务;新配置使用相同绝对证书与 token 路径,不能把实验目录重新带入服务。执行前确认 /etc/frp/frpc.toml.rollback 不存在,避免覆盖上一轮尚未处理的回退材料:
if sudo test -e /etc/frp/frpc.toml.rollback; then
printf '旧回退文件仍在,停止覆盖并核对上一轮变更\n' >&2
else
sudo install -o root -g frp -m 0640 /etc/frp/frpc.toml /etc/frp/frpc.toml.rollback &&
sudo install -o root -g frp -m 0640 ./frpc.toml.next /etc/frp/frpc.toml.next &&
sudo -u frp /opt/frp/0.68.1/frpc verify -c /etc/frp/frpc.toml.next
fi配置校验通过后,在告知入口使用方的变更窗口内安装新配置并重启 B 的 frpc:
sudo install -o root -g frp -m 0640 /etc/frp/frpc.toml.next /etc/frp/frpc.toml &&
sudo systemctl restart frpc &&
systemctl is-active frpcactive 只证明进程已启动;还要在 A 用原来的 Host 探针验证历史路由,在外部 HTTPS 入口验证身份与业务结果,并在 journalctl -u frpc -b -n 100 中确认新代理注册且没有持续重连。若新配置无法启动或探针不再通过,仅在确认旧 token 与证书仍有效时执行以下失败分支,再重复 A 和外部探针:
sudo systemctl stop frpc &&
sudo install -o root -g frp -m 0640 /etc/frp/frpc.toml.rollback /etc/frp/frpc.toml &&
sudo systemctl reset-failed frpc &&
sudo systemctl start frpc若变更同时轮换 A、B 的 token 或证书,旧值已撤销时单独恢复 B 的配置必然失败,必须以双方一致的已验证凭据恢复或切到预先准备的独立实例。frp 配置回退也不会撤销故障窗口中已转发的 Webhook、文件写入或其他业务副作用。升级二进制时保留 /opt/frp/0.68.1,新版本放独立目录并在隔离环境验证两端兼容;切换 systemd 的 ExecStart 和 ExecStartPre 后按上述进程、代理与外部请求三层复核。失败时同时恢复旧 unit 路径和与旧版本兼容的配置、重载 systemd 再启动,不覆盖旧二进制;重启 frps 会中断当时的控制与业务连接,应用仍需按自身语义处理结果未知的请求。
日常观测先把 systemctl is-active、A 的监听、A 的 Host 探针、B 的 upstream 探针与两端 journal 对到同一时间窗口。控制连接已建立但业务失败时先看健康检查与本地服务;端口没有监听则先看 frps 启动错误;代理数突然增多或认证失败突增时核对部署记录与 token 使用方。需要 Prometheus 指标时,官方监控说明要求同时启用 Dashboard,/metrics 与 Dashboard 共用管理地址;因此先确定采集身份、回环或管理网绑定和访问控制,不把指标端口直接开给公网,也不把内存 Dashboard 历史当作跨重启长期存储。
公网 IP、域名、云安全组、主机防火墙和证书也属于同一服务。投入团队使用前,应指定系统补丁、证书续期、流量账单和滥用投诉的处理人及替补人;公网出口被封禁或账单异常时,单靠重启 frps 不能恢复入口。
日志和面板同样可能扩大暴露面
frps 与 frpc 日志适合记录代理名、连接状态、错误和字节数,不应记录业务 Authorization、Cookie 或完整请求体。日志目录要有大小限制、保留期限和访问权限;调高 debug 级别前先确认不会把内部地址和凭证扩散到集中日志。
若启用 dashboard 或管理接口,应绑定管理网络或回环地址,经独立身份代理访问。管理面会展示代理、流量和内部拓扑,不能与业务代理端口一起直接暴露在公网。监控采集凭证和 frp 控制 token 也要分开,避免只读观察能力拥有注册代理的权限。
容量规划从最坏的合法客户端开始
frps 的瓶颈可能出现在公网带宽、文件描述符、连接池、CPU、内存、云防火墙或单个慢 upstream。容量测试应模拟真实连接时长与请求大小,观察端到端延迟分位数、活跃连接、传输字节、重连、拒绝、代理注册数和系统资源。测试值来自目标 SLO 与压测结果,不应把一台空闲开发机的表现当作容量结论。
allowPorts、maxPortsPerClient、连接池限制与服务端带宽限制构成防滥用基线,但仍需云账单告警、系统资源限制和网络层防护。TCP 直通比 HTTP 虚拟主机更难在应用层约束,开放数据库或管理协议的风险尤其高;除非已有独立网络身份与最小访问策略,否则不应通过 frp 直接提供这类端口。
回收要覆盖客户端、服务端和外部依赖
关闭一个临时代理时,先删除第三方回调或将 DNS 切离,停止所有 frpc 实例,再确认 frps 已清理对应代理。随后撤销任务 token,删除不再使用的域名、证书、防火墙规则和端口允许范围;如果 frps 只为本次任务存在,还要停止服务、保留必要审计证据并回收云主机。
最后从外部网络请求旧域名或端口,预期失败;同时检查 frps 在线代理列表、systemd、容器和开发机进程,确认没有自动重启的副本。只停止当前终端可能留下后台 frpc,只删除 DNS 也可能留下可被直接 IP 访问的端口。
恢复记录应写清 frps 位置与版本、frpc owner、代理名、域名或端口、token 轮换结果、残留云资源和外部失败证据。
权威资料与规范地址
安装、版本与产品能力
配置、API 与协议行为
| 查阅内容 | 官方地址 |
|---|---|
| frp 客户端配置 | https://gofrp.org/en/docs/reference/client-configures/ |
| frp 服务端配置 | https://gofrp.org/en/docs/reference/server-configures/ |
| frp HTTP Basic Auth | https://gofrp.org/en/docs/features/http-https/auth/ |
| 负载均衡与健康检查 | https://gofrp.org/en/docs/features/common/load-balancer/ |
