从备份到满血复原:Docker 服务 + 反向代理 + 密钥 的备份与灾难恢复 SOP
目标:当服务器故障/误删/迁移时,能按步骤快速恢复:博客、RSS 聚合、密码库、文件同步、状态监控、导航页等。
范围:以 Docker + Compose 部署、Nginx 反向代理 + HTTPS 出网的通用栈为例。
脱敏说明:文中使用占位符(如 SERVER_IP、app.example.com、/srv/app),不包含你的真实 IP/域名/口令。
【实操教学】
一、备份策略设计(先定“备什么、在哪、多久一次”)
1)分层备份清单(最重要放最上)
-
密钥与账号
-
本机 SSH 私钥(例如 ~/.ssh/id_ed25519)→ 用加密压缩备份
-
服务器 admin 用户 与 sudoers 片段(/etc/sudoers.d/90-admin)
-
-
反向代理与证书
-
Nginx 站点配置(或面板导出的反代配置)
-
HTTPS 证书(Let’s Encrypt 可重签;也可一并备)
-
-
Compose 项目与持久化数据
-
docker-compose.yml、.env、自定义脚本
-
数据卷/挂载目录(下表给出示例路径)
-
|
服务 |
必备数据目录(示例) |
说明 |
|---|---|---|
|
WordPress |
/srv/wordpress/html + 数据库备份 |
网站文件与数据库都要有 |
|
FreshRSS |
/srv/rss_stack/freshrss_data/ |
订阅、用户、配置 |
|
RSSHub |
可选(多为无状态) |
如有自定义路由/配置则备 |
|
Vaultwarden |
/srv/vaultwarden/data/ |
核心数据,必须备 |
|
Syncthing |
/srv/syncthing/config/ + 各资料库路径 |
配置 + 你要同步的文件 |
|
Uptime Kuma |
/srv/uptime-kuma/data/ |
监控项与通知通道 |
|
Homer |
/srv/homer/assets/ |
config.yml + custom.css |
说明:路径只作示例——你可以把所有项目统一放到 /srv/<project> 或 /home/admin/<project>,便于备份。
2)备份周期与保留(建议起点)
-
每日:留 7 份(近一周)
-
每周:留 4 份(近一月)
-
每月:留 6 份(近半年)
-
关键变更:手动打一个 里程碑备份(例如“升级前/大改动前”)
二、基础工具与目录
# 建立统一的本地备份目录
mkdir -p /srv/_backups/daily # mkdir:创建目录;-p:父目录不存在则一并创建
mkdir -p /srv/_backups/weekly
mkdir -p /srv/_backups/monthly
云端存储:如果你使用对象存储(如 S3/COS 等),建议在服务器装对应 CLI(如 aws s3 / coscli),把本地备份同步到云端冷存。
三、一次性脚本:打“整包”备份(可直接用)
把你实际的项目路径替换到脚本里;每条命令都含中文注释,便于理解。
nano /usr/local/bin/stack-backup.sh # nano:新建脚本文件
粘贴以下内容(按需调整项目列表与路径):
#!/usr/bin/env bash
set -euo pipefail
# set -e:遇错退出;-u:未定义变量即报错;-o pipefail:管道中任一命令失败即失败
NOW=$(date +%F_%H%M%S) # date:取当前日期时间,格式 2025-08-17_123456
HOST=$(hostname -s) # hostname -s:主机短名,便于区分多台机器
DEST_BASE="/srv/_backups" # 本地备份根目录
TIER="${1:-daily}" # 备份层级:daily/weekly/monthly,默认 daily
DEST_DIR="$DEST_BASE/$TIER" # 目标子目录
# 需要备份的项目(按你的实际修改)
PROJECTS=(
"/srv/wordpress" # WordPress(含 compose 与 html)
"/srv/rss_stack" # FreshRSS / RSSHub
"/srv/vaultwarden" # Vaultwarden
"/srv/syncthing" # Syncthing
"/srv/uptime-kuma" # Uptime Kuma
"/srv/homer" # Homer
)
mkdir -p "$DEST_DIR" # 确保目标目录存在
# 1) 冷冻所有 compose 项目到“干净状态”(可选:减少正在写入)
# 仅当你非常在意一致性时使用;正常家庭/轻量服务可跳过。
# for dir in "${PROJECTS[@]}"; do
# [ -f "$dir/docker-compose.yml" ] && (cd "$dir" && docker compose pause || true)
# done
# 2) 打包每个项目
for dir in "${PROJECTS[@]}"; do
name=$(basename "$dir") # basename:取目录名作为包名的一部分
tarball="${DEST_DIR}/${HOST}_${name}_${NOW}.tar.gz"
# tar -czf:打包并压缩为 .tar.gz
# --exclude:可按需排除缓存/临时文件
tar -czf "$tarball" \
--exclude='*.log' \
--exclude='node_modules' \
-C "$dir" . # -C:先切换到目录,再把“当前目录下所有内容”打进包
# 生成校验和(sha256sum:计算文件哈希)
sha256sum "$tarball" > "${tarball}.sha256"
done
# 3) 恢复运行(若之前 pause 了)
# for dir in "${PROJECTS[@]}"; do
# [ -f "$dir/docker-compose.yml" ] && (cd "$dir" && docker compose unpause || true)
# done
# 4) 本地清理策略(保留一定数量的包)
# 这里按“每层保留 30 天”为例;你也可以按数量清理(-mtime 改为 -printf + sort)
find "$DEST_DIR" -type f -name "*.tar.gz" -mtime +30 -delete
find "$DEST_DIR" -type f -name "*.sha256" -mtime +30 -delete
echo "[OK] backup done: $DEST_DIR"
保存(Ctrl+O 回车)→ 退出(Ctrl+X)→ 赋予执行权限:
chmod +x /usr/local/bin/stack-backup.sh # chmod +x:给脚本可执行权限
四、定时任务(crontab)
crontab -e
# 在文件末尾追加三行(每日/每周/每月各一次;时间可自行调整)
# 每天 凌晨 02:10 做一次“每日备份”
10 2 * * * /usr/local/bin/stack-backup.sh daily >> /var/log/stack-backup.log 2>&1
# 每周 周日 凌晨 02:20 做一次“周备份”
20 2 * * 0 /usr/local/bin/stack-backup.sh weekly >> /var/log/stack-backup.log 2>&1
# 每月 1 号 凌晨 02:30 做一次“月备份”
30 2 1 * * /usr/local/bin/stack-backup.sh monthly >> /var/log/stack-backup.log 2>&1
若要同步到对象存储,可在脚本末尾追加一段(以 S3 语法为例,COS/其他厂商类同):
# aws s3:把备份同步上云;--delete:让云端与本地一致(谨慎使用)
aws s3 sync "$DEST_DIR" "s3://your-bucket/stack/$TIER/" --delete
五、私钥的安全备份(只针对
私钥文件
)
# 1) 压缩并加密(zip 会提示输入加密口令)
cd ~/.ssh
zip --encrypt admin_ssh_key_${HOST}_$(date +%F).zip id_ed25519
# zip --encrypt:加密压缩;文件名中带日期与主机名便于辨识
# 2) 把生成的 zip 放入你的密码库 / 云盘(受信、受控)
# 切记:绝不把“明文私钥”丢在公开或弱权限的位置
六、灾难恢复(最短路径:从裸机到上线)
场景:原服务器不可用,新机器上快速恢复同一套服务。
0)新服务器最小化初始化
# 新建 admin 用户并给 bash
useradd -m -s /bin/bash admin # -m:创建家目录;-s:登录 shell
passwd admin # 设置 admin 口令(仅作本地应急)
# 配置 admin 的 SSH 公钥(把你本机公钥粘贴进去)
su - admin
mkdir -p ~/.ssh && chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys # 粘贴你的公钥(.pub 文件内容,一行)
chmod 600 ~/.ssh/authorized_keys
# 给 admin 配置 sudo 片段(免密或提示输入密码按需选择)
sudo visudo -f /etc/sudoers.d/90-admin
# 粘贴其中一行:
# admin ALL=(ALL) ALL
# 或
# admin ALL=(ALL) NOPASSWD:ALL
sudo chmod 440 /etc/sudoers.d/90-admin
sudo visudo -c # -c:检查 sudoers 语法
1)安装 Docker 与 Compose
# 不同发行版命令略有差异,这里给出通用参考(已简化)
sudo dnf install -y docker
sudo systemctl enable --now docker
docker -v # 验证 Docker 可用
docker compose version # 验证 Compose 子命令可用
2)恢复反向代理与证书
-
使用面板或手工安装 Nginx。
-
为每个子域名添加站点,目标指向 本机回环端口(稍后容器起来即可连接)。
-
申请 Let’s Encrypt 并强制 HTTPS。
-
站点反代里加入六行黄金请求头(避免样式/JS丢失):
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
3)拉回备份并解包到原路径
# 假设从对象存储或另一台机器取回最近的备份包
mkdir -p /srv/_restore && cd /srv/_restore
# 把 *.tar.gz 下载到本目录(命令略)
# 校验完整性:对每个包做 sha256sum 校验
sha256sum -c *.sha256 # -c:逐个校验哈希,OK 表示文件未损坏
# 选择一个包(示例:vaultwarden),解压回目标目录
mkdir -p /srv/vaultwarden
tar -xzf HOST_vaultwarden_YYYY-MM-DD_HHMMSS.tar.gz -C /srv/vaultwarden
# tar -xzf:解压 .tar.gz;-C:解压到指定目录
权限复位(重要):如果容器需要以 admin 身份写文件,确保属主一致:
sudo chown -R admin:admin /srv/vaultwarden
# 按项目依次处理 /srv/rss_stack /srv/syncthing /srv/uptime-kuma /srv/homer 等
4)逐项启动各服务(按你原来的项目目录)
# 先起反代依赖少的(例如 Homer)
cd /srv/homer && docker compose up -d && docker compose ps
# 再起 Kuma(便于在恢复过程中“自我监控”)
cd /srv/uptime-kuma && docker compose up -d
# 再起 FreshRSS/RSSHub
cd /srv/rss_stack && docker compose up -d
# Vaultwarden(核心)
cd /srv/vaultwarden && docker compose up -d
# Syncthing(文件同步)
cd /srv/syncthing && docker compose up -d
# WordPress(如你用 Docker 方式)
cd /srv/wordpress && docker compose up -d
若 WordPress 用的是面板安装而非 Docker:
-
先建空站点 → 导入网站文件(备份包里的 html 目录)
-
导入数据库(.sql 或面板的数据库备份);
-
若域名变化,记得更新 wp_options 里的 siteurl/home(或 wp-config.php 里定义 WP_HOME/WP_SITEURL)。
5)逐项验证(从“站点入口”到“服务本体”)
# 只在服务器本机测后端端口
curl -I http://127.0.0.1:3002 # Homer 示例
curl -I http://127.0.0.1:3001 # Kuma
curl -I http://127.0.0.1:8082 # FreshRSS
curl -I http://127.0.0.1:8384 # Syncthing GUI
# -I:只取响应头;200/302 即后端正常
# 外网浏览器访问域名(反代 + HTTPS)
https://home.example.com
https://status.example.com
https://rss.example.com
# ……
6)Syncthing 特有步骤
-
打开 https://sync.example.com:检查设备 ID 是否与本地设备互认;
-
如果资料库路径不同,按 GUI 提示**“重新配对路径”**;
-
22000/TCP+UDP 放行后,观察连接类型是否为 TCP/QUIC(非 Relay)。
7)Vaultwarden 特有步骤
-
恢复后若域名变化,客户端可能需要重新登录;
-
确认环境变量/配置里的 DOMAIN(如果有)与当前域名一致;
-
强制 HTTPS 的反代要正确传递请求头。
8)Kuma 特有步骤
-
打开 https://status.example.com:确认监控项在线;
-
测试通知:给 QQ SMTP 通道点“测试”;
-
如监控的域名有变化,批量修改目标地址或重建。
七、演练建议(别等出事才第一次恢复)
-
季度进行一次桌面演练:选 1~2 个服务,在同一台机器的备用路径(如 /srv/_drill)解包 + up -d,验证能打开;
-
演练完成后删除临时容器与数据,避免混淆与资源占用;
-
每次演练都更新一份 “恢复核对清单” 记录问题与改进点。
八、恢复核对清单(贴墙上就能照做)
-
admin 账号可 SSH 登录,sudoers 片段有效(visudo -c 通过)
-
Docker/Compose 能正常运行(docker compose version OK)
-
Nginx 反代 + HTTPS 就绪(站点存在、证书有效、六行请求头已配置)
-
备份包校验通过(sha256sum -c 全 OK)
-
各项目目录解包到位,属主为 admin(chown -R admin:admin)
-
各服务 docker compose up -d 无报错,curl -I 127.0.0.1:<port> 200/302
-
外网访问各域名正常
-
Syncthing 设备互认、资料库路径匹配、22000 直连可用
-
Vaultwarden 登录正常;若域名变化,客户端已重新登录
-
Uptime Kuma 监控与通知均恢复
-
Homer 首页导航链接全部可点开
【深度解析与知识扩展】
1)为什么“备份目录 + Compose + 数据卷”三位一体?
-
Compose 文件定义“如何跑”;
-
数据卷/挂载目录保存“跑出来的状态”;
-
反代与证书决定“别人如何访问”。
缺一不可:只有数据没 Compose,会忘记端口/环境变量;只有 Compose 没数据,站点会“空壳启动”。
2)一致性 vs 可用性
-
对数据库/高并发写入服务,一致性备份最好在短暂停机或只读窗口进行(或用热备工具)。
-
对你的轻量服务,结合“快速冷备 + 多副本”通常更实用:即便单次备份不完美,也能靠近几天的多份回滚。
3)校验和(Checksum)的意义
-
传输/存储过程中可能损坏;
-
sha256sum 给你“数学级”的确定性:校验通过才可用于恢复。
4)为什么密钥一定要“加密备份”
-
私钥一旦泄露 = 任何人都可冒充你登录服务器;
-
加密压缩 + 强口令 + 放入密码库,才能“可用又安全”。
5)“六行黄金请求头”的通用性
-
很多“反代后没样式/JS”的根因,是后端不知道自己在 https/哪个 Host;
-
这六行把关键信息补齐,适用于 Homer / Kuma / FreshRSS / Vaultwarden / Syncthing GUI 等多数 Web 服务。
6)为什么建议把项目统一放
/srv/<project>
或
/home/admin/<project>
-
备份/迁移/权限管理都极其直观;
-
你只需要记住“一棵树”,脚本里循环打包即可。
到此为止,你已经拥有一套可操作、可演练、能在出事时救命的“备份与灾备 SOP”。
鄂公网安备42011102005804号