需求:
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服务