Linux 故障恢复练习:用日志、端口与 HTTP 验证恢复
故障恢复练习应在隔离环境中先验证正常基线,再只改变一个条件,根据观察到的证据恢复它。判断恢复完成时,要同时检查服务状态和用户实际收到的响应。
开始前准备虚拟机快照与控制台恢复(英语),并按日志排障步骤比较变更前后的证据。
参考环境为常规安装的 Ubuntu 26.04 LTS 或 Rocky Linux 9 系列虚拟机。容器、Windows Subsystem for Linux(WSL)和其他版本的服务、软件包配置可能不同,先核对版本和恢复入口。
明确隔离范围并建立正常基线
使用具有 systemd 用户管理器、Python 3 和 curl 的实验虚拟机。练习只操作本次创建的用户服务和文件,不修改生产 Nginx、SSH、防火墙或磁盘配置。用 ss -lnt 确认回环地址 127.0.0.1 的 18080 端口可用;若已占用,应把本练习所有对应端口统一换成另一个空闲端口。
先用 command -v python3 确认实际可执行文件路径。示例使用 /usr/bin/python3;若本机不同,应同时修改 ExecStart 及后续 sed 要匹配的原路径。若已存在同名服务或 ~/linux-recovery-lab,不要覆盖,应统一更换实验名称和相关路径。
Python http.server 简易 HTTP 服务器仅供本地练习,绑定回环地址,不用作互联网生产服务器。以下命令应逐条执行并检查结果;预期的失败也要记录后再进入恢复步骤,不要直接当作遇错即停的批处理脚本运行。
mkdir -p "$HOME/linux-recovery-lab/site" "$HOME/.config/systemd/user"
printf "recovery baseline\n" > "$HOME/linux-recovery-lab/site/index.html"
cat > "$HOME/.config/systemd/user/linux-course-recovery.service" <<'EOF'
[Unit]
Description=Isolated Linux recovery lab
[Service]
Type=simple
WorkingDirectory=%h/linux-recovery-lab/site
ExecStart=/usr/bin/python3 -m http.server 18080 --bind 127.0.0.1
EOF
systemctl --user daemon-reload
systemctl --user start linux-course-recovery.service
systemctl --user is-active linux-course-recovery.service
curl --fail --max-time 5 http://127.0.0.1:18080/
cp "$HOME/.config/systemd/user/linux-course-recovery.service" "$HOME/linux-recovery-lab/service.good"
确认状态为 active,且页面正文为 recovery baseline,再保存和核对 service.good 正常副本,之后才引入故障。这里只 start,没有 enable,因此未增加开机自动启动。基线不成立时,先排查 Python 路径、单元配置和端口冲突。
Type=simple 的启动命令返回,不等于应用已准备好接收请求。若初次请求恰逢启动过程,先确认状态和日志,再短暂等待后重试同一 URL;不要把尚未就绪立即归为另一种故障。核对客户端代理设置,避免把代理响应当成本机服务响应。
实验一:只修改可执行文件路径
sed -i 's@ExecStart=/usr/bin/python3 @ExecStart=/nonexistent/course-python @' "$HOME/.config/systemd/user/linux-course-recovery.service"
systemctl --user daemon-reload
systemctl --user restart linux-course-recovery.service
systemctl --user status linux-course-recovery.service --no-pager
journalctl --user -u linux-course-recovery.service --since "5 minutes ago" --no-pager
单元现在指向不存在的程序,服务无法保持活动状态。先检查 sed 确实修改了 ExecStart;路径未匹配就不能认为故障已注入。受执行时序影响,可能在启动命令中立即看到失败,也可能稍后才由 status 显示。
在日志中找出执行失败及 203/EXEC 状态等线索,记录实际消息。203 表示进程执行失败,并非只代表“网络连接失败”;应结合路径和系统错误解释。五分钟窗口可能包含前几轮练习,须按本次修改时刻对照。
恢复正常配置并重新验证响应
cp "$HOME/linux-recovery-lab/service.good" "$HOME/.config/systemd/user/linux-course-recovery.service"
systemctl --user daemon-reload
systemctl --user reset-failed linux-course-recovery.service
systemctl --user start linux-course-recovery.service
systemctl --user is-active linux-course-recovery.service
curl --fail --max-time 5 http://127.0.0.1:18080/
恢复已验证的单元文件,让管理器重新读取,再启动服务。reset-failed 可重置失败状态及启动限制计数,但不会修复错误配置,也不是删除 journal 历史记录的命令。只有活动状态与预期页面都恢复,才算完成本轮恢复。
实验二:区分端口关闭和 HTTP 错误
curl -i --max-time 5 http://127.0.0.1:18080/missing-resource
systemctl --user stop linux-course-recovery.service
curl -i --connect-timeout 2 --max-time 5 http://127.0.0.1:18080/
ss -lnt
systemctl --user start linux-course-recovery.service
curl --fail --max-time 5 http://127.0.0.1:18080/
第一次请求由正在运行的服务器返回 HTTP 404,说明连接已建立,但该资源不存在。停止服务后的请求则在连接阶段失败,常见表现是连接被拒绝;这与收到正常格式的 HTTP 404 响应不同。
比较 curl 带与不带 --fail 的退出状态:普通 404 传输可能返回 0,使用 --fail 时,HTTP 400 及以上响应通常使 curl 返回 22。连接错误有自己的非零退出状态。通过这种对照,可以练习区分服务、传输和 HTTP 层,而无需关闭远程防火墙。
每次只改一个条件并保存记录
| 记录项 | 本练习应保留的证据 |
|---|---|
| 正常基线 | active 状态、监听端口、预期页面 |
| 变更 | 只改 ExecStart 路径,或只停止服务 |
| 证据 | 时间、退出状态、journal、HTTP、套接字 |
| 恢复措施 | 恢复正常文件,或重新启动服务 |
| 复验 | 相同 URL、端口及预期正文 |
| 预防复发 | 部署前检查语法和路径,并进行状态检查 |
此阶段不要通过填满系统盘、阻断管理 SSH 或随机删除文件制造故障。更具破坏性的实验,应另用克隆虚拟机、容量受限的虚拟磁盘,以及已经验证的控制台和备份,并先界定范围。练习的目标是掌握从观察到恢复的判断过程。
停止实验服务并仅移除本次单元
systemctl --user stop linux-course-recovery.service
systemctl --user reset-failed linux-course-recovery.service
rm -- "$HOME/.config/systemd/user/linux-course-recovery.service"
systemctl --user daemon-reload
ss -lnt
确认回环地址上的 18080 监听已消失。工作目录中仍有正常配置副本和静态页面,检查内容后再单独清理。失败状态操作只针对本次实验单元,不清空其他用户服务的记录。




