涵盖 默认加密、单向认证、双向认证(mTLS) 三种模式,以及证书生成方法。
一、TLS 默认行为(v0.50.0+)
从 v0.50.0 开始,frp 默认启用 TLS 加密:
- frpc 默认开启 TLS 加密,但不校验 frps 证书
- frps 若未配置证书,则使用随机生成的自签名证书加密流量
注意 :启用 TLS 后,除 xtcp 外,可以不用再设置
useEncryption重复加密。
二、TLS 配置项对照表
| 配置项 | 作用域 | 类型 | 说明 |
|---|---|---|---|
transport.tls.force |
frps | bool | 强制只接受 TLS 连接的客户端。若 trustedCaFile 有效,会自动开启 |
transport.tls.certFile |
双端 | string | TLS 证书文件路径 |
transport.tls.keyFile |
双端 | string | TLS 私钥文件路径 |
transport.tls.trustedCaFile |
双端 | string | 受信任的 CA 证书文件路径,用于验证对方身份 |
transport.tls.enable |
frpc | bool | 客户端显式启用 TLS(v0.50.0+ 默认 true) |
三、三种 TLS 模式配置
3.1 模式一:默认 TLS 加密(不验证身份)
无需额外配置,frp 默认使用随机证书加密通信。适用于信任网络环境。
toml
# frps.toml - 无需额外 TLS 配置
bindPort = 7000
# frpc.toml - 无需额外 TLS 配置
serverAddr = "x.x.x.x"
serverPort = 7000
3.2 模式二:frpc 单向校验 frps 身份
frpc 验证 frps 的服务器证书,防止中间人攻击。
toml
# ========== frps.toml ==========
bindPort = 7000
# frps 提供 TLS 证书
transport.tls.certFile = "/etc/frp/ssl/server.crt"
transport.tls.keyFile = "/etc/frp/ssl/server.key"
# ========== frpc.toml ==========
serverAddr = "x.x.x.x"
serverPort = 7000
# frpc 通过 CA 验证 frps 证书
transport.tls.trustedCaFile = "/etc/frp/ssl/ca.crt"
原理 :frpc 使用
ca.crt验证 frps 的server.crt是否由可信 CA 签发,且服务器域名/IP 需在证书的 SAN 中。
3.3 模式三:双向 TLS 认证(mTLS)⭐ 推荐
frpc 和 frps 互相验证对方身份,安全性最高,适合生产环境。
toml
# ========== frps.toml ==========
bindPort = 7000
# 强制 TLS + 服务端证书
transport.tls.force = true
transport.tls.certFile = "/etc/frp/ssl/server.crt"
transport.tls.keyFile = "/etc/frp/ssl/server.key"
# 验证客户端证书
transport.tls.trustedCaFile = "/etc/frp/ssl/ca.crt"
# ========== frpc.toml ==========
serverAddr = "x.x.x.x"
serverPort = 7000
# 客户端证书
transport.tls.certFile = "/etc/frp/ssl/client.crt"
transport.tls.keyFile = "/etc/frp/ssl/client.key"
# 验证服务端证书
transport.tls.trustedCaFile = "/etc/frp/ssl/ca.crt"
关键点:理论上 frpc 和 frps 的 CA 证书可以不同,只要能验证对方身份即可。但实际部署建议使用同一 CA 签发。
四、证书生成完整脚本(OpenSSL)
4.1 创建 OpenSSL 配置文件
bash
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
4.2 生成 CA 根证书
bash
# 生成 CA 私钥
openssl genrsa -out ca.key 2048
# 生成自签名 CA 证书(有效期约13年)
openssl req -x509 -new -nodes -key ca.key \
-subj "/CN=example.ca.com" \
-days 5000 -out ca.crt
4.3 生成服务端证书
⚠️ 服务端证书必须包含 SAN(Subject Alternative Name),否则客户端校验会失败。
bash
# 1. 生成服务端私钥
openssl genrsa -out server.key 2048
# 2. 生成证书签名请求(CSR),替换为你的服务器 IP 和域名
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:你的服务器公网IP,DNS:example.server.com")) \
-out server.csr
# 3. 使用 CA 签发服务端证书
openssl x509 -req -days 3650 -sha256 \
-in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:localhost,IP:你的服务器公网IP,DNS:example.server.com") \
-out server.crt
4.4 生成客户端证书
bash
# 1. 生成客户端私钥
openssl genrsa -out client.key 2048
# 2. 生成 CSR
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
# 3. 使用 CA 签发客户端证书
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
4.5 最终文件清单
| 文件 | 用途 | 部署位置 |
|---|---|---|
ca.crt |
根证书 | frps + frpc 的 trustedCaFile |
ca.key |
CA 私钥 | 仅用于签发,不部署到任何端 |
server.crt + server.key |
服务端证书 | frps 的 certFile / keyFile |
client.crt + client.key |
客户端证书 | frpc 的 certFile / keyFile |
重要 :
ca.key是 CA 私钥,绝对不能放到 frps 或 frpc 上,仅用于签发证书。
五、Dashboard HTTPS 证书(独立配置)
Dashboard 的 HTTPS 与传输层 TLS 是两套独立配置:
bash
# frps.toml - Dashboard 启用 HTTPS
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin"
# Dashboard 专用 TLS 证书(可以是 Let's Encrypt 等公网证书)
webServer.tls.certFile = "/path/to/dashboard.crt"
webServer.tls.keyFile = "/path/to/dashboard.key"
六、Windows 路径注意事项
Windows 系统配置证书路径时,反斜杠需转义:
bash
# ❌ 错误
transport.tls.certFile = "C:\Users\test\server.crt"
# ✅ 正确
transport.tls.certFile = "C:\\Users\\test\\server.crt"
七、完整生产环境配置示例
frps.toml(服务端)
bash
bindAddr = "0.0.0.0"
bindPort = 7000
# 认证
auth.method = "token"
auth.token = "your-strong-token-here"
# 强制 TLS + 双向认证
transport.tls.force = true
transport.tls.certFile = "/etc/frp/ssl/server.crt"
transport.tls.keyFile = "/etc/frp/ssl/server.key"
transport.tls.trustedCaFile = "/etc/frp/ssl/ca.crt"
# Dashboard
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "your-dashboard-password"
# 日志
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 7
frpc.toml(客户端)
bash
serverAddr = "your-server-ip"
serverPort = 7000
# 认证
auth.method = "token"
auth.token = "your-strong-token-here"
# TLS 双向认证
transport.tls.enable = true
transport.tls.certFile = "/etc/frp/ssl/client.crt"
transport.tls.keyFile = "/etc/frp/ssl/client.key"
transport.tls.trustedCaFile = "/etc/frp/ssl/ca.crt"
# 代理示例
[[proxies]]
name = "web"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8080
八、常见问题排查
| 错误 | 原因 | 解决 |
|---|---|---|
certificate signed by unknown authority |
CA 证书不匹配或未被信任 | 确认 trustedCaFile 指向正确的 ca.crt |
ERR_SSL_UNRECOGNIZED_NAME_ALERT |
服务端证书 SAN 不包含连接地址 | 确保证书 SAN 包含服务器 IP 或域名 |
open /path/ca.key: no such file |
误将 ca.key 配置为 trustedCaFile |
trustedCaFile 应配置 ca.crt,不是 ca.key |
session shutdown |
证书验证失败或 TLS 配置不匹配 | 检查双端 TLS 配置是否对应,证书是否过期 |
参考:GitHub Issue #4463 和 #4812 中详细讨论了证书配置问题。