跳到主要内容

备份您的实例

注意

本教程为社区贡献,Open WebUI 团队不提供官方支持。它仅作为如何针对特定用例自定义 Open WebUI 的演示。想要贡献?请查看贡献教程。

没人喜欢丢失数据!

如果您是自托管(Self-hosting)Open WebUI,您可能希望制定某种正式的备份计划,以确保您保留配置各个部分的第二和第三副本。

本指南旨在为用户如何进行备份提供一些基本建议。

本指南假设用户已通过 Docker 安装了 Open WebUI(或打算这样做)。

确保数据持久化

首先,在使用 Docker 部署您的技术栈之前,请确保您的 Docker Compose 使用了持久化数据存储。如果您使用的是 来自 GitHub 仓库的 Docker Compose,这一点已经处理好了。但自己编写变体并忘记验证这一点是很容易发生的。

Docker 容器是临时的,数据必须持久化才能确保其在宿主机文件系统上存活。

使用 Docker volumes

如果您使用的是项目仓库中的 Docker Compose,您将使用 Docker volumes 部署 Open WebUI。

对于 Ollama 和 Open WebUI,挂载路径为:

ollama:
  volumes:
    - ollama:/root/.ollama
open-webui:
  volumes:
    - open-webui:/app/backend/data

要查找宿主机上的实际绑定路径,请运行:

docker volume inspect ollama

以及

docker volume inspect open-webui

使用直接宿主机绑定

一些用户在部署 Open WebUI时,会直接(固定)绑定到宿主机文件系统,如下所示:

services:
   ollama:
     container_name: ollama
     image: ollama/ollama:${OLLAMA_DOCKER_TAG-latest}
     volumes:
       - /opt/ollama:/root/.ollama
   open-webui:
     container_name: open-webui
     image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main}
     volumes:
       - /opt/open-webui:/app/backend/data

如果这是您部署实例的方式,您需要记录根目录上的路径。

编写备份脚本任务

无论您的实例是如何配置的,都值得检查服务器上的应用数据存储,以了解您将备份哪些数据。您应该会看到类似以下的内容:

├── audit.log
├── cache/
├── uploads/
├── vector_db/
└── webui.db

持久化数据存储中的文件

文件/目录描述
audit.log用于审计事件的日志文件。
cache/用于存储缓存数据的目录。
uploads/用于存储用户上传文件的目录。
vector_db/包含 ChromaDB 向量数据库的目录。
webui.db用于持久化存储其他实例数据的 SQLite 数据库

文件级备份方法

备份应用程序数据的第一种方法是采用文件级备份方法,以确保持久化的 Open WebUI 数据得到妥善备份。

技术服务的备份方式几乎有无限多种,但 rsync 仍然是增量任务的热门首选,因此将在此处进行演示。

用户可以针对整个 data 目录一次性备份所有实例数据,也可以创建更具选择性的备份任务来针对单个组件。您还可以为目标添加更具描述性的名称。

一个典型的 rsync 任务模型如下所示:

#!/bin/bash

# 配置
SOURCE_DIR="."  # 当前目录(文件结构所在目录)
B2_BUCKET="b2://OpenWebUI-backups" # 您的 Backblaze B2 bucket
B2_PROFILE="your_rclone_profile" # 您的 rclone profile 名称

# 确保使用您的 B2 凭证配置了 rclone

# 定义源目录和目标目录
SOURCE_UPLOADS="$SOURCE_DIR/uploads"
SOURCE_VECTORDB="$SOURCE_DIR/vector_db"
SOURCE_WEBUI_DB="$SOURCE_DIR/webui.db"

DEST_UPLOADS="$B2_BUCKET/user_uploads"
DEST_CHROMADB="$B2_BUCKET/ChromaDB"
DEST_MAIN_DB="$B2_BUCKET/main_database"

# 排除 cache 和 audit.log
EXCLUDE_LIST=(
     "cache/"
     "audit.log"
)

# 为 rclone 构建排除参数
EXCLUDE_ARGS=""
for EXCLUDE in "${EXCLUDE_LIST[@]}"; do
     EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude '$EXCLUDE'"
done

# 执行带错误检查的 rclone sync 函数
rclone_sync() {
     SOURCE="$1"
     DEST="$2"
     echo "Syncing '$SOURCE' to '$DEST'..."
     rclone sync "$SOURCE" "$DEST" $EXCLUDE_ARGS --progress --transfers=32 --checkers=16 --profile "$B2_PROFILE"
     if [ $? -ne 0 ]; then
         echo "Error: rclone sync failed for '$SOURCE' to '$DEST'"
         exit 1
     fi
}

# 为每个目录/文件执行 rclone sync
rclone_sync "$SOURCE_UPLOADS" "$DEST_UPLOADS"
rclone_sync "$SOURCE_VECTORDB" "$DEST_CHROMADB"
rclone_sync "$SOURCE_WEBUI_DB" "$DEST_MAIN_DB"

echo "Backup completed successfully."
exit 0

带容器中断的 Rsync 任务

为了保持数据一致性,通常建议在冷文件系统上运行数据库备份。我们默认的模型备份任务可以进行微调,在运行备份脚本之前停止服务栈,并在备份完成后重新启动。

当然,这种方法的缺点是会导致实例停机。考虑在您不使用实例的时间段运行此任务,或者进行“软”日备(针对运行中的数据)和更健壮的周备(针对冷数据)。

#!/bin/bash

# 配置
COMPOSE_FILE="docker-compose.yml" # 您的 docker-compose.yml 文件路径
B2_BUCKET="b2://OpenWebUI-backups" # 您的 Backblaze B2 bucket
B2_PROFILE="your_rclone_profile" # 您的 rclone profile 名称
SOURCE_DIR="."  # 当前目录(文件结构所在目录)

# 定义源目录和目标目录
SOURCE_UPLOADS="$SOURCE_DIR/uploads"
SOURCE_VECTORDB="$SOURCE_DIR/vector_db"
SOURCE_WEBUI_DB="$SOURCE_DIR/webui.db"

DEST_UPLOADS="$B2_BUCKET/user_uploads"
DEST_CHROMADB="$B2_BUCKET/ChromaDB"
DEST_MAIN_DB="$B2_BUCKET/main_database"

# 排除 cache 和 audit.log
EXCLUDE_LIST=(
     "cache/"
     "audit.log"
)

# 为 rclone 构建排除参数
EXCLUDE_ARGS=""
for EXCLUDE in "${EXCLUDE_LIST[@]}"; do
     EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude '$EXCLUDE'"
done

# 执行带错误检查的 rclone sync 函数
rclone_sync() {
     SOURCE="$1"
     DEST="$2"
     echo "Syncing '$SOURCE' to '$DEST'..."
     rclone sync "$SOURCE" "$DEST" $EXCLUDE_ARGS --progress --transfers=32 --checkers=16 --profile "$B2_PROFILE"
     if [ $? -ne 0 ]; then
         echo "Error: rclone sync failed for '$SOURCE' to '$DEST'"
         exit 1
     fi
}

# 1. 停止 Docker Compose 环境
echo "Stopping Docker Compose environment..."
docker-compose -f "$COMPOSE_FILE" down

# 2. 执行备份
echo "Starting backup..."
rclone_sync "$SOURCE_UPLOADS" "$DEST_UPLOADS"
rclone_sync "$SOURCE_VECTORDB" "$DEST_CHROMADB"
rclone_sync "$SOURCE_WEBUI_DB" "$DEST_MAIN_DB"

# 3. 启动 Docker Compose 环境
echo "Starting Docker Compose environment..."
docker-compose -f "$COMPOSE_FILE" up -d

echo "Backup completed successfully."
exit 0

使用 SQLite & ChromaDB 备份函数到 B2 Remote 的模型备份脚本

#!/bin/bash

#
# 备份脚本,用于将 ChromaDB 和 SQLite 备份到 Backblaze B2 bucket
# openwebuiweeklies,保留 3 个每周快照。
# 快照是独立的且完全可恢复的。
# 使用 ChromaDB 和 SQLite 的原生备份机制。
# 排除 audit.log、cache 和 uploads 目录。
#

# 确保已正确安装和配置 rclone。
# 安装 rclone: https://rclone.org/install/
# 配置 rclone: https://rclone.org/b2/

# 源目录(包含 ChromaDB 和 SQLite 数据)
SOURCE="/var/lib/open-webui/data"

# B2 bucket 名称和 remote 名称
B2_REMOTE="openwebuiweeklies"
B2_BUCKET="b2:$B2_REMOTE"

# 备份目录的时间戳
TIMESTAMP=$(date +%Y-%m-%d)

# 备份目录名称
BACKUP_DIR="open-webui-backup-$TIMESTAMP"

# B2 bucket 中备份目录的完整路径
DESTINATION="$B2_BUCKET/$BACKUP_DIR"

# 要保留的每周快照数量
NUM_SNAPSHOTS=3

# 排除过滤器(在数据库备份*之后*应用)
EXCLUDE_FILTERS="--exclude audit.log --exclude cache/** --exclude uploads/** --exclude vector_db"

# ChromaDB 备份设置(根据需要调整)
CHROMADB_DATA_DIR="$SOURCE/vector_db"  # ChromaDB 数据目录路径
CHROMADB_BACKUP_FILE="$SOURCE/chromadb_backup.tar.gz" # ChromaDB 备份的归档文件

# SQLite 备份设置(根据需要调整)
SQLITE_DB_FILE="$SOURCE/webui.db" # SQLite 数据库文件路径
SQLITE_BACKUP_FILE="$SOURCE/webui.db.backup" # SQLite 备份的临时文件

# 备份 ChromaDB 的函数
backup_chromadb() {
   echo "Backing up ChromaDB..."

   # 创建 vector_db 目录的 tar 归档文件
   tar -czvf "$CHROMADB_BACKUP_FILE" -C "$SOURCE" vector_db

   echo "ChromaDB backup complete."
}

# 备份 SQLite 的函数
backup_sqlite() {
   echo "Backing up SQLite database..."
   # 使用 .backup 命令备份 SQLite 数据库
   sqlite3 "$SQLITE_DB_FILE" ".backup '$SQLITE_BACKUP_FILE'"

   # 将备份文件移动到源目录
   mv "$SQLITE_BACKUP_FILE" "$SOURCE/"

   echo "SQLite backup complete."
}

# 执行数据库备份
backup_chromadb
backup_sqlite

# 执行带排除项的备份
rclone copy "$SOURCE" "$DESTINATION" $EXCLUDE_FILTERS --progress

# 删除旧备份,仅保留最近的 NUM_SNAPSHOTS 个
find "$B2_BUCKET" -type d -name "open-webui-backup-*" | sort -r | tail -n +$((NUM_SNAPSHOTS + 1)) | while read dir; do
   rclone purge "$dir"
done

echo "Backup completed to $DESTINATION"

时间点快照

除了进行备份外,用户可能还希望创建可存储在本地(服务器上)、远程或同时存储在两处的时间点快照。

#!/bin/bash

# 配置
SOURCE_DIR="."  # 要创建快照的目录(当前目录)
SNAPSHOT_DIR="/snapshots" # 存储快照的目录
TIMESTAMP=$(date +%Y%m%d%H%M%S) # 生成时间戳

# 如果快照目录不存在,则创建它
mkdir -p "$SNAPSHOT_DIR"

# 创建快照名称
SNAPSHOT_NAME="snapshot_$TIMESTAMP"
SNAPSHOT_PATH="$SNAPSHOT_DIR/$SNAPSHOT_NAME"

# 执行 rsync 快照
echo "Creating snapshot: $SNAPSHOT_PATH"
rsync -av --delete --link-dest="$SNAPSHOT_DIR/$(ls -t "$SNAPSHOT_DIR" | head -n 1)" "$SOURCE_DIR/" "$SNAPSHOT_PATH"

# 检查 rsync 是否成功
if [ $? -eq 0 ]; then
   echo "Snapshot created successfully."
else
   echo "Error: Snapshot creation failed."
   exit 1
fi

exit 0

用于调度的 Crontab

一旦您添加了备份脚本并配置了备份存储,您需要对脚本进行质量保证(QA)测试以确保它们按预期运行。强烈建议记录日志。

根据您期望的运行频率,使用 crontabs 设置您的新脚本。

商业工具

除了编写自己的备份任务脚本之外,您还可以找到商业产品,它们通常通过在您的服务器上安装 agent 来抽离运行备份的复杂性。这些内容超出了本文的范围,但它们提供了便捷的解决方案。


宿主机级备份

您的 Open WebUI 实例可能配置在您控制的宿主机(物理机或虚拟机)上。

宿主机级备份涉及创建整个 VM 的快照或备份,而不是运行中的应用程序。

一些人可能希望将它们作为主要或唯一的保护手段,而另一些人则可能希望将它们作为额外的数据保护层加入。

我需要多少个备份?

您想要保留的备份数量取决于您个人的风险承受能力。但是,请记住,最佳实践是不要将应用程序本身视为备份副本(即使它运行在云端!)。这意味着,如果您在 VPS 上配置了实例,保留两个(独立的)备份副本仍然是一个合理的建议。

一个可以满足许多家庭用户需求的备份方案示例:

模型备份方案 1(主备份 + 2 副本)

频率目标技术描述
每日增量云存储 (S3/B2)rsync每日增量备份,推送到云存储 bucket(S3 或 B2)。
每周增量本地存储 (Home NAS)rsync每周增量备份,从服务器拉取到本地存储(例如家用 NAS)。

模型备份方案 2(主备份 + 3 副本)

这个备份方案稍微复杂一些,但也更全面……它涉及每日推送到两个云存储服务商,以获得额外的冗余。

频率目标技术描述
每日增量云存储 (S3)rsync每日增量备份,推送到 S3 云存储 bucket。
每日增量云存储 (B2)rsync每日增量备份,推送到 Backblaze B2 云存储 bucket。
每周增量本地存储 (Home NAS)rsync每周增量备份,从服务器拉取到本地存储(例如家用 NAS)。

其他主题

为了保持本指南的详尽性,这些额外的主题被省略了,但根据您致力于为实例设置和维护数据保护计划的时间,它们可能值得您考虑:

主题描述
SQLite 内置备份考虑使用 SQLite 的 .backup 命令来获得一致的数据库备份解决方案。
加密修改备份脚本以合并静态加密。有关数据库级加密,请参阅 使用 SQLCipher 进行数据库加密
灾难恢复与测试制定灾难恢复计划并定期测试备份和恢复过程。
替代备份工具探索其他命令行备份工具(如 borgbackuprestic)以获取高级功能。
邮件通知与 Webhooks实现邮件通知或 webhooks,以监控备份成功或失败。
This content is for informational purposes only and does not constitute a warranty, guarantee, or contractual commitment. Open WebUI is provided "as is." See your license for applicable terms.