家里 NAS 上跑着一堆自建服务,但没有公网 IP。这篇文章讲怎么用 frp 把它们安全地暴露出去,以及我在这个过程中踩的坑。
架构
公网用户
│ HTTPS :443
▼
云服务器 nginx ──按 server_name 分流──┬─→ 127.0.0.1:19951 ─frp TLS─→ NAS frpc → 服务 A
└─→ 127.0.0.1:19953 ─frp TLS─→ NAS frpc → 服务 B
关键设计:
- 公网服务器只跑 nginx + frps,不跑业务
- 所有业务服务都在内网 NAS 上,通过 frp 反向隧道暴露到 ECS 的回环端口
- nginx 做 TLS 终结和域名分流,按
server_name决定转发给哪个服务 - 回环端口整段放行(frps 的
allowPorts),新增服务不用改 frps、不用重启
坑 1:frp 的端口是"客户端声明、服务端照做"
frps 的 allowPorts 只是白名单,它不会主动开端口。真正决定"暴露哪些端口"的是 frpc 的 [[proxies]] 配置。
如果某个端口不通,先别查服务端,去看客户端是否在线:
# 采两次,看数字是否增长 —— 增长说明客户端在线
grep -c 'client login info' /var/log/frps.log
坑 2:改 frpc 配置,必须重建容器
如果 NAS 上的 frpc 是跑在 Docker 里的,改完配置点"重启"是没用的。
原因:很多 frpc 镜像把配置通过环境变量注入,而环境变量在容器创建时就固化了。docker restart 只是重启进程,环境变量还是旧的。
正确做法:删除并重建容器(docker compose down && up -d,或面板上的"重建")。
这一条和"改 Docker 挂载必须重建"是同一个道理。
坑 3:frps 日志按天轮转,统计别只看一个文件
frps.log 会滚动成 frps.log.2026-09-30 等等。如果你用
grep -c 'timeout' /var/log/frps.log
统计"有没有超时",会漏掉历史文件里的记录。
正确做法:跨所有轮转文件统计:
cat /var/log/frps*.log | grep -c 'timeout'
nginx 侧:为什么用 443 + server_name 而不是多开端口
早期我在 ECS 上开了 8443、9443 给不同服务用——因为域名还没备案,只能用 IP 直连。
备案通过后,正确的收敛方式是:只留 443,按 server_name 分流。
# 站点 A:博客
server {
listen 443 ssl;
server_name blog.example.com;
ssl_certificate /etc/letsencrypt/live/blog/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog/privkey.pem;
location / { proxy_pass http://127.0.0.1:19953; }
}
# 站点 B:代码托管
server {
listen 443 ssl;
server_name git.example.com;
ssl_certificate /etc/letsencrypt/live/git/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/git/privkey.pem;
location / { proxy_pass http://127.0.0.1:19951; }
}
# 兜底:IP 直连 / 未声明域名(自签证书)
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/pki/self-signed/fullchain.pem;
ssl_certificate_key /etc/pki/self-signed/privkey.pem;
location / { proxy_pass http://127.0.0.1:19951; }
}
好处:
- 对外只需开放 443(一个端口),攻击面最小
- 加新服务 = 加一个 server 块 + 签一张证书,不动 frps、不动客户端
- 每个域名独立证书,互不影响
记得把 return 301(HTTP→HTTPS)下沉到 location /,否则 ACME 校验请求会被 301 跳走。
安全组:最小化开放
公网机器的安全组,最终只留:
| 端口 | 用途 |
|---|---|
| 443 | HTTPS(nginx) |
| 80 | HTTP(仅用于 ACME 校验 + 301) |
| 22 | SSH(建议同时上 2FA) |
| 7000 | frps 控制面(token + TLS) |
| ICMP | ping 诊断 |
备案期用的临时端口(8443 等),域名上线后立刻删掉——安全组规则和 nginx 站点都要收。
小结
frp + nginx 这套组合的价值在于:把"暴露服务"变成一次配置,而不是一次架构变更。
- 内网服务只管跑,不关心公网
- ECS 只管转发,不存业务数据
- 新服务接入 = 一行 frpc 配置 + 一个 nginx server 块
代价是链路变长了一层。排查问题时要有顺序:客户端在线 → 隧道通 → nginx 分流 → 证书,从后往前一段段查。