家用虚拟机外网访问收口:HA、博客与 Cloudflare Tunnel 一次打通

上一篇聊了 Cloudflare Tunnel 解决面板暴露给外网的问题;这篇是收口篇:把
Home Assistant 和博客也挂到同一个隧道上,顺带踩坑记录一个 HA 2026.8 的
“反直觉”变更——http 配置从 YAML 迁到了 UI,写错位置会拖垮整个站点。

TL;DR

  • HA.dingdao.me / blog.dingdao.me 走 Cloudflare Tunnel 外网访问,源站分别是
    http://localhost:8123http://localhost:80(openresty),全程零入站端口。
  • 博客用 Hexo(Node 生成静态 HTML)+ openresty 托管,4G 内存的机器上零额外常驻。
  • 最大的坑不在隧道本身,而在 HA 的 http 配置位置:新 schema 校验导致
    http 组件启动失败,连锁拖垮几十个集成,所有带 X-Forwarded-For 的请求被拒 400。

一、拓扑

1
2
3
4
5
手机/外网 → Cloudflare Edge (blog/HA.dingdao.me)
→ cloudflared (VM 内 systemd 服务,出站 QUIC 连 CF 边缘)
→ ingress 规则(CF 后台配置,tunnel 拉取):
blog.dingdao.me → http://localhost:80 (openresty,Hexo 静态文件)
HA.dingdao.me → http://localhost:8123 (Home Assistant 容器)

cloudflared 用 token 认证跑在 systemd(cloudflared.service),ingress 规则存在
CF 后台,本地改 hostname 后约 10 秒内 tunnel 会拉取新配置(日志里能看到
Updated to new configuration version=N)——改完规则一定要看版本号变了再测,
之前测到 404 其实就是规则还没同步下来。

二、HA 的坑:http 配置搬家了

症状:HA 容器本地 8123 正常 200,外网经 tunnel 一律 400 Bad Request,
日志里刷:

1
2
3
ERROR [homeassistant.components.http.forwarded]
A request from a reverse proxy was received from 127.0.0.1,
but your HTTP integration is not set-up for reverse proxies

第一反应是”没配 trusted_proxies”,往 configuration.yaml 里加 http: 块——
结果更糟:整个 http 组件启动失败,连带 auth/onboarding/api 等几十个
集成全挂,错误是:

1
2
3
Invalid config for 'http': some but not all values in the same group of
inclusion 'proxy' 'http-><proxy>', got None
Invalid config for 'http': 'use_x_forwarded_for_header' is an invalid option

根因:HA 2026.8 起 http 配置从 configuration.yaml 迁移到 UI,
存进 .storage/http(JSON)。YAML 里残留的 http: 块走新 schema 校验,
单写 trusted_proxies 属于”部分填写必选项组”,直接判定无效配置。

正确做法:

  1. 删掉 configuration.yaml 里的 http: 块;

  2. .storage/httpstable 字段:

    1
    2
    "use_x_forwarded_for": true,
    "trusted_proxies": ["127.0.0.1/32"]
  3. 重启 HA。

注意:直接改 .storage/http 绕过了 UI 的”5 分钟确认窗口”,
HA 会在 UI 里挂一个 pending 状态等确认,建议之后进
设置 > 系统 > 网络 > HTTP 服务器 保存一次,否则可能被回滚。

三、Hexo + openresty 托管博客

4G 内存的机器不适合跑 WordPress/PHP 那套,Hexo 构建后是纯静态文件,
openresty 直接托管,运行期零额外内存占用:

1
2
3
4
5
6
cd ~/blog
npx hexo init . && npm install
npx hexo new "文章标题" # 在 source/_posts/ 下生成 md
npx hexo generate # 重新生成 public/
# 同步到 openresty(宿主 /opt/1panel 是 root 所有,经容器操作):
docker cp ~/blog/public 1Panel-openresty-hK6e:/www/blog-public

站点配置(openresty 容器内 conf/default/blog.dingdao.me.conf):

1
2
3
4
5
6
server {
listen 80;
server_name blog.dingdao.me;
root /www/blog-public;
location / { index index.html; try_files $uri $uri/ /index.html; }
}

改完 nginx -tnginx -s reload,外网即可访问。

四、踩坑清单(增量)

症状 解法
CF 后台刚改 ingress 就测 404 / 400,其实规则没生效 看 cloudflared 日志 Updated to new configuration version=N 再测
HA YAML 里加 http: 块(2026.8+) http 组件 setup 失败,全集成连锁挂 删 YAML 块,改 .storage/http
误以为 use_x_forwarded_for_header 是字段名 schema 校验报 invalid option 实际字段是 use_x_forwarded_for
openresty 容器内 404 页带 CF challenge script 以为 CF 在拦,实际是 nginx 的 404 兜底页 看响应体里 nginx 字样即可判断 404 来自源站

五、一句话总结

NAT 后的家用虚拟机,”被访问”只能靠服务主动出站的那根隧道;
而隧道通了之后,真正的坑往往在应用层——HA 配置搬家、规则同步延迟,
都藏在”看起来隧道没问题”的假象后面。


作者:小道 · 环境:kaliserver(Hyper-V / Ubuntu 26.04)· 2026-09-17
关联阅读:《我推翻了上一篇的一半结论:NAT 后的虚拟机对外提供服务,答案是 Cloudflare Tunnel》