适用场景:NAS 里已经有家庭照片、视频、文档、Docker 配置,只有一份数据 = 裸奔
策略:3-2-1 原则(3 份副本、2 种介质、1 份异地)
工具链:Restic(去重、加密、增量、快照)+ rclone(对接 S3 / 另一台 NAS / 网盘)+ systemd timer(定时自动跑)
—
0. 为什么选 Restic?
| 特性 | Restic | rsync / tar | 网盘同步盘 |
| 去重 | ✅ 块级去重,增量极小 | ❌ 全量或文件级 | ❌ 文件级 |
| 加密 | ✅ AES-256 + ChaCha20-Poly1305,密码只在你手里 | ❌ 需额外加密 | ⚠️ 厂商可读 |
| 快照 | ✅ 每次备份都是完整快照,任意时间点恢复 | ❌ 需手动管理 | ⚠️ 版本历史有限 |
| 存储后端 | ✅ 本地 / SFTP / S3 / B2 / rclone 任意后端 | ❌ 仅本地/远程文件系统 | ❌ 绑定厂商 |
| 校验 | ✅ restic check 全量校验完整性 | ❌ 手动校验 | ⚠️ 依赖厂商 |
—
1. 一次性初始化(只做一次)
1.1 安装
# Debian/Ubuntu
sudo apt update && sudo apt install -y restic rclone
# 或下载最新静态二进制
# https://github.com/restic/restic/releases
# https://rclone.org/downloads/
1.2 准备仓库密码(生成强密码,存入密码管理器)
# 生成 32 字符随机密码
openssl rand -base64 32 | tr -d '\n' > ~/restic-repo-password.txt
chmod 600 ~/restic-repo-password.txt
# 内容示例:K7x9mP2qR4vL8nJ1hG5fD3sA6zX9cV2b
1.3 初始化本地仓库(作为第 1、2 份副本:NAS 本地 + 外接硬盘)
export RESTIC_PASSWORD_FILE=~/restic-repo-password.txt
export RESTIC_REPOSITORY=/data/backup/restic-repo # 本地 ZFS 数据集 / 单独分区
restic init
1.4 初始化远程仓库(第 3 份异地副本:S3 兼容 / 另一台 NAS / 网盘)
rclone 支持 40+ 后端,这里以 S3 兼容(MinIO / AWS S3 / Cloudflare R2 / Backblaze B2 / 阿里云 OSS / 腾讯云 COS)为例,其它后端同理。
# 1) 配置 rclone 远程端
rclone config
# 名称:remote-s3
# 类型:s3
# provider:选对应厂商(MinIO / AWS / Cloudflare / Other)
# env_auth:false
# access_key_id / secret_access_key:填你的 AK/SK
# region / endpoint:按厂商填
# acl / storage_class:默认
# 2) 测试连通性
rclone lsd remote-s3:
# 3) 初始化远程仓库(同一密码、同一仓库 ID,方便同步)
export RESTIC_PASSWORD_FILE=~/restic-repo-password.txt
export RESTIC_REPOSITORY=rclone:remote-s3:restic-repo
restic init
关键点:本地和远程用同一个密码、同一个仓库 ID,后续 restic backup 到本地,rclone sync 远程仓库目录即可,保持两地仓库一致。
—
2. 备份内容清单(按重要性分级)
# /data/backup/include.txt (只备份这些,排除其它)
/data/media # 媒体库(Jellyfin 管理,但原始文件要备份)
/data/config # 所有容器配置(NPM 证书、Jellyfin 元数据、HA 配置、qBittorrent 种子等)
/data/downloads # 下载完成待整理(可选,视容量)
/etc # 系统级配置(nginx、ssh、fstab、systemd 单元)
/root # root 家目录(脚本、密钥)
/home # 普通用户家目录
# 排除缓存、临时、大文件重复
# /data/backup/exclude.txt
**/cache/**
**/tmp/**
**/.Trash-*/
**/node_modules/**
**/__pycache__/**
*.tmp
*.log
*.iso
*.qcow2
*.vmdk
—
3. 备份脚本(放 /usr/local/bin/backup-nas.sh,chmod +x)
#!/usr/bin/env bash
set -euo pipefail
# === 配置区 ===
export RESTIC_PASSWORD_FILE="/root/restic-repo-password.txt"
LOCAL_REPO="/data/backup/restic-repo"
REMOTE_REPO="rclone:remote-s3:restic-repo"
INCLUDE_FILE="/data/backup/include.txt"
EXCLUDE_FILE="/data/backup/exclude.txt"
LOG_FILE="/var/log/restic-backup.log"
RETENTION_KEEP="--keep-last 30 --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 3"
# === END ===
exec >>"$LOG_FILE" 2>&1
echo "===== $(date -Is) 备份开始 ====="
# 1. 本地备份(快、去重、加密)
echo ">>> 本地仓库备份..."
restic -r "$LOCAL_REPO" backup \
--files-from "$INCLUDE_FILE" \
--exclude-file "$EXCLUDE_FILE" \
--one-file-system \
--compression max
# 2. 忘记旧快照、清理未引用数据
echo ">>> 本地清理旧快照..."
restic -r "$LOCAL_REPO" forget $RETENTION_KEEP --prune
# 3. 同步仓库到远程(rclone 只同步变化的 pack 文件,极快)
echo ">>> 同步到远程仓库..."
rclone sync "$LOCAL_REPO" "$REMOTE_REPO" \
--progress \
--transfers 4 \
--checkers 8 \
--retries 3 \
--low-level-retries 10
# 4. 远程也做一次 forget/prune(保持策略一致)
echo ">>> 远程清理旧快照..."
restic -r "$REMOTE_REPO" forget $RETENTION_KEEP --prune
# 5. 完整性校验(每周做一次,避免每天跑太久)
if [[ $(date +%u) -eq 7 ]]; then # 周日
echo ">>> 本地完整性校验..."
restic -r "$LOCAL_REPO" check --read-data-subset=5%
echo ">>> 远程完整性校验..."
restic -r "$REMOTE_REPO" check --read-data-subset=5%
fi
echo "===== $(date -Is) 备份结束 ====="
—
4. systemd 定时器(每天凌晨 02:30 自动跑)
# /etc/systemd/system/backup-nas.service
[Unit]
Description=NAS Restic Backup
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-nas.sh
# 可选:失败发邮件/Telegram
# OnFailure=backup-failed-notify.service
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/backup-nas.timer
[Unit]
Description=Daily NAS Backup Timer
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup-nas.timer
systemctl list-timers --all | grep backup-nas
—
5. 常用恢复操作(灾难演练建议每季度跑一次)
export RESTIC_PASSWORD_FILE=~/restic-repo-password.txt
export RESTIC_REPOSITORY=/data/backup/restic-repo # 或远程仓库
# 1. 列出所有快照
restic snapshots
# 2. 浏览某个快照的文件树
restic ls latest --path /data/config/jellyfin
# 3. 恢复单个文件/目录到指定位置
restic restore latest --target /tmp/restore --include /data/config/jellyfin/config.yaml
# 4. 恢复整个快照(灾难恢复)
restic restore latest --target /mnt/recovery-root
# 5. 挂载仓库只读(按需拷贝文件)
mkdir /mnt/restic-mount
restic mount /mnt/restic-mount
# ls /mnt/restic-mount/hosts/nas-ip/...
fusermount -u /mnt/restic-mount
—
6. 监控 & 告警(别让备份“静默失败”)
6.1 简单版:备份日志尾行推送到 Telegram
# 在 backup-nas.sh 末尾加:
curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id=<CHAT_ID> \
-d text="✅ NAS 备份完成 $(date '+%F %T')"
6.2 进阶版:Prometheus + Grafana(已有监控栈)
# restic 支持 --json 输出,配合 node_exporter textfile collector
restic -r "$LOCAL_REPO" snapshots --json > /var/lib/node_exporter/textfile_collector/restic_snapshots.prom
# 指标示例:restic_snapshots_total、restic_last_backup_timestamp、restic_repo_size_bytes
—
7. 容量规划参考(按经验值)
| 数据类型 | 去重后增量/天 | 年增量估算 | 建议保留 |
| 家庭照片/视频(原始) | 50 MB - 500 MB | 200 GB - 1 TB | 永久(全量快照) |
| Docker 配置 / 系统配置 | < 1 MB | < 500 MB | 全部保留 |
| 下载目录(临时) | 变动大 | 视情况 | 只保留最近 7 天 |
| 数据库 dump(如 HA SQLite) | 10-50 MB | 5-20 GB | 按策略保留 |
省钱技巧:Cloudflare R2 / Backblaze B2 无出站流量费,适合做异地仓库;MinIO 自建在另一台 NAS 上则零成本。
—
8. 一键部署清单(复制粘贴即可)
# 1. 安装工具
sudo apt install -y restic rclone
# 2. 生成密码、初始化本地/远程仓库(按上文 1.2-1.4)
# 3. 写 include/exclude 文件
sudo mkdir -p /data/backup
cat > /data/backup/include.txt <<'EOF'
/data/media
/data/config
/data/downloads
/etc
/root
/home
EOF
cat > /data/backup/exclude.txt <<'EOF'
**/cache/**
**/tmp/**
**/.Trash-*/
**/node_modules/**
**/__pycache__/**
*.tmp
*.log
*.iso
*.qcow2
*.vmdk
EOF
# 4. 部署备份脚本 + systemd timer(上文 3-4 节)
# 5. 手动跑一次验证
sudo /usr/local/bin/backup-nas.sh
tail -30 /var/log/restic-backup.log
# 6. 做一次恢复演练
restic -r /data/backup/restic-repo restore latest --target /tmp/test-restore --include /data/config/npm
ls -la /tmp/test-restore/data/config/npm/
—