1. 项目缘起与整体思路拆解
1.1 为什么会有这个需求
先说清楚这个项目到底在干什么。核心需求是:人在外面,用手机就能访问家里那台常开的机器(我把它叫做 DSH,也就是家里那台跑着各种服务的小主机)。这台机器上可能挂着下载任务、跑着几个自用的 Web 面板、存着一堆文件,甚至还有几个定时脚本在后台默默干活。人在外面的时候,想看一眼状态、传个文件、重启个服务,总不能每次都打电话让家里人帮忙按电源键。
最朴素的方案是搞个公网 IP,但现实情况是大多数家庭宽带拿不到固定公网地址,就算拿到了,把家里的机器直接暴露在公网上也是一件让人睡不踏实的事。于是就有了「内网穿透」这个思路:在家里那台机器上跑一个客户端,主动连到一台有公网地址的服务器上,把家里的服务「反向」映射出去。手机访问公网服务器,流量再被转发回家里。FRP 就是干这件事的一个非常成熟的工具,配置简单、协议支持全、社区资料多,属于那种「拿来就能用」的类型。
而腾讯云 CVM 在这里扮演的角色就是那台「有公网地址的服务器」。选它不是因为别的,主要是手上正好有台低配的按量实例,1 核 1G 的配置跑个 FRP 服务端绰绰有余,带宽按需买,成本可控。整套方案的本质就是:CVM 做中转,FRP 做隧道,DSH 做服务提供方,手机做访问端。
1.2 整体架构长什么样
在动手之前,先把数据流向在脑子里过一遍,这样后面配置的时候每一步都知道自己在干什么。
整个链路是这样的:
- 手机发起请求,目标是 CVM 的公网 IP 加某个端口;
- CVM 上的 FRP 服务端(frps)收到请求,根据配置找到对应的隧道;
- 请求通过已经建立好的长连接,被转发到家里 DSH 上运行的 FRP 客户端(frpc);
- frpc 再把请求交给本地的实际服务,比如某个 Web 面板的 8080 端口;
- 响应沿着原路返回,最终到手机。
这里有个关键点要理解:连接是 DSH 主动发起的。也就是说,家里的机器不需要有任何公网可达性,只要能上网、能访问到 CVM 的公网 IP 就行。这正好绕开了家庭宽带没有公网地址的问题。FRP 客户端启动后会和服务端保持一条长连接,服务端有请求进来就通过这条连接推给客户端,客户端处理完再推回去。你可以把它想象成家里那台机器主动给云服务器打了个「长期电话」,外面有人找,云服务器就通过这个电话转告家里。
1.3 方案选型背后的几个考量
为什么是 FRP 而不是别的?这里说几个我实际比较过的点。
第一是协议覆盖。FRP 支持 TCP、UDP、HTTP、HTTPS 等多种类型,我家里那台 DSH 上跑的服务五花八门,有走 TCP 的自定义端口,也有走 HTTP 的 Web 面板,FRP 一个工具全包了,不用为不同服务装不同软件。
第二是配置直观。FRP 的配置文件是纯文本的 ini 格式,服务端一个 frps.ini,客户端一个 frpc.ini,字段名基本看名字就知道什么意思。对于我这种不想花太多时间在工具本身、只想赶紧把事办成的人来说,这点很重要。
第三是资源占用低。frps 在 1 核 1G 的 CVM 上跑,内存占用基本在几十兆,CPU 几乎可以忽略。这意味着我可以把 CVM 的配置压到最低,省下来的钱够买好几杯咖啡。
第四是安全可控。FRP 支持 token 认证,服务端和客户端要配对同一个 token 才能建立连接。再加上 CVM 的安全组可以限制来源 IP,整体安全性比直接把家里机器暴露出去高得多。
当然也有取舍。FRP 本身不加密流量(除非套 TLS),所以敏感数据最好还是走 HTTPS。另外它依赖 CVM 的公网带宽,如果家里要传大文件,带宽费用得算进去。这些在后面实操部分会具体说。
1.4 适合谁来参考
这套方案的门槛其实不高,但也不是完全零基础能搞定。我觉得适合这几类人:
- 手上有一台云服务器,平时只是挂着不知道干嘛,想物尽其用的;
- 家里有台常开的机器,跑着一些自用服务,想在外面也能访问的;
- 对 Linux 基本操作不陌生,能看懂配置文件、会用 SSH 的;
- 不想折腾复杂方案,希望一两个小时内搞定的。
如果你完全没碰过 Linux,那可能需要先补一下基础命令,但整体流程照着做也能走通。下面我会尽量把每一步都写清楚,包括为什么这么做、可能踩什么坑。
2. 环境准备与核心组件解析
2.1 云服务器端的准备工作
先说 CVM 这边。我用的是一台按量计费的低配实例,系统选的 Ubuntu 22.04,这个版本长期支持、软件源全、社区资料多,属于闭眼选不会错的那种。登录方式用 SSH 密钥,比密码安全,也省得记复杂密码。
拿到实例后第一件事是更新系统:
sudo apt update && sudo apt upgrade -y这一步别省。新实例的系统包往往不是最新的,更新一下能避免很多因为版本旧导致的奇怪问题。更新完重启一次,确保内核和库都是新的。
接下来是安全组配置。这是很多人第一次用云服务器容易忽略的地方。CVM 默认的安全组只开了 22 端口(SSH),其他端口一律不放行。FRP 需要用到几个端口,得提前在控制台的安全组里加规则。具体开哪些端口,取决于你后面要映射什么服务,但至少要有:
- FRP 服务端的绑定端口,我习惯用 7000,这个端口负责接收 frpc 的连接;
- 你要暴露出去的服务端口,比如 Web 面板用 8080,那就得开 8080;
- 如果要用 HTTPS,还得开 443。
安全组的来源建议先设成0.0.0.0/0方便调试,等全部跑通后再收紧到具体 IP。不过说实话,家庭宽带的公网 IP 经常变,收紧到具体 IP 维护成本高,更实际的做法是靠 FRP 的 token 和后面要说的额外认证来保证安全。
提示:安全组规则修改后立即生效,不需要重启实例。如果发现端口不通,第一件事就是回来检查安全组,十有八九是这里漏了。
2.2 FRP 的版本选择与下载
FRP 是开源项目,发布在 GitHub 上,有预编译的二进制包,直接下载解压就能用,不需要编译。版本方面,我建议用较新的稳定版,新版本在性能和安全性上都有改进。下载的时候注意选对架构,CVM 一般是 x86_64,家里那台 DSH 如果是 ARM 架构(比如某些低功耗小主机),就得下对应的 ARM 版本。
下载和解压的命令大概是这样:
wget https://github.com/fatedier/frp/releases/download/v0.xx.x/frp_0.xx.x_linux_amd64.tar.gz tar -zxvf frp_0.xx.x_linux_amd64.tar.gz cd frp_0.xx.x_linux_amd64解压后目录里会有frps、frps.ini、frpc、frpc.ini这几个文件。服务端只用frps和frps.ini,客户端只用frpc和frpc.ini。我习惯把服务端的文件放到/usr/local/frp/下,客户端放到/opt/frp/下,路径清晰,后面配 systemd 服务的时候也好写。
这里有个细节:服务端和客户端的版本最好保持一致。虽然 FRP 在协议上做了兼容,但跨大版本偶尔会有字段不识别的情况。我一般两边下同一个版本号,省心。
2.3 家里 DSH 端的环境确认
DSH 这边首先要确认的是它能正常上网,而且能访问到 CVM 的公网 IP。测试方法很简单:
ping <CVM公网IP>如果 ping 不通,可能是 CVM 安全组没放行 ICMP,也可能是家里网络的问题。ping 不通不代表 FRP 连不上,因为 FRP 走的是 TCP,但 ping 通至少说明网络层是通的,排查起来少一层干扰。
然后确认 DSH 上要暴露的服务确实在跑。比如你要映射一个 Web 面板,先在 DSH 本地用curl localhost:8080确认它能响应。本地都不通,映射出去肯定也不通,这个顺序不能反。
DSH 的系统我假设也是 Linux,因为 FRP 客户端在 Linux 上跑最省事。如果是 Windows,也有对应的 exe,但配置文件和路径写法略有不同,本文以 Linux 为主。
2.4 核心概念对照表
在正式配置前,把几个关键概念理清楚,后面看配置文件就不会晕:
| 概念 | 作用 | 所在位置 |
|---|---|---|
| frps | FRP 服务端程序 | CVM |
| frpc | FRP 客户端程序 | DSH |
| bind_port | 服务端监听 frpc 连接的端口 | frps.ini |
| server_addr | 客户端要连接的服务器地址 | frpc.ini |
| server_port | 客户端连接的服务器端口 | frpc.ini |
| token | 服务端与客户端的配对密钥 | 两边都要配 |
| remote_port | 映射到服务端的公网端口 | frpc.ini |
| local_port | DSH 上实际服务的端口 | frpc.ini |
这张表建议截图存手机里,配置的时候对着看,能省不少来回翻文档的时间。
3. 服务端与客户端配置实操
3.1 服务端 frps.ini 的完整配置
服务端的配置文件相对简单,核心就是告诉 frps 监听哪个端口、用什么 token。我的配置大概长这样:
[common] bind_port = 7000 token = your_strong_token_here dashboard_port = 7500 dashboard_user = admin dashboard_pwd = your_dashboard_pwd log_file = /var/log/frps.log log_level = info log_max_days = 7逐行解释一下。bind_port是 frps 等待 frpc 连接的端口,7000 是个常用选择,你也可以换成别的,只要安全组放行就行。token是认证密钥,一定要设得复杂一点,因为这是防止别人蹭你隧道的唯一屏障。我一般用一串随机字符,长度 32 位以上。
dashboard_port是 FRP 自带的一个 Web 管理界面,能看到当前有哪些隧道、流量多少、连接状态如何。这个功能非常实用,强烈建议开。dashboard_user和dashboard_pwd是登录这个界面的账号密码,同样要设复杂点。
日志部分,log_file指定日志路径,log_level设成 info 就够用,debug 太啰嗦,warn 又可能漏掉关键信息。log_max_days控制日志保留天数,7 天是个平衡点,既不会占太多磁盘,出问题时也有足够的历史可查。
注意:dashboard 的端口(这里是 7500)也要在安全组放行,否则你在外面打不开这个管理界面。但 dashboard 的账号密码一定要设强,因为它暴露在公网上,弱密码等于把管理权限送人。
3.2 客户端 frpc.ini 的配置与多服务映射
客户端的配置稍微复杂一点,因为要定义每个隧道。假设 DSH 上有一个 Web 面板跑在 8080,还有一个 SSH 服务跑在 22,我想把这两个都映射出去,配置大概是这样:
[common] server_addr = <CVM公网IP> server_port = 7000 token = your_strong_token_here log_file = /var/log/frpc.log log_level = info log_max_days = 7 [web_panel] type = tcp local_ip = 127.0.0.1 local_port = 8080 remote_port = 8080 [ssh_home] type = tcp local_ip = 127.0.0.1 local_port = 22 remote_port = 2222[common]段是全局配置,server_addr填 CVM 的公网 IP,server_port对应服务端的bind_port,token必须和服务端一致,否则连不上。
下面每个[xxx]段就是一个隧道。type = tcp表示走 TCP 协议,local_ip和local_port是 DSH 上实际服务的地址和端口,remote_port是映射到 CVM 上的公网端口。也就是说,手机访问CVM公网IP:8080,流量会被转发到 DSH 的127.0.0.1:8080。
这里有个容易踩的坑:remote_port不能和服务端已经占用的端口冲突,也不能和别的隧道重复。比如你把 web_panel 的 remote_port 设成 7000,那就和 bind_port 撞了,frps 启动会报错。我一般把 remote_port 规划在一个区间里,比如 8000 到 9000,避免和系统服务冲突。
另外,SSH 那个隧道我把 remote_port 设成了 2222 而不是 22,因为 CVM 自己的 22 端口已经被 SSH 占用了。映射到 2222,手机 SSH 客户端连CVM公网IP:2222就能连到家里的 DSH。
3.3 用 systemd 让 FRP 开机自启
手动运行 frps 和 frpc 的问题是,一旦进程挂了或者服务器重启,隧道就断了。用 systemd 托管是最省心的做法。
服务端的 service 文件放在/etc/systemd/system/frps.service:
[Unit] Description=FRP Server After=network.target [Service] Type=simple ExecStart=/usr/local/frp/frps -c /usr/local/frp/frps.ini Restart=always RestartSec=5 [Install] WantedBy=multi-user.target客户端的 service 文件放在/etc/systemd/system/frpc.service,内容类似,只是路径和程序名换成 frpc:
[Unit] Description=FRP Client After=network.target [Service] Type=simple ExecStart=/opt/frp/frpc -c /opt/frp/frpc.ini Restart=always RestartSec=5 [Install] WantedBy=multi-user.targetRestart=always是关键,进程意外退出后 systemd 会自动拉起来。RestartSec=5表示等 5 秒再重启,避免疯狂重启刷日志。
写好后执行:
sudo systemctl daemon-reload sudo systemctl enable frps sudo systemctl start frps sudo systemctl status frps客户端同理,把 frps 换成 frpc。status看到active (running)就说明起来了。如果失败,用journalctl -u frps -n 50看最近 50 行日志,错误信息一般都很明确。
3.4 验证隧道是否打通
配置完成后,验证分两步。
第一步,在 CVM 上看 frps 的 dashboard,或者直接看日志,确认 frpc 已经连上来。日志里会有类似client login success的记录。
第二步,用手机(关掉 WiFi,用移动网络,确保走的是外网)访问CVM公网IP:8080,看能不能打开 DSH 上的 Web 面板。如果能打开,说明整条链路通了。
如果打不开,按这个顺序排查:
- CVM 安全组有没有放行 8080;
- frpc 日志有没有报错;
- DSH 本地
curl localhost:8080通不通; - frps dashboard 里 web_panel 这个隧道是不是 online 状态。
这个排查顺序是从外到内,能快速定位问题在哪一段。
4. 常见问题与排查技巧实录
4.1 连接建立失败类问题
问题一:frpc 启动后日志报login to server failed。
这是最常见的问题,原因通常有三个。一是server_addr或server_port填错了,检查一下 IP 和端口。二是 token 不一致,服务端和客户端的 token 必须一模一样,包括大小写。三是 CVM 安全组没放行bind_port,frpc 根本连不上服务端。
排查方法:先在 DSH 上用telnet <CVM公网IP> 7000测试端口通不通。如果 telnet 不通,就是网络或安全组问题;如果通但 frpc 还是报错,就是 token 或配置问题。
问题二:隧道显示 online,但访问没反应。
这种情况通常是local_port填错了,或者 DSH 上的服务只监听了127.0.0.1而 FRP 转发时用了别的地址。FRP 默认用local_ip指定的地址去连,如果服务只监听 localhost,local_ip = 127.0.0.1是对的。但如果服务监听的是0.0.0.0,用127.0.0.1也能连上。真正的问题往往是服务本身没跑起来,或者防火墙拦了本地回环。
4.2 性能与稳定性类问题
问题三:传输大文件时速度很慢。
FRP 本身不做压缩,速度瓶颈通常在 CVM 的公网带宽。低配实例的带宽一般是 1M 到 5M,传大文件确实慢。解决办法有两个:一是升级带宽,按量计费的话临时升一下,传完再降回来;二是如果只是偶尔传文件,考虑用对象存储中转,不走 FRP。
问题四:隧道偶尔断开,过一会儿又自动恢复。
这通常是网络抖动导致的。FRP 有心跳机制,默认会定期发心跳包保持连接。如果网络不稳定,心跳超时后连接会断,然后 frpc 会自动重连。Restart=always保证了进程层面的恢复,但连接层面的恢复靠的是 FRP 自己的重连逻辑。如果频繁断开,可以在 frpc.ini 里调一下heartbeat_interval和heartbeat_timeout,把超时设长一点,容忍短暂的网络波动。
4.3 安全问题与加固建议
问题五:怎么防止别人蹭我的隧道。
第一道防线是 token,设复杂点。第二道防线是 dashboard 的账号密码,同样要强。第三道防线是 CVM 安全组,把bind_port的来源限制到你家宽带的 IP 段(虽然 IP 会变,但可以设个大致范围)。第四道防线是 FRP 的allow_ports配置,限制客户端只能映射特定范围的端口,防止有人连上来后乱开隧道。
如果对安全性要求更高,可以在 FRP 之上再套一层 TLS。FRP 支持tls_only = true,强制客户端用 TLS 连接服务端。这样即使流量被截获,内容也是加密的。配置方法是在 frps.ini 和 frpc.ini 的[common]段都加上tls_only = true,然后确保两边的证书配置一致。
4.4 常见问题速查表
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| frpc 连不上 frps | token 不一致 / 端口没放行 | 检查 token,telnet 测试端口 |
| 隧道 online 但访问无响应 | local_port 错误 / 服务未启动 | 本地 curl 测试服务 |
| 访问返回 502 | 服务端转发失败 | 看 frps 日志,检查隧道状态 |
| 速度慢 | 带宽瓶颈 | 测 CVM 带宽,考虑升级或换方案 |
| 频繁断连 | 网络抖动 / 心跳超时 | 调大 heartbeat_timeout |
| dashboard 打不开 | 端口没放行 / 密码错误 | 检查安全组和登录凭据 |
这张表建议存下来,出问题时对着查,能省很多时间。
5. 实际使用中的经验与扩展思路
5.1 我踩过的几个坑
第一个坑是端口规划混乱。刚开始我没规划,remote_port 随手填,结果有一次填了个 3306,和 CVM 上跑的数据库撞了,frps 直接启动失败。后来我固定用 8000 到 9000 这个区间,再也没出过问题。
第二个坑是日志没配轮转。FRP 默认日志会一直写,时间长了把磁盘写满。后来加了log_max_days = 7,问题解决。如果你用的版本不支持这个参数,可以用系统的 logrotate 来管。
第三个坑是忘了客户端也要开机自启。服务端配了 systemd,客户端忘了配,结果 DSH 重启后隧道就断了,人在外面干着急。两边都配 systemd 是必须的。
5.2 后续可以怎么扩展
这套方案跑通后,能扩展的方向不少。比如把 HTTP 服务用 FRP 的type = http模式映射,配合自定义域名,就能用域名访问而不是 IP 加端口。再比如用 FRP 的subdomain功能,一个服务端可以托管多个子域名,分别指向不同的内网服务。
如果家里设备多,可以在多台机器上跑 frpc,都连到同一个 frps,这样一台 CVM 就能把家里所有设备的服务都映射出去。FRP 的 dashboard 会把这些隧道都列出来,管理起来一目了然。
还有一个思路是用 FRP 做内网服务的统一入口,配合 Nginx 做反向代理和 SSL 终止,这样外面访问的是 HTTPS,证书在 CVM 上统一管理,内网服务不用各自配证书,省事很多。
5.3 成本与维护的实际感受
最后说点实在的。这套方案的成本主要是 CVM 的费用,低配按量实例一个月也就几十块,如果选包年包月还能更便宜。带宽是变量,如果只是偶尔访问,1M 带宽够用;如果要经常传文件,建议按流量计费或者临时升带宽。
维护方面,FRP 本身很稳定,配好之后基本不用管。偶尔需要关注的是 CVM 的系统更新和 FRP 的版本更新。系统更新用apt upgrade定期跑一下,FRP 更新的话,下载新版本替换二进制文件,重启服务就行,配置文件一般不用改。
我个人在实际操作中的体会是,这套方案最大的价值不是技术本身有多复杂,而是它把「在外面访问家里服务」这件事变得足够简单。配一次,后面就是无感的。手机上一键打开,跟访问本地服务没区别。对于我这种经常在外面跑、又依赖家里那台机器干活的人来说,这点便利性值回所有折腾的时间。