HAOS 升级与回滚实战:6 步安全升级 + 3 个失败事故复盘
HA 跑稳之后,最让人紧张的操作不是装第一个 addon,是升级。装完 HA 第一个月你会觉得一切尽在掌握,第二个月开始写第一个自动化,第三个月家里加了 5 个智能设备、10 条自动化、2 个摄像头——这时候某次 OTA 卡 99%、或者升级后 MQTT 断连、或者addon 集体崩溃,就是从"玩玩具"到"真运维"的分水岭。
我在 J4125 上跑 HAOS 快两年了,累计升级 12 次以上,其中 3 次翻车,最严重的一次直接让我凌晨爬起来刷 NVMe。这篇文章就是把这 3 次事故踩出来的东西系统总结:6 步升级前检查 + 3 个真实事故复盘 + 回滚决策树。
顺带说一下 HAOS vs HA Container 的升级差异:HAOS 是整台机器升级(系统 + Supervisor + HA Core 一起动),失败就整台重来;Container 只升级 HA Core 那个容器,数据卷不动,回退成本低。这不是说 Container 更安全,而是失败模式不同——Container 挂了你大概率不用刷盘,HAOS 挂了你基本要进 Recovery 模式。
一、为什么要专门讲升级
HAOS 的升级模型跟 Android OTA 很像:下载固件 → 校验 → 写到 A/B 分区之一 → 下次启动走新分区。听起来很安全,实际有几个坑:
- A/B 分区写入会耗光 SD 卡写寿命——树莓派用户 6 个月就 SD 变砖的概率不低
- Recovery 模式是唯一救火入口——一旦当前分区损坏,进不了 HA 就要进 Recovery 刷机
- 升级过程 HA 完全不可用——所有自动化、传感器、MQTT 断连,家庭场景下门锁和摄像头也会一起断
- HAOS 不支持"回退到上一个版本"——只有"重新刷",没有"回滚"
Container 部署就没这些限制:docker pull 换镜像、docker run 起来、不行删掉重来,数据卷 /config 一直挂载不动。代价是你要自己管 Supervisor、管 addon、管 HAOS 层面的东西(比如 NTP、防火墙)。
所以选完部署模式,升级流程是不一样的。下面所有流程默认 HAOS,最后单独讲 Container。
二、升级前 6 步检查清单
这是我最重要的一张 checklist,每次升级我会截图保存到运维笔记本。跳过任何一步都是赌博。
Step 1: 全量备份
不是"点一下 Supervisor 备份"就完事,要三层:
1. Supervisor UI 备份(Settings → System → Backups)
- 勾选 Database + 所有 addon + 配置
- 加密,密钥抄在纸上放抽屉
- 下载到本机一份
2. 数据库单独备份 addon(Database Backup)
- 单独生成 state.json 压缩包
- 用 rsync 或 sftp 拉到 NAS
3. /data 目录手工备份(SSH 进去)
ssh [email protected]
tar -czf /data/ha-full-$(date +%Y%m%d).tar.gz \
--exclude='/data/rfstack' \
/usr /etc /root /home
第一层是官方机制,第二层是"以防万一",第三层是"以防万一的以防万一"。J4125 有 256GB NVMe,备份随便打;树莓派 32GB 卡就要精打细算。
Step 2: 分区空间检查
df -h
Filesystem Size Used Avail Use% Mounted on
/dev/disk/by-label/ROOT 22G 14G 6.2G 69% /
/dev/disk/by-label/HOMASS 918M 342M 575M 38% /homeassistant
/dev/disk/by-label/DATA 22G 8.4G 12G 42% /data
门槛:根分区剩余 < 20% 就别升级。OTA 下载固件本身就 200-300MB,写入 A/B 分区时还要预留临时空间。低于 20% 会直接触发事故 3(下面会讲)。
清理策略:
- /data/rfstack 可以清空(Zigbee 会重扫)
- docker system prune -af 清 addon 缓存(先停 addon)
- /data/log 下的旧日志删掉
Step 3: Addon 版本兼容性检查
进 Settings → Add-ons,把每个 addon 的 Changelog 翻一遍。特别关注:
- 官方 addon(HA Supervisor、Database Backup、Network Utility、Studio Code Server)——一般 48h 内跟进
- 社区 addon(Mosquitto、Mosquitto Logger、File Editor、Nginx Proxy Manager、Node-RED、ESPHome)——跟 HA 版本发布节奏对齐
- AppDaemon / HACS / MaterialUI——最容易落后
一个 addon 版本落后,HA 启动时不会崩,但升级后可能因为 Python 库版本问题起不来。升级前把 addon 全部升到最新,比升级后挨个救简单得多。
Step 4: DNS 与 NTP 检查
# 检查 DNS
nslookup cloud.homeassistant.io
# 应该返回真实 IP,不是 0.0.0.0 或超时
# 检查 NTP
timedatectl
Local time: Mon 2026-10-26 03:12:44 CST
Universal time: Sun 2026-10-25 19:12:44 UTC
Time zone: Asia/Shanghai (CST, +0800)
NTP service: active
DNS 不对会导致 OTA 下载失败,NTP 不对会导致证书校验失败。家庭路由器里如果启用了 DNS 广告过滤(如 Pi-hole),记得把 *.homeassistant.io 加白名单。
Step 5: 网络可达性检查
在升级前用 SSH 或 Network Utility addon 测一下这几个端点:
# HA Cloud
curl -I https://cloud.homeassistant.io
# GitHub(HACS、addon 更新都会用)
curl -I https://github.com
# MQTT Broker(如果自建)
mosquitto_sub -h mqtt.local -p 1883 -t '#' -C 1 -v
# Zigbee 协调器
ping -c 3 zigbee.local
任何一个不通,先修网络再升级。升级过程中 HA 会主动拉新固件,网络抖动 = 卡 99%。
Step 6: 记录当前版本与依赖状态
版本快照(升级前):
- HAOS: 12.4
- HA Core: 2024.11.2
- Supervisor: 2024.11.1
- Hostname: ha.local
- 硬件: J4125 + NVMe 256GB
- 依赖服务:
* MQTT: broker 在 192.168.1.50,正常运行
* Zigbee: ZHA + ConBee II,22 个设备
* 摄像头: 4 台 ONVIF,走本地 NAS 存储
* 自动化: 47 条,其中 3 条依赖 Zigbee
* 定时任务: 4 个(备份、镜像、日志清理)
这份记录的作用是——升级失败时,你能精确对比"升级前 OK 的项目"和"升级后异常的项目"。
三、OTA 升级流程深度
方式一:Web UI(推荐家用)
- Settings → System → 右上角菜单 → Check for updates
- 如果有更新,显示
New version available: 2025.1.0 - 点
Restart and install→ HA 关闭 → 下载固件 → 写分区 → 重启 - 全程不需要人工干预,UI 变灰,浏览器页面会挂
方式二:REST API(推荐给团队批量部署)
TOKEN=eyJhbGciOiJIUzI1NiIs... # 从配置 → 安全 → 长期访问令牌生成
# 触发升级
curl -X POST https://ha.local:8123/api/supervisor/core/update \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# 查询状态
curl https://ha.local:8123/api/supervisor/core/info \
-H "Authorization: Bearer $TOKEN" | jq
方式三:SSH + 命令(推荐给远程运维)
ssh [email protected]
# 触发下载
sudo systemctl stop homeassistant
supervisor-core update
# 或者直接调 Supervisor API
curl -X POST http://localhost:8080/supervisor/core/update
四、HAOS vs Container 升级对比
| 维度 | HAOS | Container |
|---|---|---|
| 升级粒度 | HAOS + Supervisor + HA Core 一起 | 只升 HA Core |
| 升级方式 | Web UI / OTA | docker pull + docker run |
| 时长 | 5-15 分钟 | 1-3 分钟 |
| 失败模式 | 可能 A/B 分区损坏,进 Recovery | 容器起不来,删掉重来 |
| 回滚 | 只能重新刷固件 | 改 tag 重启容器 |
| 数据保存 | /data 目录不动 |
/config 挂载不动 |
| 升级期间 HA 可用 | 否 | 可以停容器期间短断 |
| 适用场景 | 家庭用户、单机部署 | 有 Docker 经验的用户、服务器部署 |
五、Addon 升级顺序
升级 HA Core 之后,addon 要按依赖顺序逐个升:
- 基础设施 addon(先升)
- Docker Compose Manager、Network Utility、SSH
-
这些是"工具型",升完不影响业务
-
中间件 addon(次之)
- Mosquitto Broker(MQTT)
- Mosquitto Explorer
- NGINX Proxy Manager
-
这些是通信层,升级时 MQTT 会短暂断连
-
协议集成 addon(最后)
- ZHA / Zigbee2MQTT
- ESPHome
- Tasmota
-
这些依赖 MQTT,MQTT 先稳了再动它们
-
应用层 addon(最后)
- AppDaemon
- Node-RED
- Home Assistant Companion 后端
- HACS
踩坑:如果我反过来先升 AppDaemon,Python 版本升级会让 AppDaemon 找不到老版本的第三方库,得重装。
六、事故 1:OTA 卡在 99%
现象
2024 年 8 月某日凌晨,我按流程升级 HAOS 12.1 → 12.2。UI 显示:
卡了 20 分钟。J4125 主板的指示灯还在闪,说明机器没死,HA 进程已经没了。
定位
用另一台设备 SSH 进来:
ssh [email protected]
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1 0 255.9G 0 disk
├─nvme0n1p1 0 128M 0 part
├─nvme0n1p2 0 22G 0 part
├─nvme0n1p3 0 22G 0 part
└─nvme0n1p4 0 211.4G 0 part /data
nvme0n1p2 是旧分区,nvme0n1p3 是新分区,写入过程中磁盘 IO 完全卡死。dmesg 里有:
nvme nvme0: I/O 1024 QID 0 timeout
nvme nvme0: I/O 1024 QID 0 timeout, aborting
nvme nvme0: I/O 1024 QID 0 completed, result: 0x401
典型的 NVMe 控制器挂死。原因:J4125 主板用的是板载 NVMe 走 PCIe 通道,某些固件版本写入分区时 DMA 会跟系统其它进程打架。
恢复
- 直接断电(拔电 5 秒)
- 短接 Recovery 引脚(J4125 主板有 RECOVERY 针脚,短接后接电源)
- 电脑 USB 识别到
RECOVERY分区 - 挂载 Recovery 分区,删掉损坏的 A/B 分区标志
- 用 Home Assistant OS image + Rufus 重刷 NVMe
- 启动 → 恢复备份
全程 40 分钟。因为备份在 NAS 上,恢复自动化和集成一次搞定。
教训:J4125 用户如果遇到卡 99%,先查 NVMe 型号(三星 970/980 有已知 bug),换三星 970 Pro 或西数 SN750 稳定。
七、事故 2:addon 不兼容崩溃
现象
2025 年 2 月升级到 HA 2025.2.0 后,Zigbee2MQTT addon 起不来。日志:
[19:24:13] INFO: [main] Starting Zigbee2MQTT version 1.34.0
[19:24:15] ERROR: [main] Failed to start Zigbee2MQTT
[19:24:15] ERROR: [main] TypeError: Cannot read properties of undefined (reading 'permit_join')
[19:24:15] ERROR: [main] at Coordinator.start (/app/index.js:142:34)
定位
在 HA UI 打开 Zigbee2MQTT addon,右下角 Configuration 面板显示红字:
翻 Changelog:
v5.1.0 (2025.1.2) ← 我装的
- Fixed coordinator discovery
v5.2.0 (2025.2.1) ← 应该升到这里
- Fixed compatibility with HA Core 2025.2
恢复
单独升级 Zigbee2MQTT addon 到 v5.2.0,重启,OK。
通用排查步骤:
# 看 supervisor 日志
journalctl -u supervisor -n 100
# 看具体 addon 日志
docker logs addon_config_zigbee2mqtt --tail 200
# 看 HA Core 日志
journalctl -u homeassistant -n 100 | grep -i error
90% 的 addon 报错都是addon 版本落后于 HA Core,跟 HA 本身无关。剩下 10% 是 addon 作者 bug,只能等新版。
八、事故 3:分区空间不足
现象
2024 年 11 月升级 HAOS 12.3 → 12.4,UI 直接报红:
定位
96% 使用率,直接卡死升级入口。
排查
升级前的分区分布:
du -sh /data/* | sort -h
4.2G /data/media # 音乐/视频缓存
3.8G /data/docker # addon 镜像层
1.6G /data/log # 日志
1.2G /data/supervisor # HA 数据
800M /data/rfstack # Zigbee 缓存
500M /data/media # 其他
清理策略
按风险从低到高:
# 1. 清理 addon 镜像层(先停所有 addon)
ha supervisor addons list > /tmp/addons.txt
for a in $(cat /tmp/addons.txt | awk '{print $1}'); do
ha supervisor addons stop $a
done
docker system prune -af --volumes
# 2. 清理旧日志
find /data/log -name "*.log" -mtime +30 -delete
# 3. 清理 rfstack(会重扫 Zigbee 设备)
rm -rf /data/rfstack/*
# 4. 清理 media 缓存(如果没本地媒体需求)
rm -rf /data/media/cache/*
清理后:
从 96% 降到 71%,可以升级。
长期方案
- 定期清理:cron 每周日 3 点执行
docker system prune - 备份策略:保留 7 天历史备份,超过 7 天的移到 NAS
- 大文件别放
/data/media——那分区跟系统共享,一满全灭
九、回滚决策树
升级翻车了怎么办?按顺序问自己 4 个问题:
问题 1: HA 还能进 Web UI 吗?
├─ 能 → 问题 2
└─ 不能 → 进 Recovery 模式刷盘
问题 2: HA Core 版本是否可降级?
├─ Container 部署 → 直接改 docker tag 重来
└─ HAOS 部署 → 问题 3
问题 3: 是 addon 崩溃还是 HA Core 崩溃?
├─ addon 崩溃 → 单独重装 addon,不用回滚 HA
└─ HA Core 崩溃 → 问题 4
问题 4: 分区完整吗?
├─ df -h 正常 → 用旧版本固件重新刷
└─ 分区损坏 → Recovery 模式 + Factory reset
HAOS 回滚流程
- 从 home-assistant.io/download 下载旧版本镜像
- Rufus 写镜像到 SD 卡或 NVMe 启动盘
- 短接 Recovery 引脚启动
- 挂载旧系统,
/data分区保留(自动化和配置还在) - 从 Recovery UI 里选 "Install latest version" 走新固件,或手动挂载旧分区
关键点:/data 分区不动,重装系统不会丢配置。
Container 回滚流程
# 拉取旧版本
docker pull homeassistant/home-assistant:2025.1.2
# 停止当前容器
docker stop homeassistant
# 删除当前容器(不删数据卷)
docker rm homeassistant
# 用旧镜像重新创建
docker run -d --name homeassistant \
-e TZ=Asia/Shanghai \
-v /mnt/user/backup/ha-config:/config \
--restart unless-stopped \
homeassistant/home-assistant:2025.1.2
10 秒钟完成,数据全在。这就是 Container 部署的杀手锏。
十、升级后冒烟测试
升级完别急着关掉浏览器,5 项必测:
1. 登录测试
用管理员账号登录,看能否正常进入 Dashboard。登不上说明 Supervisor 或 HA Core 都没起来,直接进 recovery。
2. API 测试
curl https://ha.local:8123/api/ -H "Authorization: Bearer $TOKEN"
# 应该返回 {"message": "API running."}
返回 401 是 token 问题,返回 502 是 Supervisor 挂了。
3. 自动化测试
挑 3 条关键自动化:
- 一条基于时日的(比如"早上 7 点开灯")——触发时间检查
- 一条基于状态变化的(比如"门窗打开触发")——事件总线检查
- 一条基于 MQTT 的(比如"设备离线告警")——MQTT 检查
用 Developer Tools → Automations 手动触发,看执行日志。
4. MQTT 测试
# 订阅所有消息
mosquitto_sub -h mqtt.local -p 1883 -t '#' -v
# 发布测试消息
mosquitto_pub -h mqtt.local -p 1883 -t 'test/ping' -m 'hello'
发布后订阅端能收到 test/ping hello,MQTT 链路正常。
5. 传感器测试
在 Developer Tools → States 里随便挑 3 个传感器:
- 温湿度传感器(本地协议)
- 智能插座(MQTT 上报)
- Zigbee 设备(ZHA/Z2M 上报)
每个都能显示数值、更新时间在 5 分钟内,OK。
5 项全过才敢关掉浏览器。任何一项挂了就按上面的排查流程走。
十一、FAQ
Q1: HAOS 升级卡 99% 不动了怎么办?
99% 是 OTA 下载完后正在写分区。这时候千万别急着重启——重启可能让新分区写到一半,进 Recovery 也救不回。
正确姿势: 1. 等 5 分钟,看进度条有没有动 2. 不动就断电(拔电 5 秒),然后重新插电 3. 短接 Recovery 引脚,进 Recovery UI 4. 选 "Factory reset and install latest version" 5. Recovery 完事,登录 HA,从 NAS 备份恢复配置
不会变砖,只是回到出厂状态。因为备份完整,恢复 20 分钟能搞定。
Q2: 升级后 addon 报错怎么办?
先别慌,看报错原文:
incompatible with HA version→ addon 版本落后,单独升 addonTypeError: Cannot read properties of undefined→ addon 代码 bug,等新版ModuleNotFoundError: No module named 'xxx'→ Python 库升级,pip install补一下Failed to bind to port 1883→ 端口冲突,改端口或停冲突服务
90% 的报错是 addon 版本落后,先单 addon 升级重试。如果 addon 本身有 bug(比如 Changelog 明写 "not tested with 2025.2"),回退 HA 版本。
Q3: HAOS 能回滚到上一个版本吗?
不能直接回滚。HAOS 每次升级都会格式化一个分区,另一个分区保留旧版,但系统只认当前分区。想回退,只能重新刷回旧版本固件:
- 下载旧版本镜像(比如 12.3)
- Rufus + dd 刷到 SD 卡或 NVMe
- Recovery 模式启动
- Factory reset + Install
所以升级前必须做全量备份。这也是为什么 Container 部署更适合爱折腾的用户——回退 10 秒钟。
Q4: HA Container 怎么升级?
# 1. 拉新镜像
docker pull homeassistant/home-assistant:latest
# 2. 停止当前容器
docker stop homeassistant
# 3. 删除当前容器(不删数据卷)
docker rm homeassistant
# 4. 用新镜像重新创建
docker run -d \
--name homeassistant \
--net host \
-e TZ=Asia/Shanghai \
-e NODE_TLS_REJECT_UNAUTHORIZED=0 \
-v /mnt/user/backup/ha-config:/config \
-v /etc/localtime:/etc/localtime:ro \
--privileged \
--restart unless-stopped \
homeassistant/home-assistant:latest
数据卷挂载 /mnt/user/backup/ha-config 不会丢。整个过程 HA 只断 30 秒左右。
Container 有个额外好处:可以同时跑两个版本。比如:
docker run -d --name ha-test \
-v /mnt/user/backup/ha-config:/config:ro \
-p 8124:8123 \
homeassistant/home-assistant:latest
新版本跑在 8124 端口,先在测试账号下验证,稳定了再切主容器。
Q5: 升级要多久?
取决于网络速度与硬件:
| 硬件 | 网络 | 时长 |
|---|---|---|
| J4125 + NVMe | 有线千兆 | 3-5 分钟 |
| J4125 + SATA SSD | 有线千兆 | 4-6 分钟 |
| 树莓派 4 + SD 卡 | WiFi | 8-15 分钟 |
| 树莓派 4 + NVMe HAT | WiFi | 5-8 分钟 |
| 树莓派 5 + NVMe | WiFi | 4-7 分钟 |
升级期间 HA 完全不可用——所有自动化、传感器、门锁、摄像头会一起断。建议:
- 凌晨 2-5 点执行(家里没人、自动化不会触发)
- 提前通知智能家居设备用户(如果团队多人)
- 保留 SSH 通道,UI 挂了还能进来排查
我在 J4125 上跑 HAOS 两年多的经验总结:升级不是玄学,是有 checklist 的运维操作。照着 6 步走 + 5 项冒烟测试,翻车概率能从 30% 降到 5% 以下。剩下的 5% 就是硬件故障,备份救你。