场景很常见:家里或办公室有一台跑着内部服务的机器,需要在外面访问;但它没有公网 IP, 路由器也不在自己手里。买一台最便宜的云服务器做中转,用 frp 打通,是最省事的方案。
这套东西我用了很久,中间因为升级版本翻过一次车——配置文件格式从 ini 改成了 TOML, 旧配置直接启动失败。趁这次迁移把整份配置重新捋了一遍,记下来省得下次再查。
一、结构:两端各一个进程
frp 由两部分组成:frps 跑在有公网 IP 的服务器上,frpc 跑在内网机器上。 frpc 主动向 frps 建立长连接,把内网端口"映射"到服务器上,外部访问服务器端口就等于访问内网服务。 NAT 和防火墙的问题就此绕过——因为它从来不需要外部主动连进来。
外部用户 → (公网 IP:8080) → frps → 加密隧道 → frpc → (内网 127.0.0.1:8000)
二、新旧配置格式对照
v0.52 之后 frp 用 TOML 取代了 ini。老配置长这样:
# frpc.ini(旧格式,已废弃)
[common]
server_addr = 1.2.3.4
server_port = 7000
token = your_token
[web]
type = tcp
local_ip = 127.0.0.1
local_port = 8000
remote_port = 8080
新格式把"公共段"和"代理段"拆成了两处:公共配置写在文件顶层,
每个代理用一个 [[proxies]] 数组项表示。
# frpc.toml
serverAddr = "1.2.3.4"
serverPort = 7000
auth.method = "token"
auth.token = "your_token"
log.level = "info"
[[proxies]]
name = "web"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8000
remotePort = 8080
服务端同样变了。老版本是 [common] 里写 bind_port,
现在是顶层字段:
# frps.toml
bindPort = 7000
auth.method = "token"
auth.token = "your_token"
# 面板:只监听本地,通过 SSH 隧道访问,不要直接暴露公网
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "change_me"
迁移时最常见的报错是
parse config error。八成是还在用 ini 语法—— 注意 TOML 里字符串必须带引号,localPort = 8000不能写成"8000"(虽然能解析,但类型不对会报警告)。
三、端口规划:别随手挑
端口冲突是最容易浪费时间的问题。我现在固定一套规划,写进注释里:
| 端口 | 用途 | 暴露范围 |
|---|---|---|
| 7000 | frps 控制端口 | 公网(限制来源 IP 更好) |
| 7500 | frps 管理面板 | 仅本地 127.0.0.1 |
| 8080 | 映射出去的内网 Web 服务 | 公网 |
| 6000 | SSH 映射(应急用) | 公网,建议改非默认端口 |
云服务器还有一层安全组,端口开了服务还得在控制台放行,这一步经常被忘。
判断方法很简单:服务器上 ss -lntp | grep 8080 有监听、本地 curl 127.0.0.1:8080 通,
但从外面连不上,那基本就是安全组的问题。
四、鉴权与加密:别裸奔
公网上的 frps 控制端口会被扫描。至少做三件事:
- 开 token 鉴权。 就是上面配置里的
auth.token,两端必须一致。用长随机串,别用123456。 - 限制控制端口来源。 如果内网出口 IP 固定,直接在安全组里只放行那个 IP。
- Web 服务套 HTTPS。 frp 只做端口转发,不负责加密业务流量。让 Nginx 在前面终止 TLS,或者用 frp 自带的
https类型代理。
还有一个容易忽略的点:管理面板千万不要暴露在公网。默认账号密码 + 公网可达 = 别人能看到你所有隧道的状态。
我把它绑在 127.0.0.1,需要时用 SSH 端口转发过去看。
五、开机自启:systemd 比 nohup 靠谱
用 nohup ./frpc -c frpc.toml & 启动的进程,机器一重启就没了,而且挂了没人拉起来。
写个 systemd 单元,省心得多:
# /etc/systemd/system/frpc.service
[Unit]
Description=frp client
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=5
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
systemctl status frpc --no-pager
Server=always 加 RestartSec=5 是关键:网络抖动导致隧道断开时,进程会自己回来。
服务端同样处理,把 frpc 换成 frps 即可。
六、排错顺序
连不上时按这个顺序查,基本能在五分钟内定位:
- frps 有没有起来:
systemctl status frps,看日志里有没有start frps success。 - frpc 有没有连上:frpc 日志出现
login to server success才算通,出现connect to server error就是网络或端口问题。 - 隧道有没有建起来:日志里每个代理会打印
start proxy success,没有就说明 remotePort 被占用或权限不足。 - 安全组放行了吗:云控制台单独检查,这一步最容易漏。
- 内网服务本身活着吗:在 frpc 那台机器上
curl 127.0.0.1:8000,先确认本地通。
这五步覆盖了我遇到过的所有情况。绝大多数"连不上"不是 frp 的问题,而是安全组或者内网服务本身挂了。
七、小结
frp 是个典型的"配置对了就永远不操心"的工具。真正需要花心思的不是它的功能,而是三件事: 端口规划要留文档、token 要随机、管理面板不要暴露。前两件是给自己省事,最后一件是给自己省麻烦。
另外,升级前务必备份旧配置并看一眼 changelog。我那次翻车就是因为直接 apt upgrade 完重启,
结果服务起不来,半夜在服务器上翻文档。现在我的习惯是:升级前 cp frpc.ini frpc.ini.bak,
并且先在测试机上跑一遍。