N100 系统盘取证恢复与安全启动重构
#N100 #数据恢复 #Docker #systemd #ext4 #btrfs
背景与结论
N100 出现开机即卡死、反复重启并最终无法进入系统。原 128 GB NVMe 被取出,通过 Mac 做只读取证、镜像和文件系统恢复,再克隆到 256 GB NVMe。新盘已经成功从 N100 启动,SSH、系统盘和 Docker 基础能力均通过验证。
本轮能够确认的是:
-
原系统盘 ext4 存在由异常断电/硬重启留下的 journal、inode bitmap、free count 和 checksum 不一致;修复后连续两次只读检查干净。
-
原盘完整镜像和独立回读校验一致,
ddrescue未报告读错误或坏扇区。 -
新 256 GB NVMe 的系统分区和文件系统已扩容,当前根分区约 234 GiB。
-
旧启动链把 USB 外盘挂载和 Docker 放进主机启动关键路径,会放大外盘、USB 或文件系统异常的影响;现已解耦。
-
现有证据不能把唯一根因锁定为 Btrfs、Wi-Fi 或某个硬件部件。ext4 损坏是确定事实,但 USB/硬盘柜/供电等因素仍需观察。
旧方案与阶段性判断参见 《MyUbuntu 服务关机与启动流程》、《N100 安全事件响应:OpenClaw SSH 暴力破解与 fail2ban 加固》 和 《N100 网络重构与服务修复记录》。本文是后续取证后的当前基线。
一、镜像与校验链
原盘精确大小为 128035676160 字节。恢复前先生成原盘镜像,ddrescue 完成率 100%,未发现 read error 或 bad sector。可信镜像的完整 SHA-256 为:
1 | af736b6b1db2b5e86b06db9fcb962c6d0bf9c37e3c62e8cf1908b6152d71148d |
镜像还在健康的 Ventoy PSSD 上完成独立回读。随后将它恢复到 Samsung 256 GB NVMe,新盘原盘长度范围的 SHA-256 与镜像一致,因此克隆过程没有改变源数据。
旧 4 TB exFAT 盘也保存过临时副本,但 SMART 有以下历史风险指标:
| 指标 | 原始值 |
|---|---|
| Reallocated Sector Count | 32 |
| Current Pending Sector | 1 |
| Offline Uncorrectable | 30 |
| Multi-Zone Error | 24 |
| 历史 device errors | 107 |
该盘只适合存放可替代的影视等非关键数据,不作为唯一备份,也不作为镜像验收的唯一依据。坏道屏蔽只能绕开已发现区域,不能把老化盘恢复成健康盘。
二、ext4 恢复与新盘扩容
原系统分区只读检查发现 journal、inode/bitmap、空闲计数和 checksum 问题,符合多次硬重启留下的文件系统不一致。Mac 上直接对 raw device 修复在 superblock flag 阶段失败,改用缓冲设备 /dev/disk4s2 后成功完成。
恢复验收包括:
-
修复后连续两次只读
e2fsck均通过。 -
坏块检查未发现 bad block。
-
GPT 备份表移动到 256 GB 新盘末端,保留原分区 GUID、起始位置和已有数据。
-
N100 启动后扩展系统分区,并用
resize2fs扩展 ext4。
扩容后根分区约 234 GiB,已用约 97 GiB,可用约 127 GiB,使用率约 44%。
三、启动后的硬件与系统验证
当前系统为 Ubuntu 22.04.5,内核已更新到 6.8.0-136-generic。新 NVMe SMART 自检通过,media/data integrity errors 与 error log 均为 0;最终无盘启动验收时 NVMe 为 35°C、CPU 约 40–42°C。unsafe shutdowns 为 86,说明历史上确有大量非正常断电,但不能单独证明盘体故障。
本次启动日志未发现新的 NVMe、ext4、I/O 或 controller reset 错误。旧日志中只看到一条 USB Audio and HID 0573:1573 的 active URB timeout,它是 USB 链路排查线索,不足以单独定性。
系统已有 Wi-Fi 稳定性补丁:
-
关闭 Wi-Fi powersave;
-
rtw88关闭 deep LPS; -
rtw88关闭 ASPM。
补丁在当前系统正常加载,Wi-Fi 与 SSH 稳定。因此没有证据表明该补丁导致本次故障,也不能证明 Wi-Fi 就是原始根因。
四、Docker 数据与生产容器验证
生产 Docker 数据目录 /var/lib/docker 保留完整,识别到 14 个容器、16 个镜像,约占 12 GiB;容器并未丢失。所有生产容器的 restart policy 当前保持为 no,避免主机启动时抢跑。
先使用隔离的临时 data-root 验证 Docker 核心能力,以下项目全部通过:
-
overlayfs;
-
bind mount;
-
BusyBox 镜像拉取;
-
HTTP 容器完整生命周期。
随后对不依赖机械盘的生产容器进行受控测试:nginx-proxy、download-gate、qbit-executor、document-worker 均可启动,document-worker 健康检查通过。后两者在 10 秒停止窗口内以 137 退出,说明仍需优化优雅停机,不影响其“可启动”结论。
无盘最终重启后又复测了一次上述四个容器,结果仍通过,测试完成后所有容器、Docker 与 containerd 均恢复停机。只读盘点 14 个生产容器的实际 bind mount 后,依赖关系进一步明确:
| 数据层 | 容器 |
|---|---|
| 仅系统盘 | nginx-proxy、download-gate、qbit-executor、document-worker 等 |
/smb |
qbittorrent、media-acceptance、media-processor、openclaw |
/nfs |
mt-photos |
同时依赖 /smb 与 /nfs |
webdav |
依赖 /nfs 或 /smb 的 OpenClaw、qBittorrent、MT Photos 和 WebDAV 未在硬盘柜缺席时强行启动。
五、外盘现状与安全边界
两块约 2 TB 机械盘组成的是 Btrfs RAID1,不是 RAID0。完整只读检查后来报告:
1 | We have a space info key for a block group that doesn't exist |
当前未发现数据 checksum mismatch 的证据,但 free-space-tree/space-info 元数据存在不一致。完整备份完成前:
-
禁止执行
btrfs check --repair; -
禁止读写挂载;
-
禁止 scrub;
-
必要取证只允许
ro,rescue=nologreplay。
两块成员盘必须按 serial/WWN 识别,不依赖易变的 /dev/sdX 顺序。
六、安全启动重构
目标是确保系统盘、网络和 SSH 永远优先,外盘或 Docker 失败不得阻塞 multi-user.target。
已实施的宿主机改动:
-
/nfs、/smb从自动挂载改为noauto,nofail; -
Btrfs 默认只读并使用 rescue 选项;
-
未挂载目录设为
0555,防止容器把数据误写到系统盘同名空目录; -
禁用并停止
docker.service、docker.socket、containerd.service的开机自动启动; -
停止 NFS/Samba、qBittorrent 防火墙单元和旧的外盘相关 timer;
-
删除 Docker 对外盘 mount unit 的全局硬依赖。
Docker 保留有限失败重试,但不进入主机启动关键路径:
1 | [Unit] |
静态验收时系统为 running,failed unit 与 pending job 均为 0,关键启动图中已没有外盘或 Docker 阻塞链。变更前配置备份位于:
1 | /home/milin/server-backups/oc33-host-boot-decouple-20260806-133036 |
无盘重启发现的 Plymouth 竞态
解耦后的前两次正常重启都复现了另一个独立问题:SSH 和 GDM 已经可用,但 plymouth-quit-wait.service 一直执行 plymouth --wait,并行的 quit job 没有运行,systemd 因此永久停在 starting。这不是外盘或 Docker 阻塞。
最终使用 drop-in 让 wait 单元自身执行 plymouth quit,并设置 20 秒上限,消除无限等待。修复后的验证启动结果为:
1 | 17.896 秒到达 graphical.target |
该次启动中 SSH 正常,/nfs、/smb 均未挂载,Docker 和存储服务没有抢跑,也没有新的 ext4、NVMe I/O、USB reset 或外盘 device timeout。
为避免用一次成功代替长期稳定性结论,现已启用独立的系统盘观察 timer:启动 15 分钟后采样,此后每 6 小时记录 systemd 状态、挂载、NVMe SMART、温度和当前 boot 的存储错误到 /var/log/oc30-stability/。24–72 小时自然观察结束前,OC-30 仍保持进行中。
七、外盘串行恢复器
启动逻辑已经拆成互不阻塞的两条通道:
1 | 主机通道:系统盘 → local-fs → 网络 → SSH → multi-user |
每一阶段都必须满足:有界等待、失败即停止本分支、记录日志、不无限重试、不触发重启。Btrfs 在完成备份和治理前只读;4 TB 盘的 SMART 告警不得被自动化忽略。
串行恢复器和运行时掉盘 watchdog 已部署,但当前保持严格封锁:
1 | oc33-storage-recovery.service = static/inactive |
恢复器使用单一 flock,并依次执行身份、SMART、挂载、Docker 和容器分组门禁。掉盘 watchdog 会停止依赖丢失挂载点的容器。模拟测试已通过,但在硬盘柜到场、录入三盘精确身份并人工复核容器分组以前,它不会自动接触外盘。
Btrfs 治理完成前,NFS 和同时依赖两盘的服务分组保持为空,因此 MT Photos、WebDAV 和 NFS 写服务仍无法被恢复器启动。Syncthing 固定在最后阶段。
八、待完成事项
-
等待 24–72 小时定时快照,确认 NVMe、ext4、USB reset、温度和重启状态没有异常。
-
为当前可启动的 256 GB 系统盘生成新基线镜像,并完成两次独立回读 SHA-256 验收。
-
新基线验收前保留原盘和旧镜像,不做清理。
-
接回硬盘柜后记录每块盘的 serial/WWN,复核 SMART 门槛和容器分组,再手动放行恢复器。
-
先备份 Btrfs RAID1,再决定元数据治理方案;不要在唯一副本上 repair。
-
外盘稳定后再恢复 MT Photos、WebDAV、qBittorrent 和 OpenClaw,并逐组验证停机顺序。
-
新系统镜像和接盘验收都完成后,撤销临时管理授权并验证失效。
最终判断:系统已恢复到可启动、可远程维护、可继续验证的状态;启动架构也已从“外盘失败拖死主机”改为“主机优先、存储异步、服务显式放行”。根因调查仍保持开放,后续以无硬盘柜稳定性和逐盘接入结果收敛。
九、恢复链后续进展(2026-08-09)
后续恢复工作遵循单链串行:不把验证、迁移和服务恢复并发到同一块源盘上。已确认的新 4 TB staging 盘完成两次 SMART Long、全盘随机写读和冷回读验收;RAID1 数据副本的逐文件校验与冷回读也已通过。只读 scrub 实际完成且原始报告为无错误,期间出现的是脚本解析字段不兼容造成的假失败,未据此重复执行 scrub。
旧 4 TB 源盘仍保持严格只读。其实体复制已经完成,当前由独立恢复任务继续执行 checksum diff、源/目标 SHA 与目标冷回读;在这些证据完成前,不把旧盘视为可退役,也不删除其中数据。恢复期间 MT Photos 的必要容器已按受限顺序恢复,未恢复不依赖验证结果的高风险写入操作。
这意味着当前阶段从“系统盘无法启动”转为“旧介质数据迁移与可审计验收”。系统盘离线镜像、物理断柜/重连和最终重启验收仍需人工维护窗口,不能由常规任务自动触发。
十、独立 Rescue 载体静态验收(2026-08-10)
为避免“在线系统给自己做整盘镜像”的一致性风险,新增了一块独立 USB Rescue 载体。它使用 GPT、512 MiB FAT32 EFI 分区和 ext4 根分区,安装精简 Ubuntu Server、UEFI removable path、内核、GRUB、ddrescue、SMART 与 NVMe 工具。生产 256 GB Ubuntu 仍是永久默认启动项;本阶段没有修改生产 EFI、GRUB 或 systemd,也没有执行重启和真实系统盘镜像。
制作中宿主曾正常关机,导致 debootstrap 在 dpkg 事务中收到 SIGTERM。恢复时没有重新分区或格式化,而是先固定核对 USB serial、精确容量、稳定 by-id、USB 拓扑、GPT/PARTUUID/文件系统 UUID,再从保全的 status-old 和 220 个 dpkg journal 更新恢复包状态。直接重放 debootstrap --second-stage 会重复写入 dpkg stanza,因此最终改为从现有缓存包执行 unpack/configure。所有挂载均放在 private mount namespace,宿主 PID 1 namespace 没有出现 Rescue 盘挂载。
静态验收结果全部通过:
-
FAT32 与 ext4 的只读 fsck 均返回成功,ext4 为 0 bad block;
-
EFI/BOOT/BOOTX64.EFI、GRUB、内核和 initramfs 均存在; -
fstab只引用 Rescue 自身固定 UUID; -
冻结依赖、包 manifest、运行器、service 和 build manifest 的 SHA-256 全部一致;
-
oc38-rescue.service已启用,但没有请求 marker 时保持惰性; -
制作前后的
efibootmgr -v快照逐字节一致; -
清理后无构建进程、无宿主挂载传播,10 秒 Rescue 盘 I/O 增量为 0。
后续自动化仍是单独授权阶段:生产侧完成 UPS、磁盘身份、SMART、容量和服务排空门禁后,只设置一次性 BootNext 或 grub-reboot;Rescue 启动后要求源 NVMe 完全未挂载,再执行 ddrescue map 100%、源 SHA 等于镜像 SHA、flush/重新枚举后的第二次镜像 SHA。每个 run 只尝试一次,成功或失败都回生产默认项;新镜像全绿以前不删除旧可信镜像,前两次真实全链必须人工监护。
静态验收后的内容完整性更正
上述静态验收只能证明分区、文件系统结构、启动文件和冻结清单自洽,不能证明每个包管理文件的语义内容都正确。后续 A2 网络准备在执行任何写入前安全停止:dpkg 读取 triggers/File 时发现二进制垃圾并返回 rc=100。扩大只读检查后,/var/lib/dpkg/info 的 865 个文件中有 130 个被识别为二进制异常,涉及 maintainer script、list、md5sums、shlibs、symbols、conffiles 和 triggers;抽样文件连续两次 SHA 稳定,说明它们是已经落盘的内容损坏,而不是一次瞬时读取错误。
因此 Rescue 当前状态更正为:禁止启动、禁止逐文件猜修、禁止设置 BootNext。所有私有挂载均已卸载,宿主 PID 1 没有挂载传播;没有停生产服务、修改 EFI 或触碰生产数据盘。后续必须先做限额冷回读介质测试,通过后再选择整体重建根分区内容或明确重新格式化,不能把“fsck 全绿”误写成“Rescue 可投入使用”。
十一、生产存储角色完成切换(2026-08-10)
健康的新 4 TB 盘已经从临时 staging 升级为正式生产存储:其 ext4 HOMELAB_STAGING 保持挂载在 /staging,经过身份、SMART、空间和冷回读门禁后,以受控 bind mount 向 /smb 提供读写数据。恢复器持续保留至少 300 GiB 空间余量门槛,并由掉盘 watchdog 监控真实挂载源,避免容器在卷缺失时把数据写进系统盘上的空目录。
两块 2 TB Btrfs RAID1 成员已经完成:
-
独立展开备份与逐文件 SHA;
-
只读取证、数据 checksum 检查和拓扑证据;
-
原始报告全绿的 scrub;
-
证据冷回读与
no-action-clean-baseline治理登记; -
独立临时目录写入、同步、SHA 回读和删除探针。
治理结论不是“执行过修复”,而是现状检查没有复现旧 free-space-tree 签名,因此没有执行 Phase C、btrfs check --repair、balance 或重建。RAID1 现以读写方式提供 /nfs,两个成员的 device stats 均为 0。
Samba、NFS、Docker 和 13 个已启用的业务容器已恢复。只读服务验收中,无认证端点 8/8 返回 HTTP 200,OpenClaw、document-worker 和 Syncthing 的健康状态正常,slot4 SMART 全绿。Hermes 尚未启用,因此不计入失败。OpenClaw 的静态配置和已保存 session 仍指向既定本地模型,但本轮没有发送真实推理请求,不能把配置检查替代为模型路由验收。
旧 slot5 盘不再承载 /smb,也不再是媒体、下载或其它上层任务的前置条件。它只允许作为可丢失缓存盘进行独立温控整备;其成功、失败、过热暂停或物理掉线都不得影响 /smb、/nfs、宿主启动和生产容器。该盘已有介质风险与散热不足,禁止迁回生产角色。
十二、旧 4 TB 盘破坏性测试与退役(2026-08-11)
数据安全迁出后,旧 4 TB 盘被放入独立硬盘盒,按“可丢失下载缓存盘”标准执行破坏性整备。全盘零写完成后,回读阶段通过宿主本地 timer 做温控闭环:连续达到 55°C 时冻结测试进程并停转,降至 45°C 后从同一 PID 和 I/O 位置继续;60°C 或任何 SMART、身份、USB/I/O、生产挂载门禁异常都会停止且不重试。
测试在回读约 1.46 TB(约 36.4%)时终止:
| 指标 | 测试前 | 终止时 |
|---|---|---|
| Reallocated Sector Count | 34 | 36 |
| Current Pending Sector | 0 | 1 |
| Offline Uncorrectable | 30 | 30 |
| UDMA CRC Error Count | 0 | 0 |
badblocks 当时仍显示 0/0/0,输出坏块文件也为空,但这不能覆盖 SMART 的底层证据:固件可能已在主机收到最终成功结果前执行重试或重映射,而且持续读取仍产生了新的待定扇区。已知坏块列表只能绕开当前发现的位置,无法预测继续扩散的新坏区,也无法保证访问坏区时不会因固件重试拖慢 I/O 队列。因此该盘不再格式化、不运行 SMART Long,也不再作为下载缓存使用,最终退役。
收尾时已终止测试进程,将旧盘整盘和分区恢复为 block-RO 并停转;其专用 systemd unit、温控 timer、脚本、日志和运行状态均已删除。OC33 的运行与重启验收门禁也移除了该退役盘,只要求两块 RAID1 成员和新 4 TB 生产盘。
slot4 上约 476 GB 的 RAID1 展开副本在确认双成员读写正常、治理证据完整且 device stats 全为 0 后删除;治理 manifests 保留,生产 /smb 数据未动。slot4 可用空间由约 962 GB 增至约 1.5 TB。旧盘物理移除不会影响宿主启动、/smb、/nfs 或生产容器。
十三、仍未完成的最终门禁
-
OC-33 仍需完成接柜、无柜、再次接柜的完整重启状态机验收,证明任一外盘缺失都不会阻塞系统、网络和 SSH。
-
256 GB 系统盘的新离线镜像仍未完成;Rescue 介质修复或重建前,不得用它触发自动镜像。
-
临时免密管理权限只能在最终重启、服务和回退验收全部通过后撤销。
-
联网 UPS
192.168.2.8已为硬盘柜和 N100 供电;品牌、型号、额定容量、管理协议、自动关机联动和实测续航仍需另行记录与验收。
