使用 frp 实现 NAS 内网穿透:云服务器与 Docker 部署指南
最近,我在一台阿里云服务器上部署多个服务后,系统因内存占用过高而卡死,甚至无法登录。重启排查后发现,这台服务器只有 2 GB 内存,仅一个 MySQL 服务就占用了近一半。由于这些服务只供个人使用,直接升级云服务器的性价比并不高。
我家里正好有一台长期运行的 NAS,于是准备把服务部署到 NAS,再通过公网服务器提供访问入口。厂商自带的远程访问服务不能自定义访问路径;IPv6 方案则要求访问端同时支持 IPv6,而且我此前使用家中宽带 IPv6 时体验并不稳定,因此都不太符合需求。
同事建议我使用 frp。frp 是一个反向代理工具,可以把位于 NAT 或防火墙后的内网服务暴露到公网。它由两部分组成:
frps:部署在具有公网 IP 的服务器上,接收外部请求和frpc的连接;frpc:部署在 NAS 上,把指定的本地服务转发给frps。
本文以 NAS 中的 MySQL 服务为例,最终的访问链路如下:
MySQL 客户端
→ 公网服务器:13306
→ frps
→ frpc
→ NAS:3306
准备工作
开始前需要准备:
- 一台拥有公网 IP 的服务器;
- 一台能够运行 Docker 的 NAS;
- 一个高强度 Token,用于
frpc与frps之间的身份认证; - 确认 NAS 上的目标服务可以被
frpc访问。
本文会用到三个端口:
7000:frpc连接frps的通信端口;7500:frpsDashboard 端口,可选;13306:示例中对外提供 MySQL 访问的代理端口。
如果服务器使用了云安全组和系统防火墙,需要同时配置两处规则。实际端口可以自行修改,但服务端与客户端的配置必须保持一致。
在公网服务器上部署 frps
我使用 1Panel 管理服务器,因此直接在应用商店中安装 frp 服务端:

如果不使用 1Panel,可以从 frp 的 GitHub Releases 页面下载与服务器系统和 CPU 架构匹配的版本。解压后,使用下面的命令启动 frps:
./frps -c ./frps.toml
如果需要长期运行,可以再通过 systemd 等工具管理进程和开机自启。
配置服务端
使用 1Panel 安装时,可以直接在页面中填写配置:

主要参数的作用如下:
- 服务端口:
frps接收frpc连接的端口,默认值为7000; - Dashboard 端口、用户名和密码:用于配置
frps的 Web 管理界面; - Token:
frpc与frps之间的认证凭据,两端必须配置相同的值。
对应的 frps.toml 配置如下:
# 接收 frpc 连接的地址和端口
bindAddr = "0.0.0.0"
bindPort = 7000
# frpc 与 frps 使用相同的认证方式和 Token
auth.method = "token"
auth.token = "请替换为高强度 Token"
# 可选:开启 frps Dashboard
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "请替换为高强度密码"
如果使用二进制方式部署,可以先检查配置文件是否有效:
./frps verify -c ./frps.toml
配置完成后,按照实际环境在云安全组和系统防火墙中放行 7000 端口,供 NAS 上的 frpc 连接。
如果启用了 Dashboard,可以通过 http://SERVER_IP:7500 访问:

不要直接公开管理面板
webServer.addr = "0.0.0.0"会让 Dashboard 监听所有网卡。除了设置高强度密码,最好在安全组或防火墙中把7500端口限制为仅允许可信 IP 访问。如果不需要远程查看 Dashboard,可以将监听地址保留为默认的127.0.0.1,或者直接关闭该功能。
至此,服务端配置完成。
在 NAS 上部署 frpc
frpc 不一定要部署在 NAS 上,也可以运行在其他需要向公网暴露内网服务的设备中。
我通过 Docker 在绿联 NAS 上部署 frpc,使用的镜像是 snowdreamtech/frpc。如果使用其他镜像,需要根据镜像说明调整配置文件的挂载路径和启动参数,并尽量让 frpc 与 frps 使用相同版本。
创建客户端配置
先在 NAS 的 Docker 目录中创建一个用于存放 frp 配置的文件夹,再创建 frpc.toml。绿联 NAS 的文件管理器不能直接新建 .toml 文件时,可以先创建 .txt 文件,编辑完成后再修改扩展名。
frpc.toml 内容如下:
# 公网服务器地址,以及 frps 的通信端口
serverAddr = "请填写公网服务器 IP 或域名"
serverPort = 7000
# 必须与 frps 的认证配置一致
auth.method = "token"
auth.token = "请填写与服务端相同的 Token"
# 一个 [[proxies]] 区块代表一个需要代理的服务
[[proxies]]
name = "mysql"
type = "tcp"
# NAS 上 MySQL 服务的地址和端口
localIP = "127.0.0.1"
localPort = 3306
# frps 在公网服务器上监听的代理端口
remotePort = 13306
这里几个容易混淆的配置项分别表示:
localIP和localPort:frpc实际要连接的内网服务地址;remotePort:frps在公网服务器上监听的端口。访问该端口的流量会被转发到前面的本地服务;name:代理名称,同一个frpc配置中的名称不能重复。
本例让 frpc 容器使用 host 网络,因此 127.0.0.1:3306 指向 NAS 主机上的 MySQL 端口。如果改用 Docker 的桥接网络,127.0.0.1 通常只指向 frpc 容器本身,此时需要把 localIP 改成 frpc 容器能够访问的 MySQL 地址。
创建并启动容器
创建容器时选择 host 网络,并按照镜像说明把刚才创建的 frpc.toml 映射到容器内的配置文件路径:

启动容器后,查看日志,确认 frpc 已连接到 frps,并且 mysql 代理启动成功。
还需要按照实际环境,在公网服务器的云安全组和系统防火墙中放行 13306 端口。完成后,可以在 Navicat 等 MySQL 客户端中使用下面的地址测试连接:
SERVER_IP:13306
也可以打开 http://SERVER_IP:7500,在 Dashboard 中查看代理状态:

谨慎暴露数据库端口
auth.token只用于认证frpc与frps,不会替代 MySQL 自身的账号和权限控制。不要把13306无限制地暴露到公网;建议在安全组或防火墙中仅允许可信来源 IP 访问,同时为 MySQL 使用高强度密码和最小权限账号。若访问端 IP 不固定,可以考虑通过 VPN 或 SSH 隧道访问数据库。
至此,NAS 上的 MySQL 服务已经可以通过公网服务器访问。
使用域名访问 Web 服务
对于 Web 服务,直接使用 IP:端口 访问不够直观,可以在公网服务器上通过 Nginx 或 1Panel 配置域名反向代理,把域名请求转发到 frp 暴露的 Web 服务端口。MySQL 这类 TCP 服务通常不需要配置 HTTP 反向代理。
frp 也原生支持 HTTP 和 HTTPS 类型的代理,可以根据域名转发请求。选择这种方式时,需要在 frps 中配置 vhostHTTPPort 或 vhostHTTPSPort,并在 frpc 的代理配置中设置 customDomains。具体配置可以参考官方文档中的通过自定义域名访问内网的 Web 服务。
无论采用哪种方式,都需要先把域名解析到公网服务器。若需要 HTTPS,还要根据所选方案,在公网反向代理或内网 Web 服务一侧配置证书。
评论