← 返回技术札记

没有公网 IP,也能把家里的服务安全地带出来

家里的宽带没有公网 IP,路由器、NAS 和媒体服务无法从外网直接访问。我用 FRP 把家里的服务接到公网入口,再把整套服务从海外 VPS 迁到了国内服务器。

为什么需要内网穿透

家里的宽带属于运营商共享出口。外网请求首先到达运营商的公网设备,并不会直接进入我家的路由器,因此即使在路由器里做了端口转发,公网访问也无法真正抵达家中。

这类网络环境并不影响正常上网,却会影响远程访问:人在外面时,无法直接打开家里的软路由管理页、NAS 服务或媒体服务。

我的目标不是把整个家庭网络暴露到公网,而是只为确实需要的服务提供一条受控的访问路径。

FRP 的基本结构

FRP 的思路很直接:让内网设备主动连接一台具有公网地址的服务器。外部访问先到服务器,再由服务器通过已经建立的隧道把请求转回家中的服务。FRP 是开源项目,官方仓库可以下载最新版本。

外部设备
  ↓
公网服务器
  ↓
Nginx 反向代理 + HTTPS + 额外认证
  ↓
FRP 服务端
  ↓
家中软路由 / NAS 上的 FRP 客户端
  ↓
家庭内部服务

家里的设备不需要开放入站端口,主要工作是主动维持到公网服务器的连接。公网服务器则承担统一入口、域名和反向代理的职责。

最小配置示例

服务端部署在公网服务器上,客户端部署在家中软路由或 NAS 上。以下是最小可用配置,所有敏感值均以占位符代替:

# frps.toml(公网服务器)
bindPort = 7000
auth.method = "token"
auth.token = "替换成高强度随机字符串"
# frpc.toml(家中软路由或 NAS)
serverAddr = "你的公网服务器IP"
serverPort = 7000
auth.method = "token"
auth.token = "与服务端相同的token"

[[proxies]]
name = "router"
type = "tcp"
localIP = "家中网关的内网IP"
localPort = 80
customDomains = ["router.example.com"]

客户端连接成功后,访问 router.example.com 就会由服务器转发到家中软路由的 80 端口。同一份配置再加一组 [[proxies]] 就能多开一个服务,每个服务一个独立子域名。

为什么从海外 VPS 迁到国内服务器

之前的 FRP 服务部署在另一台海外 VPS 上,整体可以使用,但访问家中设备时,流量需要跨境绕行。对于管理页面、文件浏览和媒体服务来说,延迟和稳定性都不够理想。

后来我准备把入口迁到国内服务器。迁移的目的不是改变家庭网络结构,而是让国内设备访问这个入口时,尽量减少不必要的跨境路径。

域名也按照服务拆分成多个子域名,例如路由器、NAS 和媒体服务分别使用独立入口。这样做的好处是权限和故障排查都更加清楚,后续也可以单独调整某一个服务。

FRP 只负责穿透,安全还要靠前面的几层

FRP 解决的是“流量如何回家”,它不是完整的安全方案。公网入口仍然需要认真加固。

即使有人扫描到公网服务器,也不应该只面对一层密码。公网入口、反向代理认证、FRP token 和家中服务自身的登录验证,应当各自独立。

迁移时最容易忽略的地方

FRP 迁移不只是把客户端地址替换成新服务器 IP,外围配置往往才是最容易出问题的部分。

最后的效果

迁移完成后,家里的服务不需要公网 IP,也不需要把路由器或 NAS 的管理端口直接暴露在家庭网络出口上。

人在外面时,可以通过独立子域名访问需要的服务;在家里时,仍然按局域网方式使用。国内服务器承担公网入口和中转职责,家中的软路由与 NAS 保持在内网侧。

这不是一套搭完就永远不用管的方案。服务器补丁、证书续期、日志检查和端口审计仍然需要定期做。但对于没有公网 IP 的家庭网络来说,它提供了一条相对清晰、可控,也便于长期维护的访问路径。

FRP 的价值不只是把服务“暴露出去”,而是让原本封闭的家庭网络,拥有一条自己能够理解和管理的回家路线。