返回文章

使用 frp 实现 NAS 内网穿透:云服务器与 Docker 部署指南

10 分钟阅读

最近,我在一台阿里云服务器上部署多个服务后,系统因内存占用过高而卡死,甚至无法登录。重启排查后发现,这台服务器只有 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,用于 frpcfrps 之间的身份认证;
  • 确认 NAS 上的目标服务可以被 frpc 访问。

本文会用到三个端口:

  • 7000frpc 连接 frps 的通信端口;
  • 7500frps Dashboard 端口,可选;
  • 13306:示例中对外提供 MySQL 访问的代理端口。

如果服务器使用了云安全组和系统防火墙,需要同时配置两处规则。实际端口可以自行修改,但服务端与客户端的配置必须保持一致。

在公网服务器上部署 frps

我使用 1Panel 管理服务器,因此直接在应用商店中安装 frp 服务端:

如果不使用 1Panel,可以从 frp 的 GitHub Releases 页面下载与服务器系统和 CPU 架构匹配的版本。解压后,使用下面的命令启动 frps

./frps -c ./frps.toml

如果需要长期运行,可以再通过 systemd 等工具管理进程和开机自启。

配置服务端

使用 1Panel 安装时,可以直接在页面中填写配置:

frps-config

主要参数的作用如下:

  • 服务端口frps 接收 frpc 连接的端口,默认值为 7000
  • Dashboard 端口、用户名和密码:用于配置 frps 的 Web 管理界面;
  • Tokenfrpcfrps 之间的认证凭据,两端必须配置相同的值。

对应的 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 访问:

frps-webserver

不要直接公开管理面板

webServer.addr = "0.0.0.0" 会让 Dashboard 监听所有网卡。除了设置高强度密码,最好在安全组或防火墙中把 7500 端口限制为仅允许可信 IP 访问。如果不需要远程查看 Dashboard,可以将监听地址保留为默认的 127.0.0.1,或者直接关闭该功能。

至此,服务端配置完成。

在 NAS 上部署 frpc

frpc 不一定要部署在 NAS 上,也可以运行在其他需要向公网暴露内网服务的设备中。

我通过 Docker 在绿联 NAS 上部署 frpc,使用的镜像是 snowdreamtech/frpc。如果使用其他镜像,需要根据镜像说明调整配置文件的挂载路径和启动参数,并尽量让 frpcfrps 使用相同版本。

创建客户端配置

先在 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

这里几个容易混淆的配置项分别表示:

  • localIPlocalPortfrpc 实际要连接的内网服务地址;
  • remotePortfrps 在公网服务器上监听的端口。访问该端口的流量会被转发到前面的本地服务;
  • 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 只用于认证 frpcfrps,不会替代 MySQL 自身的账号和权限控制。不要把 13306 无限制地暴露到公网;建议在安全组或防火墙中仅允许可信来源 IP 访问,同时为 MySQL 使用高强度密码和最小权限账号。若访问端 IP 不固定,可以考虑通过 VPN 或 SSH 隧道访问数据库。

至此,NAS 上的 MySQL 服务已经可以通过公网服务器访问。

使用域名访问 Web 服务

对于 Web 服务,直接使用 IP:端口 访问不够直观,可以在公网服务器上通过 Nginx 或 1Panel 配置域名反向代理,把域名请求转发到 frp 暴露的 Web 服务端口。MySQL 这类 TCP 服务通常不需要配置 HTTP 反向代理。

frp 也原生支持 HTTP 和 HTTPS 类型的代理,可以根据域名转发请求。选择这种方式时,需要在 frps 中配置 vhostHTTPPortvhostHTTPSPort,并在 frpc 的代理配置中设置 customDomains。具体配置可以参考官方文档中的通过自定义域名访问内网的 Web 服务

无论采用哪种方式,都需要先把域名解析到公网服务器。若需要 HTTPS,还要根据所选方案,在公网反向代理或内网 Web 服务一侧配置证书。

参考资料

评论