frp 内网穿透实战:服务端与客户端配置全流程

frp 是自建穿透的事实标准:一台云服务器跑 frps(服务端),家里 NAS 跑 frpc(客户端),把内网服务映射到云上的端口。这一篇按 frp 官方文档的现行规范(v0.52.0 起 TOML 配置)走完全流程,从租服务器到外网访问成功。

前置准备

  • 一台云服务器:国内轻量云即可,带宽 3~10Mbps 量级(速度上限就是它),系统选主流 Linux 发行版;域名非必需(TCP 代理不需要,HTTP 代理需要);
  • 一台家里的常开设备跑 frpc:NAS(Docker)或任意小主机;
  • 安全组放行:云厂商控制台里放行 7000(frp 通信,默认值)和你计划映射的端口。

服务端:frps 配置与启动

SSH 登录云服务器,从 GitHub Releases 下载对应架构的 frp 压缩包,解压后取 frps 二进制。编写 frps.toml(字段名与默认值依据 frp 官方文档):

bindPort = 7000                # 与 frpc 通信的端口,默认 7000
auth.method = "token"
auth.token = "换成一段足够长的随机字符串"

vhostHTTPPort = 8080           # 需要用 HTTP 类型代理时才配

webServer.addr = "0.0.0.0"
webServer.port = 7500          # 管理面板端口
webServer.user = "admin"
webServer.password = "强密码"

启动前先校验语法,再运行:

./frps verify -c ./frps.toml    # 校验,输出 syntax is ok 才继续
./frps -c ./frps.toml

长期运行建议注册为 systemd 服务(发行版差异以官方文档为准),开机自启、崩溃自动拉起。

客户端:frpc 配置与启动

家里设备下载同一版本的 frp,取 frpc 二进制(NAS 上用 Docker 镜像亦可,挂载配置文件即可)。编写 frpc.toml,示例穿透两个服务:

serverAddr = "你的云服务器公网IP"
serverPort = 7000
auth.method = "token"
auth.token = "与服务端完全一致"

[[proxies]]
name = "nas-dsm"
type = "tcp"
localIP = "192.168.10.10"     # NAS 的内网地址
localPort = 5001              # DSM HTTPS 默认端口
remotePort = 52001            # 云服务器上对外的端口

[[proxies]]
name = "home-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

同样先校验再启动:

./frpc verify -c ./frpc.toml
./frpc -c ./frpc.toml

启动成功后,frps 面板(云服务器 7500 端口)里能看到已注册的代理。验证:外网访问 https://云IP:52001 应看到 DSM 登录页;ssh -p 6000 用户@云IP 应连到家里那台机器。整条链路是:访客 → 云端口 → frps → frpc → 内网服务。

HTTP 类型代理与域名

TCP 代理「一个端口对一个服务」,服务多了端口不够用。HTTP 代理用域名区分流量:服务端开 vhostHTTPPort 后,客户端这样写:

[[proxies]]
name = "home-web"
type = "http"
localIP = "192.168.10.20"
localPort = 8096              # 例:Jellyfin 默认端口
customDomains = ["jelly.example.com"]

再把域名 A 记录指到云服务器 IP,访客用 http://jelly.example.com:8080 访问。生产建议在前面再套一层 HTTPS(反代加证书),裸 HTTP 会明文传输内容。

日常维护要点

  • token 安全:它就是唯一的门钥匙,泄露即全域沦陷,定期轮换;
  • remotePort 收敛:每个代理一个端口,映射面越少越好,与端口映射篇的「暴露面清单」同一纪律;
  • 版本升级:frps 与 frpc 版本建议同步升级,升级前看官方 Release Notes,注意大版本间的配置变更;
  • 排障顺序:本地服务通不通(先 curl 内网地址)→ frpc 连上 frps 没(看客户端日志)→ 云安全组放行没(telnet 云端口)→ 最后才是域名解析。

注册为系统服务:开机自启与崩溃自愈

手动运行的 frps/frpc 在断电重启后就没了,生产姿势是交给 systemd 管理。以服务端为例(Debian/Ubuntu 系思路),创建 /etc/systemd/system/frps.service:

[Unit]
Description=frp server
After=network.target

[Service]
Type=simple
ExecStart=/opt/frp/frps -c /opt/frp/frps.toml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

然后启用并启动:

systemctl enable --now frps
systemctl status frps        # 确认运行状态

Restart=on-failure 意味着进程异常退出后 5 秒自动拉起——穿透服务的可用性一半靠配置,一半靠这种自愈机制。客户端 frpc 同理,把路径与配置文件名换掉即可;发行版差异与更细的参数以官方文档为准。NAS 侧若用 Docker 跑 frpc,restart: unless-stopped 已提供同等能力。

STCP:不暴露公网端口的穿透姿势

frp 还有一个对安全敏感用户特别有价值的模式:STCP(安全 TCP 隧道)。它与普通 TCP 代理的区别在于——被穿透的服务不在云服务器上开放任何公网端口,只有持有访问密钥(secretKey)的 frpc 访问者才能连进来。

客户端把代理类型改为 stcp 并设置 secretKey;你自己的设备上再跑一个 frpc 访问者,配置同一个 secretKey 与 sk 后本地监听一个端口。效果:外人扫遍云服务器所有端口也摸不到你的服务,相当于把 frp 变成了一台按密钥授权的私人隧道。对不想暴露 DSM 端口又要远程管理的场景,这是 TCP 代理的优雅替代。

代价是访问端也要常驻一个 frpc 进程(手机上不方便),所以实战定位是:给电脑端的 SSH、管理后台用 STCP,给需要广泛可达的服务用普通代理。两种模式在同一个 frpc.toml 里可以共存,按服务逐个选择。

面板与监控的日常使用

frps 的管理面板(frps.toml 里的 webServer 配置)值得每天路过看一眼:

  • 代理列表:确认所有代理处于 running 状态,掉线的代理一目了然;
  • 流量图表:观察每个代理的进出流量曲线,异常峰值(比如某个代理流量突然暴涨)值得警惕——可能是服务被滥用,也可能是家里某台设备在疯狂上传;
  • 连接数:总连接数与活跃代理数,判断是否该加资源。

面板端口(7500)务必只通过安全方式访问:给面板加强密码是底线,更好的做法是不把 7500 加入公网安全组,需要看面板时通过 SSH 隧道连过去。监控的意义在于在用户报障之前发现异常——凌晨掉线的穿透,早上看面板就知道该去查什么了。

新手常见误区

  • 「照抄老教程的 ini 配置。」 ini 自 v0.52.0 起已弃用,新特性只在 TOML/YAML/JSON 中提供,老教程字段名(如 bind_port)与 TOML(bindPort)也不同,看教程先看版本。
  • 「token 随便设个 123456。」 云服务器端口是全网可达的,弱 token 等于无 token。
  • 「frps 和 frpc 版本混搭。」 两端版本差异过大可能出现兼容问题,保持同版本最省心。
  • 「穿透了 DSM 管理页就觉得完事了。」 穿透只是通道,DSM 那头的双因素、自动封锁一个都不能少——通道和服务是两道独立的门。

frp 给了完全的可控性,但配置量不小。如果你只是想「自己的设备随时连回家」,下一篇的 Tailscale 可能才是你的菜。

本章由 WorkBuddy 原创整理,关键参数以官方文档为准。