太长不看

  • 用云端私有存储搭了一套免费双通道自动备份系统:加密备份 + 明文直传
  • 文件变化后自动上传,每小时全量同步兜底
  • 机器人支持查目录、翻页、按序号取文件,Windows 服务开机自启
  • 完整记录实施思路和踩坑排查,可封装成一键安装包
  • 需要准备:Windows 10/11 + Python 3.11+ + 合规的云存储账号

声明:本文为 AI 辅助开发实践记录。代码由 AI 辅助生成,作者负责需求设计、方案选型、测试、部署和排障。文中出现的云服务、机器人、令牌、用户名均为匿名化占位符,请勿直接复制使用;落地时请结合合规的云存储产品和当地法律法规。

1. 我为什么需要一个自动备份系统

我最怕的事,是电脑突然坏了。博客、课件、代码、学习资料全都存在本地硬盘里,坏了就真的什么都没了。U 盘会丢、会坏;传统网盘要么容量小,要么限速,要么收费;而且大多需要手动上传,经常想不起来备份。

其实这个问题,我上一个项目就尝试解决过。当时我做了 Git 自动同步方案,先问了 AI 一个问题:远端仓库大小、单个仓库能存的文件数,到底有什么限制?得到的答案是:空间和单仓库大小都有明确上限。

那时我就意识到,只靠 Git 一个小工具,解决不了所有备份问题。同步博客这种文件少、体积小的场景没什么压力,但一旦要同步课件、学习资料这类又多又大的文件,就很吃力了。Git 项目虽然也能备份,但只适合小文件。我需要探索一种新的备份范式。

我把上面的痛点整理成了明确的需求:

  • 容量要大——能装下课件和学习资料
  • 速度不能太慢——别像某些网盘一样上传下载都限速
  • 要自动——文件一改,自动同步
  • 要异地保存——电脑坏了、U 盘丢了,文件还在别处
  • 成本要低——个人使用,不想年年交钱

后来我发现,很多即时通讯软件自带“私有频道/私有空间”能力,可以存放大量文件,恰好符合容量大、成本低、跨设备访问的特点。于是我想:能不能用脚本把本地目录自动推送到云端私有空间,再通过机器人随时取文件?这就是这个项目的直接推动力。

2. 最终做成了什么

一套 Windows 上的双通道备份系统:

  • 加密通道:文件先本地加密,再分片上传云端,内容不可直接查看
  • 明文通道:文件以原始格式上传,可以在客户端直接查看、下载
  • 实时同步:目录有变化,约 5~10 秒内自动上传;每小时还有全量同步兜底
  • 机器人:发命令查总目录、今日更新,回复序号就能把对应文件发到私聊
  • 后台服务:注册三个 Windows 服务,开机自启、崩溃自动重启
  • 一键安装包:把整套系统封装成可以复制到其他电脑使用的安装包

电脑自动备份,手机也能直接传文件,两边数据互通。

3. 技术选型思路

组件作用为什么选它
云端私有存储服务文件分片、加密、上传容量大、成本低、支持开放接口
PostgreSQL保存文件索引、分片、空间信息原生 Windows 服务,稳定直观
同步工具加密备份的同步支持远程后端,可命令行调用
直传客户端明文直传和机器人逻辑Python 生态成熟,接口灵活
机器人接口目录检索、取文件官方开放能力,天然跨设备
NSSM注册 Windows 服务开机自启、崩溃自动重启

选型时主要考虑三件事:

  1. 为什么选云端私有空间? 免费、容量大、跨设备(电脑和手机都能访问),不依赖本地磁盘。缺点是依赖第三方平台,所以只作为异地副本,本地保留原文件。
  2. 为什么加密和明文两条通道? 加密备份安全,文件加密后都是乱码,查看必须依赖服务端;一旦丢失密钥或配置文件,数据就成了死数据。明文直传恰好解决这些缺点:可以跨设备直接查看文件,下载恢复不再依赖电脑,但安全性低。所以两个都要:重要资料走加密,日常文件走明文。
  3. 为什么分片设 500 MB、默认覆盖模式? 分片越大,云端消息条数越少,方便管理;但又不能设得过大。日常备份不需要每次修改都留历史版本,默认覆盖只保留最新版,需要版本历史的目录可以单独开启 version 模式。

4. 系统架构

所有程序都放在用户目录下,加密备份和明文直传两条链路各自独立:

%USERPROFILE%\.backup\             ← 备份系统的"家"
├─ backup.ps1        加密备份服务(同步工具 + 云存储)
├─ rclone.conf      同步工具配置
├─ backup-config.json 备份源、同步间隔、排除规则
├─ logs\             同步日志
└─ direct\           明文直传 + 机器人
   ├─ direct-watch.ps1  明文直传服务
   ├─ direct_upload.py  上传与机器人核心
   ├─ direct_config.json 空间、备份源配置
   └─ bot_config.json   机器人配置(敏感,不展示)

整套系统分两条备份链路,外加一个检索机器人,跑在三个 Windows 服务上:

本地目录
  ├─ 加密备份: FileSystemWatcher -> 同步工具 -> 云存储(加密)
  └─ 明文直传: FileSystemWatcher -> 直传客户端 -> 云空间(可直接查看)

机器人
  ├─ /start 开始
  ├─ /status 查看状态
  ├─ /today 今日更新
  ├─ /all 全部目录
  ├─ 翻页 / 跳页 / 回复序号取文件
  └─ 每日更新 + 停止按钮

加密和明文两条链路互相独立,各自有空间、各自的锁和 manifest 日志,互不影响。

5. 实施路线(通用版)

下面只保留通用的实施思路,具体账号、令牌、密钥的获取方式请按你所选云存储服务的官方文档执行。

5.1 第 1 步:准备环境

安装 Python 3.11+,安装时勾选 “Add Python to PATH”,然后验证:

python --version

能输出版本号就成功。

5.2 第 2 步:安装数据库

使用原生 PostgreSQL 服务,而不是 Docker,减少一层依赖,也更方便开机自启。

创建备份服务专用的数据库账号和库,密码使用随机生成的长密码,并妥善保管。

5.3 第 3 步:搭建云端存储服务

部署一个支持文件分片、加密、上传的服务端,配置文件里放占位符:

# 核心配置占位符
data-source = "postgres://用户名:密码@地址:端口/数据库"
jwt-secret = "JWT_SECRET"
encryption-key = "ENCRYPTION_KEY"

必须修改三处:

配置项说明
数据库连接串换成真实密码和端口
JWT 签名密钥换成随机长字符串,不要使用字面量
加密密钥随机生成,长度建议 32B,丢失后无法解密

生成随机密钥的参考命令:

$b = New-Object byte[] 32
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($b)
[System.BitConverter]::ToString($b).Replace("-", "")

服务启动后,用三层检查确认正常:

第 1 层:进程正常、端口在听
第 2 层:Web 可访问(返回 200)
第 3 层:数据库连接能查到一行记录

5.4 第 4 步:配置同步工具

普通版同步工具不一定支持云存储后端,必须使用配套版本,并在 rclone.conf 中填写后端配置:

[remote]
type = cloud
api_host = http://127.0.0.1:8080
access_token = PASTE_ACCESS_TOKEN
chunk_size = 500M
upload_concurrency = 4
encrypt_files = true
random_chunk_name = true
channel_id = 0
root_folder_id =

配置完成后,先列一次远端文件,能列出来就说明令牌填对了。

5.5 第 5 步:安装 Python 依赖

python -m pip install --upgrade 依赖包1 依赖包2

依赖包用于直传上传、机器人交互和图片处理,按实际所选 SDK 安装。

5.6 第 6 步:创建两个私有空间

在云服务中创建两个私有空间:

  • 一个加密空间,用于加密备份
  • 一个明文空间,用于日常直传

把机器人添加进明文空间并设为管理员,方便后续取文件。

5.7 第 7 步:登录并填写令牌

服务端登录后,会返回会话令牌。令牌不要填在网页里,而是填回本地配置文件的 access_token 位置。

⚠️ 这个令牌等同于登录态,别泄露给别人;一旦泄露,请立即在服务端撤销并重新生成。

5.8 第 8 步:注册三个 Windows 服务

使用 NSSM 把三个命令注册为服务:

服务 1:云存储 Web 服务 + API
服务 2:加密备份监听
服务 3:明文直传监听

服务启动后,做一次初始扫描并上传 manifest,然后进入监听循环。

5.9 第 9 步:添加备份目录

分别给加密通道和明文通道添加备份目录,设置前缀、频道/空间和覆盖模式。

6. 验证思路

经过验证,脚本可以自动备份,随后我把两个脚本封装成一个菜单界面。

备份时默认忽略隐藏文件和空文件

  • 隐藏目录/隐藏文件默认跳过,例如以 . 开头的路径、.log 文件和 0 字节文件
  • 普通文件正常备份,状态文件会记录每个文件的 size、mtime、message_id

我还在统计脚本里加入了隐藏文件和实际备份文件的数量统计,方便校对。

同时,我在云端空间里加了 manifest.txt 统计文件。manifest 不是由本地备份的,所以不计入本地统计;验证后发现各备份源都能正常自动备份。

然后我在机器人上也做了验证:

  • /status 查看状态
  • /all 查看全部目录
  • 回复序号取文件
  • 修改文件后触发自动上传

经过校验,加密备份和明文备份都验证成功。从文件备份、读取,到灾备恢复和异常处理,这套系统都能覆盖;需要加密的重要资料可以走加密通道,同时必须妥善备份密钥。

7. 技术原理

技术解决什么问题核心原理
FileSystemWatcher监听目录变化Windows 文件系统事件
Debounce 防抖避免频繁触发上传事件后等待 N 秒再执行
文件锁防止多个同步同时执行独占打开锁文件
同步工具加密备份同步对比本地和远端差异
云存储服务分片、加密、上传调用云端开放接口上传分片
PostgreSQL保存文件索引记录文件、分片、空间状态
直传客户端明文直传客户端库封装开放接口
状态文件记住已上传文件保存 size、mtime、message_id
manifest记录目录和日期本地生成日志上传云端
长轮询机器人接收消息定时拉取更新
回调按钮机器人交互内联键盘 + 回调数据
NSSM开机自启把命令注册成 Windows 服务

7.1 文件监听

使用 System.IO.FileSystemWatcher 监听目录,事件包括 Changed、Created、Deleted、Renamed。只监听事件还不够,文件系统事件可能漏掉,所以服务里还会做短间隔轮询兜底。

7.2 防抖

事件触发后不立即同步,而是记录最后变化时间;只有距离最后一次变化超过防抖时间才真正执行,避免频繁小修改反复上传。

7.3 文件锁

两个进程不能同时执行同步或上传,否则会产生重复记录。锁的原理是独占打开锁文件:第二个进程尝试打开时被拒绝,表示另一个同步正在运行。

7.4 手动同步优先级

手动同步时,如果后台正在同步,不能直接杀掉进程,否则可能留下半成品数据库记录。方案是:

  • 手动同步创建 priority 文件
  • 后台循环发现该文件后,停止下一个任务
  • 手动同步等待当前任务完成,然后获取锁执行
  • 手动执行完成后删除 priority 文件

7.5 同步原理

同步命令让远端和本地一致,支持保留空目录、并发传输、断点续传。sync 会对比本地和远端差异,只上传变化部分。

7.6 状态文件

状态文件记录每个文件的大小、修改时间、消息 ID。扫描时先对比状态:

  • 大小和修改时间一致 → 已上传,跳过
  • 不一致或没有记录 → 加入待上传队列
  • overwrite 模式 → 更新同一条远端消息
  • version 模式 → 保留历史版本

7.7 manifest

manifest 记录目录里的所有文件、更新时间、覆盖时间,上传到云端,方便手动核对本地和远端数量。超过最大体积自动轮替,保留最近若干份。

7.8 机器人交互

机器人通过长轮询接收消息,支持文本命令和内联按钮。目录数据由本地生成,机器人只是查询和取文件的入口。

8. 常见问题排查思路

  1. 网页端无法登录:多为浏览器缓存、Cookie 或扩展拦截,清理后重试,或换浏览器。
  2. 数据库服务无法启动:检查端口占用、数据目录权限、服务账号;先看系统事件日志。
  3. 云端显示文件数比本地多:多为本地已删除但远端仍保留,或手机/手工上传;用 manifest 对比。
  4. 清空远端后再次同步只上传少量文件:索引和远端不一致,先清索引再重建。
  5. 同步产生重复记录:锁未生效或并发执行,检查锁文件是否残留。
  6. 同步工具报 HTTP 500:多为服务端配置、令牌或数据库连接问题,先看服务端日志。
  7. 机器人按钮没有反应:检查机器人令牌、回调处理和更新偏移量。
  8. 机器人把文件发错位置:检查发送目标 ID 和私聊判断逻辑。
  9. 手机上传的文件在目录里看不到:目录只汇总本地文件,远端手工文件需要单独标记。
  10. 0 字节文件无法上传:默认跳过空文件,这是设计行为。
  11. bat 双击一闪而过:bat 缺少 pause,或在执行后直接退出;检查编码和换行。
  12. 后台服务找不到 Python:服务环境变量和普通用户环境变量不是一回事,需要显式设置 Python 路径。
  13. 会话数据库被锁:另一个进程正在使用会话,等待完成或检查锁残留。
  14. manifest 每小时都更新:没有判断内容是否变化,加内容签名即可。
  15. manifest 和日志无限增长:设置最大体积轮替和日志保留天数。
  16. 同步后端突然失效:多为版本不匹配,升级后必须重新验证后端。
  17. 加密备份不实时同步:事件监听可能漏事件,用短间隔轮询兜底。
  18. 手动同步中断后实时同步停止:priority 文件残留导致,超过时间自动清理。

9. 总结

这次项目从最初的模糊想法到最终落地,带给我的收获比预期大得多。回头对照最初列的 5 个需求——容量大、速度够用、文件变化后自动上传、异地保存、低成本——全部达成了。

加密通道保护重要资料,明文通道随时手机取文件,两者互补;再加上和 Git 自动同步项目配合,小文件走 Git、大文件走云端,算是真正解决了我的备份焦虑。

整个过程中,代码由 AI 辅助生成,但需求拆解、方案选型、测试验证、问题定位、优先级裁定、锁机制设计都需要自己判断。即使不手写每一行代码,理解系统逻辑和排障思路依然是核心能力。

这个项目比普通脚本项目难度大得多——日志轮替、冲突管理、密钥生成、格式问题、版本冲突,每一个坑背后都涉及操作系统、网络协议、数据库和并发编程的知识。边做边查、反复测试,最终把理论上可行的方案变成了能稳定运行的系统。

如果你也想搭一套自己的备份系统,可以从环境检查开始,逐步安装、添加目录、测试恢复,最后再交给服务自动运行。遇到问题,优先看服务日志和 manifest 统计,往往比瞎猜更快。

最后提醒两件事:加密密钥丢了,已加密的数据基本等于永久丢失;自己的令牌、配置和会话文件不要公开分享。备份的核心不是“上传了多少”,而是“丢了之后能恢复多少”。祝大家备份无忧。


大家好,这是我托管在 CF 的博客网站:https://dsduyopg-github-io.pages.dev/

欢迎大家访问我的网站,有什么问题,欢迎大家提意见。