Skip to content

Homelab 终极远程访问架构:Cloudflare Tunnel + Nginx 统一接入层(多 SSH 主机版)

ESXi 8.0 启动 U 盘制作示意图

不只是 Web 服务,连 SSH 都能统一接入。通过 Nginx Stream 模块 + SNI 路由,一个隧道、一个端口,访问任意 SSH 主机。


为什么需要这套架构?

如果你已经尝试过 Cloudflare Tunnel,可能会遇到几个很实际的问题:

  1. 子域名泛滥:每新增一个服务就需要增加一个二级域名,DNS 记录越来越长。
  2. 协议受限cloudflared 原生主要支持 HTTP/HTTPS,SSH 等 TCP 协议需要额外处理。
  3. 多 SSH 主机困境:当 Homelab 中有多台机器需要通过 SSH 访问时,简单的 TCP 隧道方案无法区分目标主机。

这套架构的核心目标就是解决这些问题:通过 Nginx 统一接入层,实现所有内网服务(包括多台 SSH 主机)的智能路由与统一管理。

终级方案整体架构

这套架构的核心思想是:在 Homelab 内部部署一个 Nginx 反向代理,作为所有内网服务的唯一入口。cloudflared 只需要将流量指向这个 Nginx,由 Nginx 根据请求的特征(域名、路径、协议)将流量路由到具体的后端服务。

text
公网用户


Cloudflare 边缘节点 (HTTPS/TLS)
    │  (加密隧道)

cloudflared (Homelab 中的守护进程)
    │  (将流量转发到 Nginx)

Nginx 统一接入层 (核心路由)

    ├── HTTP/HTTPS 路由 (通过 location 路径)
    │   ├── https://homelab-esxi.your-domain.com → ESXi (192.168.0.201:443)
    │   ├── https://homelab-vcenter.your-domain.com → vCenter (192.168.0.202:443)
    │   └── https://gitlab.your-domain.com → GitLab (172.16.0.10:80)  [独立子域名]

    └── TCP/SSH 路由 (通过 SNI)
        ├── dev.homelab.your-domain.com → 开发机 (172.16.0.10:22)
        ├── k8s.homelab.your-domain.com → K8s 主节点 (172.16.0.20:22)
        └── storage.homelab.your-domain.com → 存储节点 (172.16.0.30:22)

💡 注意

解决 esxi 及 vcenter 路由重写添加 /ui 问题,必须使用独立二级域名

准备工作

在开始之前,确保你已经具备以下条件:

条件说明
Cloudflare 账号你拥有的域名已在 Cloudflare 上托管
一台 Linux 虚拟机用于运行 cloudflared 守护进程(如 Ubuntu 22.04 LTS)
内网服务信息ESXi、vCenter 等服务的 IP 地址和端口

前置操作

登录到您的 Linux 虚拟机,完成以下操作。

1. 配置本地 HOST DNS 解析

查看 Linux 虚拟机的静态 IP(例如 192.168.0.212),执行以下命令将其写入 /etc/hosts 文件,以便在 Nginx 配置文件中使用 homelab.local 主机名:

bash
echo "192.168.0.212 homelab.local" | sudo tee -a /etc/hosts

2. 安装 cloudflared

bash
# 下载并安装 cloudflared
wget -q https://github.com/cloudflare/cloudflared/releases/download/2026.7.2/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb

# 验证安装
cloudflared --version

3. 安装 NGINX

bash
sudo apt update
sudo apt install nginx -y

第一部分:NGINX 端配置

1.1 创建 SSL 配置目录并上传证书

bash
sudo mkdir -p /etc/nginx/ssl

将 Cloudflare Origin CA 证书(.pem)和私钥(.key)文件上传到 /etc/nginx/ssl/ 目录下。

证书说明:在 Cloudflare Dashboard → SSL/TLS → Origin Server 中创建证书,选择「Let Cloudflare generate a private key and CSR」,有效期建议设置为最长(15 年)。下载后上传至服务器即可。

1.2 配置 Nginx HTTP/HTTPS 路由(Web 服务)

我们使用 /etc/nginx/conf.d/ 目录,按服务拆分配置文件。首先删除默认的 sites-enabled/default,然后为每个服务创建独立的配置文件。

bash
sudo rm -f /etc/nginx/sites-enabled/default

1.2.1 统一入口配置:homelab.conf

nginx
# /etc/nginx/conf.d/homelab.conf
server {
    listen 443 ssl http2;
    server_name homelab.your-domain.com;

    ssl_certificate /etc/nginx/ssl/your-domain.com.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    access_log /var/log/nginx/homelab-access.log;
    error_log /var/log/nginx/homelab-error.log;

    # Cloudflare IP 地址范围(用于获取真实客户端 IP)
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    real_ip_header CF-Connecting-IP;

    # 路径路由:通过 location 区分不同服务
    # location /esxi/ {
    #     proxy_pass https://192.168.0.201:443/;
    #     proxy_ssl_verify off;
    #     proxy_set_header Host $host;
    #     proxy_set_header X-Real-IP $remote_addr;
    #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #     proxy_set_header X-Forwarded-Proto $scheme;
    # }

    # location /vcenter/ {
    #     proxy_pass https://192.168.0.202:443/;
    #     proxy_ssl_verify off;
    #     proxy_set_header Host $host;
    #     proxy_set_header X-Real-IP $remote_addr;
    #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #     proxy_set_header X-Forwarded-Proto $scheme;
    # }

    location / {
        return 404;
    }
}

1.2.2 ESXi 限定前缀域名配置 homelab-esxi.conf

/etc/nginx/conf.d/homelab-esxi.conf
nginx
# /etc/nginx/conf.d/homelab-esxi.conf
server {
    listen 443 ssl http2;
    server_name homelab-esxi.your-domain.com;

    ssl_certificate /etc/nginx/ssl/your-domain.com.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    access_log /var/log/nginx/esxi-access.log;
    error_log /var/log/nginx/esxi-error.log;

    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    real_ip_header CF-Connecting-IP;

    location / {
        proxy_pass https://192.168.0.201;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

1.2.3 vCenter 限定前缀域名配置 homelab-vcenter.conf

/etc/nginx/conf.d/homelab-vcenter.conf
nginx
# /etc/nginx/conf.d/homelab-vcenter.conf
server {
    listen 443 ssl http2;
    server_name homelab-vcenter.your-domain.com;

    ssl_certificate /etc/nginx/ssl/your-domain.com.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    access_log /var/log/nginx/vcenter-access.log;
    error_log /var/log/nginx/vcenter-error.log;

    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    real_ip_header CF-Connecting-IP;

    location / {
        proxy_pass https://192.168.0.202;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

1.2.4 GitLab 独立域名配置:gitlab.conf

nginx
# /etc/nginx/conf.d/gitlab.conf
server {
    listen 443 ssl http2;
    server_name gitlab.your-domain.com;

    ssl_certificate /etc/nginx/ssl/your-domain.com.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    access_log /var/log/nginx/gitlab-access.log;
    error_log /var/log/nginx/gitlab-error.log;

    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    real_ip_header CF-Connecting-IP;

    location / {
        proxy_pass http://172.16.0.10:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

1.2.5 default.conf(默认 404 规则)

nginx
# /etc/nginx/conf.d/default.conf
server {
    listen 443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/your-domain.com.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;

    return 404;
}

1.2.6 http-redirect.conf(HTTP 强制跳转 HTTPS)

nginx
# /etc/nginx/conf.d/http-redirect.conf
server {
    listen 80;
    server_name homelab.your-domain.com gitlab.your-domain.com;
    return 301 https://$host$request_uri;
}

1.3 配置 Nginx TCP/SSH 多主机路由(核心)

编辑 /etc/nginx/nginx.conf,在 events 模块之后添加 Stream 配置:

nginx
stream {
    map $ssl_preread_server_name $ssh_backend {
        dev.homelab.your-domain.com   172.16.0.10:22;
        k8s.homelab.your-domain.com   172.16.0.20:22;
        storage.homelab.your-domain.com  172.16.0.30:22;
        default                       172.16.0.10:22;
    }

    server {
        listen 2222;
        proxy_pass $ssh_backend;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        ssl_preread on;
    }
}

配置完成后,执行 sudo nginx -t 检查配置语法是否正确,然后执行 sudo systemctl reload nginx 重新加载配置。

第二部分:cloudflared 端配置

2.1 认证并绑定域名

bash
cloudflared tunnel login

命令执行后会返回一个授权链接。在浏览器中打开该链接,选择你的 Cloudflare 域名,完成授权。

提示:授权成功后,cloudflared 会在你的虚拟机中生成一个 cert.pem 证书文件,用于后续的身份验证。

2.2 创建隧道

bash
cloudflared tunnel create homelab

执行后会生成一个 Tunnel UUID 和一个 credentials 文件(如 <Tunnel UUID>.json),请妥善保管。

2.3 配置隧道路由规则

创建 ~/.cloudflared/config.yml 配置文件:

yaml
tunnel: <你的 Tunnel UUID>
credentials-file: /root/.cloudflared/<Tunnel UUID>.json

ingress:
  - hostname: homelab.your-domain.com
    service: https://homelab.local:443
    originRequest:
      noTLSVerify: true
      httpHostHeader: homelab.your-domain.com

  - hostname: homelab-esxi.your-domain.com
    service: https://homelab.local:443
    originRequest:
      noTLSVerify: true
      httpHostHeader: homelab-esxi.your-domain.com

  - hostname: homelab-vcenter.your-domain.com
    service: https://homelab.local:443
    originRequest:
      noTLSVerify: true
      httpHostHeader: homelab-vcenter.your-domain.com

  - hostname: gitlab.your-domain.com
    service: https://homelab.local:443
    originRequest:
      noTLSVerify: true
      httpHostHeader: gitlab.your-domain.com

  - hostname: ssh.your-domain.com
    service: tcp://homelab.local:2222

  - service: http_status:404

ingress 参数说明

参数类型必填说明
hostnamestring是(除默认规则外)匹配的外部域名。支持精确匹配或通配符。
servicestring转发目标地址,格式为 协议://地址:端口。支持 http://https://tcp://unix://http_status:code
originRequestobject定义转发时的请求行为。
originRequest.noTLSVerifybool否(建议 true是否跳过对后端服务 TLS 证书的验证。
originRequest.httpHostHeaderstring覆盖转发请求中的 Host 头。
originRequest.originServerNamestring指定后端服务器的 SNI。
originRequest.tcpKeepAliveint设置 TCP Keep-Alive 探测间隔(秒)。

2.4 配置 DNS 记录

bash
cloudflared tunnel route dns homelab homelab.your-domain.com
cloudflared tunnel route dns homelab homelab-esxi.your-domain.com
cloudflared tunnel route dns homelab homelab-vcenter.your-domain.com
cloudflared tunnel route dns homelab gitlab.your-domain.com
cloudflared tunnel route dns homelab ssh.your-domain.com

设计说明homelab.your-domain.com 作为所有 Web 服务的统一入口,通过路径(如 /esxi/vcenter)区分后端服务。GitLab 和 SSH 因协议或管理需要,保留独立子域名。这种设计在保持子域名收敛的同时,为特殊服务保留了灵活性。

第三部分:负载相关服务

3.1 启动 Nginx

bash
sudo systemctl start nginx
sudo systemctl enable nginx

3.2 启动 cloudflared 隧道

bash
cloudflared tunnel --loglevel=debug run homelab

💡 注意

该方式为测试时,使用的终端模式,测试完成后必须通过使用 cloudflare service 管理服务,可以参考

3.3 验证 HTTP/HTTPS 访问

bash
curl -k https://homelab-esxi.your-domain.com
curl -k https://homelab-vcenter.your-domain.com
curl -k https://gitlab.your-domain.com

3.4 验证 SSH 多主机访问

bash
# 访问开发机
ssh -o ProxyCommand="cloudflared access ssh --hostname %h" [email protected]

# 访问 K8s 主节点
ssh -o ProxyCommand="cloudflared access ssh --hostname %h" [email protected]

# 访问存储节点
ssh -o ProxyCommand="cloudflared access ssh --hostname %h" [email protected]

如果觉得每次都要输入 ProxyCommand 很麻烦,可以在 ~/.ssh/config 中添加配置:

ssh-config
Host *.homelab.your-domain.com
    ProxyCommand cloudflared access ssh --hostname %h

之后只需要执行 ssh [email protected] 即可。

第四部分:生产环境 cloudflared 服务管理

在测试内网穿透过程中我们可以使用以下命令进行调试

bash
cloudflared tunnel --loglevel=debug run homelab

调试完成之后我们就需要通过 systemd 的方式来管理 cloudflared 了,cloudflared 提供了一个 service 子命令

bash
cloudflared service help

具体的命令信息如下

NAME:
   cloudflared service - Manages the cloudflared system service

USAGE:
   cloudflared service [global options] command [command options] [arguments...]

COMMANDS:
   install    Install cloudflared as a system service
   uninstall  Uninstall the cloudflared service
   help, h    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h  show help (default: false)

4.1 生成 cloudflared systemd 服务定义文件

要生成 cloudflared systemd 服务定义文件,只需要执行以下命令即可

bash
cloudflared service install

具体的执行日志如下

2026-07-22T17:09:05Z INF Using Systemd
2026-07-22T17:09:07Z INF Linux service for cloudflared installed successfully

它将会在 /etc/systemd/system 生成一个名为 cloudflared.service 的服务定义文件

/etc/systemd/system/cloudflared.service
ini
[Unit]
Description=Cloudflare Tunnel client
After=network-online.target
Wants=network-online.target

[Service]
TimeoutStartSec=15
Type=notify
ExecStart=/usr/bin/cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

4.2 验证 cloudflared 服务状态

在上面一步执行 cloudflared service install 时,cloudflared 软件包就会生成 systemd 服务定义文件并且启动 cloudflared 服务,我们可以执行以命令来验证

bash
systemctl status cloudflared

将会输出类似如下的服务状态信息

● cloudflared.service - Cloudflare Tunnel client
     Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2026-07-22 17:09:07 UTC; 4min 34s ago
   Main PID: 36946 (cloudflared)
      Tasks: 10 (limit: 9383)
     Memory: 15.7M
        CPU: 1.438s
     CGroup: /system.slice/cloudflared.service
             └─36946 /usr/bin/cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run

Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF |  SUMMARY: Environment is healthy. cloudflared will use 'quic' as p>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF +------------------------------------------------------------------->
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="DNS Resolution" details="DNS Resolved successful>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="DNS Resolution" details="DNS Resolved successful>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="UDP Connectivity" details="QUIC connection succe>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="UDP Connectivity" details="QUIC connection succe>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="TCP Connectivity" details="HTTP/2 connection suc>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="TCP Connectivity" details="HTTP/2 connection suc>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck component="Cloudflare API" details="API is reachable" run_i>
Jul 22 17:09:13 cloudflared cloudflared[36946]: 2026-07-22T17:09:13Z INF precheck complete hard_fail=false run_id=a55be9f4-82cb-4244-a61e-c3a>
lines 1-20/20 (END)

并且,已经设置为开机自动启动。这样,即使你服务重启,cloudflared 服务也会被 systemd 守护进行拉起,是不是非常的丝滑!这就可以愉快的内网穿透了,你开心吧~

配置文件结构总览

text
/etc/nginx/
├── conf.d/
│   ├── homelab.conf          # 统一入口路径路由(核心)
│   ├── homelab-esxi.conf     # exsi
│   ├── homelab-vcenter.conf  # vcenter
│   ├── gitlab.conf           # GitLab 独立子域名
│   ├── default.conf          # 默认 404 规则
│   └── http-redirect.conf    # HTTP 强制跳转 HTTPS
├── ssl/
│   ├── your-domain.com.pem
│   └── your-domain.com.key
└── nginx.conf                # 主配置文件(包含 Stream 模块配置)

架构优势总结

特性说明
子域名收敛Web 服务统一使用 homelab.your-domain.com,通过路径区分服务
多 SSH 主机支持通过 Nginx Stream + SNI 路由,一个端口支持无限 SSH 目标
统一接入层所有流量集中经过 Nginx,配置统一
扩展性强新增服务只需在 Nginx 中添加 location
配置清晰每个服务独立配置文件,便于维护

工作原理简述

HTTP/HTTPS 路径路由:

  1. 用户访问 https://homelab.your-domain.com/esxi/
  2. Cloudflare 通过隧道转发给 cloudflared
  3. cloudflared 转发给 Nginx
  4. Nginx 根据 location /esxi/ 代理到 ESXi 后端

SSH SNI 路由:

  1. SSH 客户端连接 dev.homelab.your-domain.com
  2. cloudflared 将 TCP 流量转发到 Nginx 的 2222 端口
  3. Nginx 通过 ssl_preread 读取 SNI,根据 map 规则转发到对应后端

需要注意的细节

  • 路径尾随斜杠proxy_pass 中的尾随斜杠会影响 URL 重写,请确保配置正确。
  • Nginx SSL 证书:使用 Cloudflare Origin CA 证书,上传至 /etc/nginx/ssl/ 目录。
  • Cloudflare IP 地址范围:需与 Cloudflare 官方 IP 列表保持一致,建议定期更新。
  • 本地 DNS 解析/etc/hosts 中定义 homelab.local 指向 Nginx 内网 IP。
  • Stream 模块位置:Stream 配置只能放在 nginx.conf 主配置文件中。

结语

这套架构,本质上是在 Homelab 内部构建了一个企业级的反向代理接入层 + TCP 智能路由层。它使得你的内网服务不再孤立,而是通过一个统一的入口对外提供访问。当你未来添加新服务时,只需在 Nginx 配置中增加一条 location 规则,整个流程保持简洁、可控。

相关文档


附录:相关 IP 地址参考

  • ESXi 管理地址https://192.168.0.201
  • vCenter 管理地址https://192.168.0.202
  • Nginx 统一接入层https://homelab.local(Homelab 内部访问)
  • SSH 目标主机示例
    • 开发机:172.16.0.10:22
    • K8s 主节点:172.16.0.20:22
    • 存储节点:172.16.0.30:22
最后更新2026/08/14 02:07
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal