通过 Docker、Nginx Proxy Manager 与 FRP 安全地暴露内网服务

1561 字
8 分钟
通过 Docker、Nginx Proxy Manager 与 FRP 安全地暴露内网服务

概述#

本指南通过组合使用 Docker、Nginx Proxy Manager (NPM) 和 FRP,安全地将位于内网(如家庭 NAS、开发电脑)的服务发布到公网。目标效果:

  • 只能通过自定义的 HTTPS 域名(如 nas.yourdomain.com)访问内网服务。
  • 内网服务的真实 IP 和端口不暴露,所有流量经由加密隧道和反向代理,降低端口扫描风险。
  • 使用 Docker Compose 统一管理云端服务,通过 NPM 的 Web UI 轻松管理域名和 SSL 证书。
NginxProxyManager
/
nginx-proxy-manager
Waiting for api.github.com...
00K
0K
0K
Waiting...
fatedier
/
frp
Waiting for api.github.com...
00K
0K
0K
Waiting...

架构概览#

流量路径:用户HTTPS 域名云服务器(443)NPM 容器Docker 内部网络frps 容器(代理端口)FRP 隧道内网 frpc 客户端内网目标服务

先决条件#

  • 一台云服务器 (VPS),拥有一个公网 IP 地址。
  • 一个域名,并将需要使用的子域名(如 nas)通过 A 记录解析到云服务器公网 IP。
  • 云服务器已安装 Docker 与 Docker Compose。
  • 一台内网设备(如 NAS),并已知其内网 IP 地址与端口。
TIP

推荐为云服务器开启防火墙,仅放行 80、81、443、7000 端口;其他由 FRP 动态创建的代理端口不需要对公网开放。

部署步骤#

第一步:准备服务器环境#

在云服务器上创建一个项目目录,用于存放所有配置文件。

Terminal window
# 创建项目目录并进入
mkdir my-proxy-stack
cd my-proxy-stack

在该目录中,我们将创建两个核心文件:frps.tomldocker-compose.yml

第二步:配置 frps 服务(frps.toml#

创建 frps.toml 文件,这是 FRP 服务端的配置文件。

Terminal window
nano frps.toml

将以下内容粘贴进去,并根据注释进行修改:

# frps 监听的地址,"0.0.0.0" 表示监听所有网络接口
bindAddr = "0.0.0.0"
# frps 用于和 frpc 客户端通信的主端口
bindPort = 7000
# [关键配置] 代理服务监听的地址
# 设置为 0.0.0.0 意味着它会监听在容器的内部IP上,
# 这样同一个 Docker 网络中的其他容器(如NPM)才能访问它。
# 因为该端口不会通过 Docker 映射到宿主机,所以公网无法访问,是安全的。
proxyBindAddr = "0.0.0.0"
# 认证配置
[auth]
# 指定认证方式与令牌
method = "token"
token = "YOUR_VERY_STRONG_AND_SECRET_TOKEN"

关键点

  • bindPort = 7000:FRP 的“握手”端口,需要暴露给公网,让内网的 frpc 能连接上来。
  • token:务必设置一个长且复杂的字符串,防止未经授权的客户端连接。
  • proxyBindAddr = 0.0.0.0:确保 NPM 容器可以访问到 frps 的代理端口。
TIP

如果云服务器开启了防火墙/安全组,记得放行 TCP 7000 端口。

第三步:编排 Docker 服务(docker-compose.yml#

创建 docker-compose.yml 文件,这是定义和运行我们所有服务的蓝图。

Terminal window
nano docker-compose.yml

将以下内容完整地粘贴进去:

version: '3.8'
services:
# 服务一:Nginx Proxy Manager (NPM)
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
# 公开的 Web 端口,用于接收外部用户的访问请求
- '80:80' # HTTP
- '443:443' # HTTPS
# NPM 自身的管理后台端口
- '81:81'
volumes:
- ./npm-data:/data
- ./npm-letsencrypt:/etc/letsencrypt
networks:
# 将 NPM 加入到我们自定义的共享网络中
- proxy-net
# 服务二:FRP Server (frps)
frps:
image: 'snowdreamtech/frps:latest'
container_name: frps
restart: unless-stopped
volumes:
# 将宿主机的 frps.toml 配置文件挂载到容器内部
- ./frps.toml:/etc/frp/frps.toml
ports:
# [关键] 只发布 frps 的主服务端口 7000 到公网
- '7000:7000'
# [注意] 千万不要在这里发布任何代理端口
networks:
# 将 frps 也加入到同一个共享网络中,以便和 NPM 通信
- proxy-net
# 定义一个自定义的桥接网络,用于服务间的内部通信
networks:
proxy-net:
driver: bridge

关键点

  • ports:只暴露 80, 81, 443, 7000 四个端口。由 FRP 动态创建的代理端口不对公网暴露。
  • networks: - proxy-net:确保 npmfrps 在同一 Docker 网络中,可通过容器名(frps)直接通信。

第四步:启动云端服务#

my-proxy-stack 目录下,运行以下命令来启动所有服务:

Terminal window
docker-compose up -d

检查服务是否正常运行:

Terminal window
docker-compose ps

您应该能看到 nginx-proxy-managerfrps 两个容器都处于 Up 状态。

第五步:配置 Nginx Proxy Manager#

  • 登录后台:在浏览器中访问 http://<你的服务器IP>:81
  • 首次登录:
    • 默认邮箱: [email protected]
    • 默认密码: changeme
    • 登录后会立即要求修改邮箱和密码,请务必修改为安全的凭据。
  • 添加代理主机 (Proxy Host):
    • 点击 HostsProxy HostsAdd Proxy Host
    • Details 标签页:
      • Domain Names: 输入域名,例如 nas.yourdomain.com
      • Scheme: 选择 http
      • Forward Hostname / IP: 输入 frps(frps 容器在 Docker 网络中的名字)。
      • Forward Port: 输入 8096(计划由 frpc 穿透过来的端口)。
      • 勾选 Block Common Exploits
    • SSL 标签页:
      • SSL Certificate: 选择 Request a new SSL Certificate
      • 勾选 Force SSLHTTP/2 Support
      • 同意 Let’s Encrypt 服务条款。
    • 点击 Save

NPM 会自动申请 SSL 证书并配置反向代理。几分钟后,您的域名就准备好了。

TIP

可在 NPM 中为不同内网服务添加多个 Proxy Host,并配合 Access List 实现基于用户名/密码的二次保护。

第六步:配置内网客户端(frpc.toml#

在您的内网设备(如 NAS)上,创建 frpc.toml 配置文件。

# 服务器(云主机)的公网 IP 地址
serverAddr = "YOUR_SERVER_PUBLIC_IP"
# 与 frps.toml 中设置的 bindPort 一致
serverPort = 7000
[auth]
method = "token"
token = "YOUR_VERY_STRONG_AND_SECRET_TOKEN"
# 定义一个代理
[[proxies]]
name = "nas_http_proxy" # 为代理起一个唯一的名字
type = "tcp" # 代理类型
localIP = "192.168.1.10" # 内网服务的 IP
localPort = 5000 # 内网服务的端口
remotePort = 5000 # 远程服务器的端口

启动 frpc 客户端(以 Linux 为例):

Terminal window
./frpc -c ./frpc.toml

建议将其设置为开机自启的服务。

第七步:最终验证#

  • 成功验证:在浏览器中访问 https://nas.yourdomain.com。应能看到内网服务页面,且浏览器地址栏显示锁形图标。
  • 安全验证:尝试访问 http://<你的服务器IP>:8096,应当失败(无法连接)。这证明内网服务端口未暴露在公网,只能通过 NPM 安全访问。
TIP

若证书申请失败,确认域名解析是否正确,80/443 端口是否被占用/屏蔽,以及服务器时间是否同步。

参考#

通过 Docker、Nginx Proxy Manager 与 FRP 安全地暴露内网服务
https://lunary.cc/posts/通过-dockernginx-proxy-manager-与-frp-安全地暴露内网服务/
作者
鹤望兰
发布于
2025-09-06
许可协议
CC BY-NC-SA 4.0