云边协同:基于 Docker 与 FRP 的家庭实验室全栈内网穿透指南

摘要 :家里有一台高性能工作站(如 ThinkStation P520),如何利用一台配置普通的公网云服务器,安全、优雅地从外网访问家里的服务?本文将介绍一套基于 Docker 的全栈解决方案,实现零侵入云端现有环境本地 Nginx 统一网关 以及基于 URL 路径的服务分发

1. 场景与需求

很多 HomeLab 玩家都有这样的困扰:

  1. 家庭宽带无公网 IP:高性能设备(P520, NAS)只能在局域网"自嗨"。
  2. 云服务器配置低:为了公网 IP 买的 VPS 通常只有 1核2G 或 2核4G,跑不动重型应用。
  3. 端口管理混乱 :每次加一个服务就要在防火墙开一个端口,记不住 IP:5000, IP:8081 这种地址。

本文的目标方案:

  • 云端 (Server):只做流量中转,不占用 80/443 端口(避免影响云端现有的建站业务)。
  • 边缘端 (Client) :家庭服务器通过 Docker 运行 Nginx 网关,所有服务通过 http://云IP:8080/app1/http://云IP:8080/app2/ 的方式访问。

2. 架构设计

我们采用 FRP (Fast Reverse Proxy) 建立隧道,配合 Nginx 进行七层反向代理。

复制代码
graph TD
    User[用户] -->|访问 http://云IP:8080/test/| Cloud_Firewall
    
    subgraph Cloud_Server [云服务器 (VPS)]
        Cloud_Firewall[防火墙 TCP:8080] --> Cloud_FRPS
        Existing_Nginx[现有 Nginx (Port 80)] -.->|互不干扰| Cloud_FRPS
        Cloud_FRPS[Docker: FRP 服务端]
    end

    Cloud_FRPS <==>|FRP 加密隧道 (TCP:7000)| Home_FRPC

    subgraph Home_Server [家庭服务器 (P520)]
        Home_FRPC[Docker: FRP 客户端] -->|流量转发| Home_Nginx
        Home_Nginx[Docker: Nginx 网关 (Port 80)]
        
        Home_Nginx -->|Location /test/| Web_App_1[容器: 测试页]
        Home_Nginx -->|Location /alist/| Web_App_2[容器: 网盘]
    end

3. 云服务器端部署 (FRP Server)

策略 :为了不影响云服务器上已经运行的 Nginx(占用 80 端口),我们将 FRP 的 Web 访问端口设为 8080

3.1 配置文件 frps.toml

复制代码
# frps.toml
bindPort = 7000           # FRP 客户端连接端口
vhostHTTPPort = 8080      # 【关键】外部访问 Web 的入口端口
auth.token = "YourStrongPassword2025" # 通信密钥

# 仪表盘配置 (可选)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin"

3.2 启动容器 docker-compose.yml

复制代码
version: '3.8'
services:
  frps:
    image: snowdreamtech/frps:latest
    container_name: frps
    restart: always
    network_mode: host  # 使用 host 模式,直接监听宿主机端口
    volumes:
      - ./frps.toml:/etc/frp/frps.toml

注意 :启动后,请务必在云服务器控制台(安全组)放行 TCP 70008080 端口。


4. 家庭服务器端部署 (FRP Client + Nginx)

策略:在 P520 上,我们使用 Docker Compose 编排三个服务:FRP 客户端、Nginx 网关、以及一个测试用的 Web 服务。

4.1 目录结构

建议在 ~/homelab 下统一管理:

复制代码
homelab/
├── docker-compose.yml
├── frpc.toml
└── nginx/
    ├── conf.d/
    │   └── default.conf
    └── html/
        └── index.html

4.2 穿透配置 frpc.toml

复制代码
serverAddr = "x.x.x.x"  # 你的云服务器公网 IP
serverPort = 7000
auth.token = "YourStrongPassword2025" # 必须与服务端一致

[[proxies]]
name = "home-gateway"
type = "http"
localIP = "127.0.0.1"
localPort = 80             # 将流量转发给本地的 Nginx
customDomains = ["x.x.x.x"] # 填云服务器 IP,如果有域名则填域名

4.3 Nginx 网关配置 nginx/conf.d/default.conf

这是实现 "路径分发" 的核心配置。

复制代码
server {
    listen       80;
    server_name  localhost;
    charset utf-8;  # 防止中文乱码

    # 1. 默认首页
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    # 2. 业务示例:测试服务
    # 外部访问: http://云IP:8080/test/
    # 内部转发: http://127.0.0.1:8081/
    location /test/ {
        # 【重点】proxy_pass 结尾加 / 表示截断路径
        # 即把 /test/ 后面的内容传给后端,去掉 /test 本身
        proxy_pass http://127.0.0.1:8081/; 
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

4.4 整体编排 docker-compose.yml

复制代码
version: '3.8'

services:
  # 服务 1: 穿透客户端
  frpc:
    image: snowdreamtech/frpc:latest
    container_name: frpc
    restart: always
    depends_on:
      - nginx-gateway
    volumes:
      - ./frpc.toml:/etc/frp/frpc.toml
    network_mode: "host" # 使用 Host 模式,方便访问本机 Localhost

  # 服务 2: 本地 Nginx 网关
  nginx-gateway:
    image: nginx:latest
    container_name: nginx-gateway
    restart: always
    ports:
      - "80:80" # 占据 P520 的 80 端口
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/html:/usr/share/nginx/html

  # 服务 3: 模拟业务应用 (用于测试)
  web-demo:
    image: nginx:alpine
    container_name: web-demo
    restart: always
    ports:
      - "8081:80" # 实际运行在 8081,通过网关转发
    # 简单映射个页面进去方便看效果
    volumes:
      - ./nginx/html:/usr/share/nginx/html 

5. 部署与验证

5.1 启动服务

在 P520 的 homelab 目录下执行:

复制代码
docker compose up -d

5.2 验证效果

  1. 内网验证 : 打开浏览器访问 P520 的内网 IP:http://192.168.x.x/test/,应该能看到测试页面。
  2. 公网验证 : 打开手机 4G,访问:http://云服务器IP:8080/test/

如果一切顺利,你应该能看到同样的页面。这意味着:请求 -> 云服务器 -> FRP 隧道 -> 家里 P520 -> Nginx -> 具体容器 的链路已经打通。


6. 技术避坑指南 (必读)

虽然"路径转发"(如 /app/)看起来很美,但在实际部署复杂应用时,你可能会遇到 静态资源 404 的问题。

  • 原因 : 比如你访问 /alist/,页面加载了一个 CSS 文件 /style.css。浏览器会去请求 http://云IP:8080/style.css,Nginx 会发现根目录下没有这个文件,因为这个文件实际在 /alist/ 下。
  • 解决方案
    1. 首选 :在应用本身的设置里,寻找 Base URLWeb Root 选项,将其设置为 /alist/
    2. 备选 :如果应用不支持 Base URL,建议放弃路径转发,改用 子域名 方案(如 alist.yourdomain.com),这需要你有自己的域名。

7. 总结

通过这套方案,我们成功地将家庭服务器纳入了云端网络架构中。未来如果想增加新服务(比如 HomeAssistant),只需:

  1. 在 Docker Compose 里添加服务容器。
  2. nginx/conf.d/default.conf 里增加一段 location /ha/ { ... }
  3. 重启 Nginx,无需修改云服务器和防火墙设置。

Happy Hacking!

相关推荐
Gold Steps.1 小时前
K8S基于 Argo Rollouts 的高级版本发布实践
云原生·容器·kubernetes
王九思2 小时前
Docker访问权限问题
docker·云原生·容器
孤岛悬城2 小时前
61 K8s之Pod控制器与配置资源管理
云原生·容器·kubernetes
噎住佩奇2 小时前
kubeadm方式部署单节点k8s
云原生·容器·kubernetes
追光的孩子3 小时前
window雷池WAF安装运行文档
云原生·eureka
不做码农好多年,该何去何从。3 小时前
云原生k8s(一)
云原生·容器·kubernetes
Y.O.U..5 小时前
Kubernetes-PV(PersistentVolume)和PVC(PersistentVolumeClaim)
云原生·容器·kubernetes
Curvatureflight5 小时前
Kubernetes完全指南:从集群搭建到生产部署
云原生·容器·kubernetes
博思云为5 小时前
企业级智能PPT生成:Amazon云+AI驱动,全流程自动化提效
人工智能·语言模型·云原生·数据挖掘·云计算·语音识别·aws
laozhoy15 小时前
K8s基础命令
云原生·容器·kubernetes