需求:

a.docker部署的三个服务分别为 portainer,ghcr,nginx 三个需要用https:域名访问(80/443被禁的)
如何实现:通过Cloudflare tunnel穿透(通过的是Cloudflare的443端口自带SSL)
b.网络为ipv6,ipv4为内网
如何实现:通过Cloudflare tunnel穿透(cf会接收ipv6请求转发给本地服务器ipv4)

一、部署Cloudflare tunnel

a.安装cloudflaretunnel客户端

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb

登陆获取通行证

cloudflared tunnel login

访问cloud给的链接并授权

b.创建tunnel并配置

cloudflared tunnel create ${tunnel_name}
例如:
cloudflared tunnel create nginx-tunnel

c.配置隧道

配置隧道:
(编辑 /root/.cloudflared/config.yml) 一般在~/.cloudflared/config.yml
目录:/root/.cloudflared
tunnel: <TUNNEL-ID> # 就是同目录下的json文件的文件名
credentials-file: /path/to/credentials.json
ingress:
- hostname: xxx # 需要访问的域名
service: http://192.xxxx:80 # 指向内网服务
- service: http_status:404


例如:

tunnel: e6060801-4fc1-41bd-afe1-xxxxx

credentials-file: /root/.cloudflared/e6060801-4fc1-41bd-afe1-xxxxx.json

ingress:

  - hostname: xxx.eu.org            # 需要访问的域名

    service: http://localhost:8888  # 指向您的内网服务

  - hostname: www.xxx.eu.org        # 需要访问的域名
    service: http://localhost:8080  # 指向您的内网服务

  - hostname: portainer.xxx.eu.org  # 需要访问的域名
    service: http://localhost:9000  # 指向您的内网服务

  - hostname: ghcr.xxx.eu.org       # 需要访问的域名
    service: http://localhost:3000  # 指向您的内网服务

  - service: http_status:404

dns:

  ip6: true

验证配置文件格式是否正确

cloudflared tunnel ingress validate

d.配置DNS记录

cloudflared tunnel route dns <tunnel-name> <domain>

例如:
cloudflared tunnel route dns e6060801-4fc1-41bd-afe1-xxxx xxxx.eu.org
#如果还有其他域名需要配置,可以继续执行上面的命令。配置完成后可以前往Cloudflare控制台查看到CNAME记录。

e.运行tunnel

cloudflared tunnel --config /root/.cloudflared/config.yml run <TUNNEL-ID>

例如
cloudflared tunnel --config /root/.cloudflared/config.yml run e6060801-4fc1-41bd-afe1-xxxx

!!!推荐:
例如:加入后台运行指定json保存启动日志

nohup cloudflared tunnel --credentials-file /root/.cloudflared/e6060801-4fc1-41bd-afe1-xxxx.json run  <TUNNEL-ID>> /root/.cloudflared/cloudflared.log 2>&1 &

目前实现:
访问:www.xxx.eu.org ,portainer.xxx.eu.org,ghcr.xxx.eu.org 被CF代理到本地的8080 9000 3000端口并且是带有SSL的
Cloudflare tunnel自带域名分流实际无需再去借助nginx

二、借助Nginx分流

a.修改tunnel的config.yaml
需要将所有的service指向nginx的端口
例如我nginx是8080
9000 ---->8080

例如:

    tunnel: e6060801-4fc1-41bd-afe1-xxxxx

credentials-file: /root/.cloudflared/e6060801-4fc1-41bd-afe1-xxxxx.json

ingress:

  - hostname: xxx.eu.org            # 需要访问的域名

    service: http://localhost:8080  # 指向您的内网服务

  - hostname: www.xxx.eu.org        # 需要访问的域名
    service: http://localhost:8080  # 指向您的内网服务

  - hostname: portainer.xxx.eu.org  # 需要访问的域名
    service: http://localhost:8080  # 指向您的内网服务

  - hostname: ghcr.xxx.eu.org       # 需要访问的域名
    service: http://localhost:8080  # 指向您的内网服务

  - service: http_status:404

dns:
 ip6: true

b.重新启动tunnel

ps -ef|grep -i cloudflared #获取进程PID
kill -9 $PID
例如:
kill -9 1111

#启动tunnel

nohup cloudflared tunnel --credentials-file /root/.cloudflared/e6060801-4fc1-41bd-afe1-xxxx.json run  <TUNNEL-ID>> /root/.cloudflared/cloudflared.log 2>&1 &

c.修改nginx配置文件 default.conf

#配置nginx前端页面域名用于排查nginx是否正常访问

server {

    listen 80;   #nginx为容器映射端口为8080:80所以使用80

    listen [::]:80;

    server_name www.xxxx.eu.org; 



    location / {

        root   /usr/share/nginx/html;

        index  index.html index.htm;

    }



    error_page   500 502 503 504  /50x.html;

    location = /50x.html {

        root   /usr/share/nginx/html;

    }

}

#配置nginx分流9000端口服务

server {

    listen 80;    #nginx为容器映射端口为8080:80所以使用80

    server_name portainer.xxxx.org;  #域名



    location / {

        proxy_pass http://192.xxx:9000;  #这里写机器的IP,也就是宿主机的IP不要写docker的
                                         #因为这几个docker服务不在一个网络组只能通过宿主机代理

        proxy_set_header Host $host;

        proxy_set_header X-Real-IP $remote_addr;

    }

}

#配置nginx分流3000端口服务

server {

    listen 80;    #nginx为容器映射端口为8080:80所以使用80

    server_name ghcr.xxx.org;  #域名



    location / {

        proxy_pass http://192.xxx:3000;  #这里写机器的IP,也就是宿主机的IP不要写docker的
                                         #因为这几个docker服务不在一个网络组只能通过宿主机代理

        proxy_set_header Host $host;

        proxy_set_header X-Real-IP $remote_addr;

    }

}

d.nginx检查&重启

docker exec -it <$nginx容器ID> bash
nginx -t 检查配置文件

docker restart <$nginx容器ID>

实现效果:

访问:www.xxx.eu.org ,portainer.xxx.eu.org,ghcr.xxx.eu.org 被CF代理到本地的nginx的8080端口并且是带有SSL的

分流是否需要使用nginx场景:

使用场景 是否需要 Nginx
通过路径(如 /portainer)而不是子域名分流 ✅ 需要
多个容器监听的是 同一个端口,必须统一入口 ✅ 需要
需要做 URL 重写、WebSocket 转发等高级配置 ✅ 需要
配置一个子域名(比如只配置 vps.xxx.org)再在它内部分发 ✅ 需要
每个服务有独立子域名,Tunnel 直接转发即可 ❌ 不需要

原理

使用Cloudflared tunnel自带分流(不使用nginx分流实现原理):
用户访问 ---> ipv6 ---> Cloudflared tunnel(自带443ssl证书) ---> 通过DNS的CNAME记录 ---> 对应域名后端端口(config.ymal)---> 通过ipv4转发内部对应服务

使用nginx分流实现原理:
用户访问 域名a ---> ipv6 ---> Cloudflared tunnel(自带443ssl证书) ---> 通过DNS的CNAME记录 ---> 对应域名后端端口(config.ymal都配置转发8080端口,也就是nginx的端口) ---> 通过ipv4转发内部docker-nginx服务 ---> nginx通过反向代理进行分流 ---> location到域名a ---> 转发本地对应a服务

用户访问 域名b ---> ipv6 ---> Cloudflared tunnel(自带443ssl证书) ---> 通过DNS的CNAME记录 ---> 对应域名后端端口(config.ymal都配置转发8080端口,也就是nginx的端口) ---> 通过ipv4转发内部docker-nginx服务 ---> nginx通过反向代理进行分流 ---> location到域名b ---> 转发本地对应b服务

最后修改:2025 年 08 月 06 日
如果觉得我的文章对你有用,请点个赞支持一下