Supernote 私有云灾难恢复实录:从数据全毁到完美重建的 48 小时

一、事故回顾:一次断电引发的连锁反应

事情要从一次意外的断电说起。

我的 Synology DS923+ NAS 经历了几次突然断电,最初只是觉得运气不好,重启后一切似乎正常。然而几天后,4 号硬盘(8T)突然报状态为 Critical,整个 SHR 存储池被降级。更换新硬盘后,噩梦才真正开始——系统文件已经损坏到无法通过常规手段修复的程度。

按照官方技术支持的建议,我不得不走上一条“备份全部数据 → 删除 Volume → 重新创建 Volume → 恢复所有数据”的道路。

当时我的系统配置是:

  • 群晖 DS923+
  • 4 块硬盘:4T + 4T + 8T + 8T,组成 SHR RAID
  • 2TB SSD 缓存 + 16GB 内存
  • 部署了多个服务,除了mysql、share drive以外,还包括 Supernote 私有云,详细部署过程参见这篇文章

重建存储池和恢复基础数据的过程虽然繁琐但有章可循,真正的挑战来自 Supernote 私有云。这个自建服务在数据恢复后反复报错,登录始终失败,在通过网页登录私有云时提示“Account or Password Error”,创建新用户、重置密码均无法解决问题,耗费了整整两天时间才彻底解决。

我把整个过程记录下来,希望能帮到遇到类似问题的朋友。


二、私有云故障的核心症状

数据恢复后,Supernote 私有云出现以下现象:

  1. 登录始终报错“Account or password error”,即使通过官方渠道重置密码也无法解决
  2. 容器日志反复出现 TooManyResultsException: Expected one result... but found: 2
  3. u_user 表中明明只有一个用户,但错误依然存在
  4. 即使清空所有表数据、重建容器,错误依然顽固

这个错误信息成了整个排查过程中的“噩梦模式”——它像幽灵一样挥之不去,让我一度怀疑自己是不是碰到了无法解决的 Bug。


三、踩坑与排错:一个曲折的定位过程

第 1 坑:以为只是重复用户的问题

最初看到 TooManyResultsException,第一反应是数据库里存在重复的用户记录。检查 u_user 表后,确实发现两个用户(一个是我原来的账号,一个是后来为了测试创建的新账号)。删除新用户后,问题依旧。

经验教训:不要只盯着 u_user 表。Supernote 的登录验证会关联查询多个表。

第 2 坑:逐一排查 26 张表

通过查询所有包含 user_id 字段的表,发现以下表都有数据:

  • e_temp / e_temp_now
  • e_user_equipment / e_user_equipment_record
  • f_capacity / f_file_action / f_file_convert
  • f_file_his_sync / f_file_server_change
  • f_recycle_file / f_share_record / f_user_file
  • t_schedule_* 系列(多张定时任务表)
  • t_summary / t_summary_tag
  • u_commonly_area / u_commonly_equipment
  • u_data_migration_record / u_sensitive_record
  • u_user_history / u_user_sold_out / u_login_record

逐一删除另一个用户的残留数据后,重启容器——问题依然存在!

第 3 坑:清空所有表数据仍然无效

此时我已经开始怀疑人生。为了彻底排除数据问题,执行了清空所有 26 张表的操作,重新注册账号。结果——依然是 TooManyResultsException

这说明问题根本不在数据层面。

第 4 坑:发现真正的根源

重新检查 docker-compose.yml,发现一个致命问题:所有服务没有配置自定义网络

Supernote 私有云需要以下四个服务协同工作:

  • mariadb:数据库
  • redis:缓存
  • notelib:笔记库服务
  • supernote-service:主服务

如果没有将它们放在同一个自定义网络(supernote-net)中,supernote-service 就无法通过主机名 mariadb 连接到数据库,导致启动失败。

正确的网络配置

services:
  mariadb:
    networks:
      - supernote-net
  redis:
    networks:
      - supernote-net
  notelib:
    networks:
      - supernote-net
  supernote-service:
    networks:
      - supernote-net

networks:
  supernote-net:
    name: supernote-net
    driver: bridge

第 5 坑:设备绑定标识无法清除

即使私有云服务恢复正常,设备端仍然提示“必须登录原来绑定的私有云账号”。这是因为 Supernote 设备在首次绑定私有云时,会在本地存储一个与该私有云实例绑定的唯一标识。

清空数据库、重建容器都无法解决这个问题。最终只能通过以下流程解决:

  1. 通过 USB 将设备上的所有文件(NoteDocumentExport 等文件夹)完整备份到电脑
  2. 登录官方 Supernote 云,将笔记同步到官方服务器(作为中转)
  3. 恢复出厂设置
  4. 从电脑备份恢复所有文件
  5. 重新连接私有云

四、正确的完整重建流程

以下是经过验证的、能够彻底解决私有云登录问题的完整流程:

在这里插入图片描述

第一步:备份设备数据(最重要)

# 通过 USB 连接 Supernote 到电脑
# 将整个设备的所有文件夹复制到本地:
# - Note/      (笔记文件)
# - Document/  (文档)
# - Export/    (导出文件)
# - MyStyles/  (样式)
# - ScreenShot/(截图)
# - MyScripts/ (脚本)

千万不要只依赖系统内置的“备份摘录”功能,那个只有 15MB,而你的真实数据可能是 14GB!

第二步:通过官方云中转数据

在设备上登录官方 Supernote 账号
将所有笔记同步到官方云
访问 https://cloud.supernote.com 确认数据完整

第三步:恢复出厂设置

设备设置 → 系统 → 恢复出厂设置

第四步:从电脑恢复数据

USB 连接电脑,将备份的所有文件夹复制回设备
登录官方云,同步确认数据完整

第五步:正确的私有云部署

# docker-compose.yml 核心配置(完整版)

version: '3.8'

services:
  mariadb:
    image: mariadb:10.6.24
    container_name: supernote-mariadb
    networks:
      - supernote-net
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_DATABASE: supernotedb
      MYSQL_USER: supernote_user
      MYSQL_PASSWORD: your_user_password
    volumes:
      - /path/to/mariadb_data:/var/lib/mysql
    restart: unless-stopped

  redis:
    image: redis:7.4.7
    container_name: supernote-redis
    networks:
      - supernote-net
    command: redis-server --requirepass your_redis_password
    volumes:
      - /path/to/redis_data:/data
    restart: unless-stopped

  notelib:
    image: docker.io/supernote/notelib:6.9.3
    container_name: supernote-notelib
    networks:
      - supernote-net
    restart: unless-stopped

  supernote-service:
    image: docker.io/supernote/supernote-service:26.02.23
    container_name: supernote-service
    networks:
      - supernote-net
    ports:
      - "18072:18072"   # 设备同步端口
      - "19072:8080"    # Web 界面端口
    volumes:
      - /path/to/sndata/recycle:/home/supernote/recycle
      - /path/to/supernote_data:/home/supernote/data
      - /path/to/sndata/logs/cloud:/home/supernote/cloud/logs
      - /path/to/sndata/logs/app:/home/supernote/logs
      - /path/to/sndata/logs/web:/var/log/nginx
      - /path/to/sndata/convert:/home/supernote/convert
      - /etc/localtime:/etc/localtime:ro
    environment:
      MYSQL_DATABASE: supernotedb
      MYSQL_USER: supernote_user
      MYSQL_PASSWORD: your_user_password
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: your_redis_password
    depends_on:
      - mariadb
      - redis
      - notelib
    restart: unless-stopped

networks:
  supernote-net:
    name: supernote-net
    driver: bridge

第六步:启动服务

cd /path/to/supernote/
sudo docker-compose down -v   # 彻底清理
sudo docker-compose up -d     # 全新启动

五、避坑指南:经验总结

🔴 致命错误(会导致服务完全不可用)

错误 后果 正确做法
未配置自定义网络 服务无法连接数据库,启动失败或 502 错误 所有服务必须在同一个 networks
忘记配置 depends_on 主服务在数据库就绪前启动,连接失败 明确声明服务依赖关系
直接删除 u_user 表数据 残留数据导致登录验证失败 通过官方渠道删除用户,或清空所有关联表

🟡 常见陷阱(会导致登录失败)

陷阱 现象 解决方法
数据库存在重复的 email TooManyResultsException 确保 u_user.email 唯一
残留的设备绑定记录 新账号无法登录 清空 e_user_equipmente_equipment_authorize
容器启动顺序问题 数据库连接超时 使用 depends_on 确保顺序

🟢 最佳实践

  1. 使用自定义网络:所有服务都需要显式声明加入同一个网络,这是最常见的问题根源
  2. 数据持久化:使用 volumes 映射数据目录,避免容器删除导致数据丢失
  3. 设备绑定与恢复
    • 备份:USB 完整复制 + 官方云同步(双重保险)
    • 恢复出厂设置前:务必备份所有文件
    • 恢复后:设备会作为新设备绑定,数据从设备同步到私有云
  4. 端口说明
    • 19072:Web 管理界面(映射容器 8080)
    • 18072:设备同步服务

六、结语

回顾这次 48 小时的折腾,最初的几小时都在错误的方向上浪费时间——以为删掉重复用户就能解决,结果发现还有 26 张表需要清理;以为清空所有表就能重新开始,结果发现网络配置才是根本问题。

最深刻的教训是:当一个问题持续无解时,要敢于怀疑最初的假设TooManyResultsException 并不一定意味着数据库真的有多条记录,也可能是服务根本没有正确连接到数据库。

另外,Supernote 设备端的备份机制有很强的误导性。那个 15MB 的“备份”只包含摘录,不包含你的千辛万苦写下的笔记。完整备份必须通过 USB 连接电脑,直接复制所有文件夹。

希望这篇文章能帮助你避开我踩过的坑。如果你也在自建 Supernote 私有云,建议先在测试环境验证网络配置的正确性,再投入正式使用。


最后更新:2026年5月

更多推荐