使用 Cloudflare Tunnel 隐藏网站源站
从公网域名、Cloudflared 连接器到仅监听本机的 Nginx 端口, 完整记录一次可验证、可回滚、不会影响主站的部署过程。
普通的 Cloudflare 橙色云依然要求 Cloudflare 主动访问服务器的公网
80 或 443 端口。Cloudflare Tunnel 则反过来:服务器中的
cloudflared 主动向 Cloudflare 建立出站连接,
外部请求再通过这条隧道进入本地服务。
本文不会直接迁移正在使用的主域名,而是先使用
w.jiuliu.org 做隔离测试。网站为纯 HTML、CSS、JavaScript,
即使测试失败,也不会影响主站和 WordPress。
用户访问 https://w.jiuliu.org,请求经过 Cloudflare
和加密 Tunnel,最终进入服务器本机的
127.0.0.1:8088,该端口不会对公网开放。
1. Cloudflare Tunnel 到底是什么
Cloudflare Tunnel 是 Cloudflare 官方提供的连接方式。服务器上运行一个轻量连接器
cloudflared,由它主动连接 Cloudflare 网络。对于被 Tunnel 接管的服务,
不再需要把应用端口直接暴露给公网。
源站仍要开放公网 Web 端口,知道源站 IP 的人可能尝试绕过 Cloudflare。
Cloudflared 主动建立出站连接,本地应用可以只监听 127.0.0.1。
Tunnel 只能保护被它接管的入口。如果同一服务器的其他域名、邮件服务、 VPN 或管理端口仍公开使用该 IP,别人仍可能知道服务器地址。
2. 本次部署方案
之所以不直接让 Tunnel 访问现有的 https://127.0.0.1:443,
是为了避开证书名称校验、HTTP 到 HTTPS 重定向以及多个虚拟主机之间的干扰。
单独增加一个仅本机监听的 HTTP 端口,结构更清晰,也更容易排错。
3. 建立仅供 Tunnel 使用的 Nginx 入口
创建一个独立虚拟主机,只监听 127.0.0.1:8088。
因为绑定的是回环地址,这个端口不需要在 Oracle 安全列表或 UFW 中开放。
sudo tee /www/server/panel/vhost/nginx/w-tunnel-local.conf > /dev/null <<'EOF'
server {
listen 127.0.0.1:8088;
server_name w.jiuliu.org;
root /www/wwwroot/jiuliu.org;
index index.html index.htm;
charset utf-8;
location / {
try_files $uri $uri/ =404;
}
location ~ /\. {
return 404;
}
location ~* \.(env|ini|conf|log|sql|bak|old|tmp|zip|rar|7z|tar|gz)$ {
return 404;
}
location ~* \.(gif|jpg|jpeg|png|webp|avif|bmp|svg|ico)$ {
expires 30d;
access_log off;
log_not_found off;
}
location ~* \.(css|js)$ {
expires 12h;
access_log off;
log_not_found off;
}
add_header X-Content-Type-Options "nosniff" always;
access_log /www/wwwlogs/w-tunnel-local.log;
error_log /www/wwwlogs/w-tunnel-local.error.log;
}
EOF
sudo nginx -t && sudo systemctl reload nginx其中真正生效的 Nginx 配置如下:
server {
listen 127.0.0.1:8088;
server_name w.jiuliu.org;
root /www/wwwroot/jiuliu.org;
index index.html index.htm;
charset utf-8;
location / {
try_files $uri $uri/ =404;
}
location ~ /\. {
return 404;
}
location ~* \.(env|ini|conf|log|sql|bak|old|tmp|zip|rar|7z|tar|gz)$ {
return 404;
}
location ~* \.(gif|jpg|jpeg|png|webp|avif|bmp|svg|ico)$ {
expires 30d;
access_log off;
log_not_found off;
}
location ~* \.(css|js)$ {
expires 12h;
access_log off;
log_not_found off;
}
add_header X-Content-Type-Options "nosniff" always;
access_log /www/wwwlogs/w-tunnel-local.log;
error_log /www/wwwlogs/w-tunnel-local.error.log;
}检查配置和端口
sudo nginx -t
sudo ss -lntp | grep 8088
curl -I \
-H 'Host: w.jiuliu.org' \
http://127.0.0.1:8088/
端口显示为 127.0.0.1:8088,并且 Curl 返回
HTTP/1.1 200 OK。
如果 React、Vue 或其他单页应用使用前端路由,可将
try_files $uri $uri/ =404; 改为
try_files $uri $uri/ /index.html;。
4. 在 Ubuntu 安装 Cloudflared
在 Cloudflare 创建 Tunnel 时,系统选择 Debian, 架构根据服务器选择 ARM64 或 64-bit。 Ubuntu 使用 Debian 软件包体系,因此可以直接使用 Cloudflare 官方 APT 软件源。
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-public-v2.gpg \
| sudo tee /usr/share/keyrings/cloudflare-public-v2.gpg > /dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-public-v2.gpg] https://pkg.cloudflare.com/cloudflared any main' \
| sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update
sudo apt-get install -y cloudflared
cloudflared --version本文实测版本为:
cloudflared version 2026.7.3 (built 2026-07-23-09:59 UTC)
后续 service install 命令包含一段很长的 Token。
不要把它发到聊天、博客、截图或公开代码仓库。
APT 被锁定怎么办
如果出现 /var/lib/apt/lists/lock 被其他进程占用,
不要直接删除锁文件。先查看占用进程,确认它是否仍在正常工作。
sudo ps -p <PID> -o pid,ppid,user,tty,stat,etime,cmd
sudo pstree -ap <PID>
sudo kill -TERM <PID>
sleep 5
sudo dpkg --configure -a
sudo apt-get -f install -y
sudo apt-get update对长期运行的生产服务器,可以保留自动检查更新,但关闭无人值守自动安装:
sudo systemctl enable --now apt-daily.timer && \
sudo systemctl disable --now apt-daily-upgrade.timer && \
printf 'APT::Periodic::Update-Package-Lists "1";\nAPT::Periodic::Unattended-Upgrade "0";\n' \
| sudo tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null5. 创建 Tunnel 与连接器
-
01
进入 Tunnel 页面
Cloudflare Zero Trust → Networks → Connectors → Cloudflare Tunnels。
-
02
选择 Cloudflared
不要选择 Mesh。本次需求是把公开域名映射到本地 Web 服务。
-
03
设置名称
例如
oracle-arm-w,名称只用于后台识别。 -
04
安装为系统服务
复制 Cloudflare 页面提供的第二条命令:
sudo cloudflared service install <你的 Tunnel Token>
不建议只执行临时的 cloudflared tunnel run --token ...,
因为关闭终端后进程可能停止。安装为 systemd 服务后,可以后台常驻并随系统启动。
sudo systemctl status cloudflared --no-pager
sudo journalctl -u cloudflared -n 50 --no-pager
sudo systemctl restart cloudflared
sudo systemctl enable cloudflared
Systemd 显示 Active: active (running),
Cloudflare 页面出现连接器,状态为 Healthy。
6. 将 w.jiuliu.org 指向本机 8088
连接器在线后,进入 Tunnel 的“已发布的应用程序路由”,添加一条新路由。
页面已经单独选择了 HTTP 类型,因此地址输入框中只填写
127.0.0.1:8088,不要重复写成
http://http://127.0.0.1:8088。
在“其他应用程序设置 → HTTP 设置”中,将
HTTP Host 标头设为 w.jiuliu.org。
这样 Nginx 会收到正确的 Host 请求头。
Cloudflared 到本机使用的是 HTTP,而不是 HTTPS, 所以不存在本地证书名称不匹配问题。
7. 删除冲突的旧 DNS 记录
如果 w.jiuliu.org 原来已经存在指向源站 IP 的
A、AAAA 或 CNAME 记录,需要先删除同名旧记录。
Tunnel 路由会让该域名关联到类似下面的地址:
<Tunnel UUID>.cfargotunnel.com如果保存时提示同名 A、AAAA 或 CNAME 已存在,说明旧记录尚未清理干净。
8. 验证请求是否真的经过 Tunnel
curl -I https://w.jiuliu.org/
sudo tail -n 20 /www/wwwlogs/w-tunnel-local.log成功时,Curl 响应中通常能看到:
HTTP/2 200
server: cloudflare
cf-cache-status: DYNAMIC
cf-ray: ...
同时,/www/wwwlogs/w-tunnel-local.log 中出现新的访问记录,
才能证明请求完整经过了:
9. 阻止访客绕过 Tunnel 直连源站
仅从旧虚拟主机的 server_name 中删除
w.jiuliu.org 并不一定足够。Nginx 找不到匹配域名时,
仍可能由 443 端口的默认虚拟主机返回页面。
可以使用下面的命令直接测试源站:
curl -kI \
--resolve w.jiuliu.org:443:152.70.124.102 \
https://w.jiuliu.org/
如果返回 server: nginx 和 HTTP 200,
表示源站仍接受带有该 Host/SNI 的直连请求。
同一服务器仍有其他网站使用 80/443 时
不要直接关闭整台服务器的 80/443。可以为
w.jiuliu.org 单独建立拒绝访问的公网虚拟主机,
而 Tunnel 继续使用 127.0.0.1:8088。
sudo tee /www/server/panel/vhost/nginx/w-origin-deny.conf > /dev/null <<'EOF'
server {
listen 80;
listen [::]:80;
server_name w.jiuliu.org;
return 444;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name w.jiuliu.org;
ssl_certificate /www/server/panel/vhost/cert/jiuliu.org/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/jiuliu.org/privkey.pem;
return 444;
}
EOF
sudo nginx -t && sudo systemctl reload nginx
上面的示例沿用宝塔中 jiuliu.org 的证书路径。
执行前确认该证书包含 w.jiuliu.org,并先运行
nginx -t。
拒绝规则生效后,直连测试通常会得到:
curl: (52) Empty reply from server但正常域名访问仍应保持:
HTTP/2 200
server: cloudflare10. 在 Nginx 中恢复访客真实 IP
如果 Nginx 日志只显示 127.0.0.1,
可以让本地 Tunnel 入口读取 Cloudflare 传递的
CF-Connecting-IP。
set_real_ip_from 127.0.0.1;
set_real_ip_from ::1;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
这里只信任本机回环地址提供该请求头,避免公网访客自行伪造
CF-Connecting-IP。
sudo nginx -t
sudo systemctl reload nginx
sudo tail -f /www/wwwlogs/w-tunnel-local.log11. 常见问题与解决方法
连接器区域一直为空
只安装 cloudflared 软件还不够,还要执行 Cloudflare 页面提供的
sudo cloudflared service install <TOKEN>。
Cloudflare 返回 502
Tunnel 已连接,但 Cloudflared 无法访问本地服务。依次检查
ss -lntp | grep 8088、
curl http://127.0.0.1:8088 和 Nginx 错误日志。
保存路由时提示 DNS 记录已存在
删除 w.jiuliu.org 原有的同名 A、AAAA 或 CNAME,
再重新保存 Tunnel 路由。
页面发生无限重定向
通常是 Tunnel 使用 HTTP 连接了一个强制跳转 HTTPS 的 80 端口。
本文使用独立的 127.0.0.1:8088,不会触发原站的跳转规则。
删除旧 server_name 后源站仍返回 200
请求落到了默认虚拟主机。为该域名单独创建公网
return 444 虚拟主机即可。
Nginx 提示 conflicting server name
表示同一监听地址和端口上存在重复的 server_name。
使用 grep -RIn 找到重复配置,再逐一核对,不要直接删除未知文件。
12. 日常维护命令
sudo systemctl status cloudflared --no-pager
sudo journalctl -u cloudflared -n 50 --no-pager
sudo systemctl restart cloudflared
sudo systemctl enable cloudflared升级 Cloudflared
sudo apt-get update
sudo apt-get install --only-upgrade -y cloudflared
sudo systemctl restart cloudflared
cloudflared --version快速健康检查
curl -I https://w.jiuliu.org/
sudo systemctl is-active cloudflared
sudo ss -lntp | grep 808813. 最终总结
本次部署最关键的设计,不是简单地把域名指向 Tunnel,而是为 Tunnel 建立一个只监听回环地址的 Nginx 入口:
这种结构不依赖本地 HTTPS 证书,不会和原站 80/443 的重定向规则互相影响, 也不需要把 8088 开放到 Oracle 防火墙。后续迁移 WordPress、后台或其他服务时, 可以继续采用“每个应用一个本地端口”的方式,逐个测试、逐个切换。
域名响应包含 server: cloudflare,并且
w-tunnel-local.log 中出现对应请求。













暂无评论内容