Skip to main content
warning

本教程是社区贡献,不受 Open WebUI 团队支持。它仅作为如何为您的特定用例自定义 Open WebUI 的演示。想要贡献?查看贡献教程。

备份您的实例

没有人喜欢丢失数据!

如果您正在自托管 Open WebUI,那么您可能希望制定某种正式的备份计划,以确保您保留配置的第二份和第三份副本。

本指南旨在为用户如何执行此操作提供一些基本建议。

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

确保数据持久性

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

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

使用 Docker 卷

如果您使用的是项目存储库中的 Docker Compose,您将使用 Docker 卷部署 Open Web UI。

对于 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 Web UI,如下所示:

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 Web UI 数据得到适当备份。

备份技术服务的方法几乎无限多,但 rsync 仍然是增量作业的热门选择,因此将用作演示。

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

一个模型 rsync 作业可能看起来像这样:

#!/bin/bash

# 配置
SOURCE_DIR="." # 当前目录(文件结构所在位置)
B2_BUCKET="b2://OpenWebUI-backups" # 您的 Backblaze B2 存储桶
B2_PROFILE="your_rclone_profile" # 您的 rclone 配置文件名称
# 确保 rclone 已使用您的 B2 凭据配置

# 定义源和目标目录
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"

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

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

# 执行带错误检查的 rclone 同步函数
rclone_sync() {
SOURCE="$1"
DEST="$2"
echo "正在将 '$SOURCE' 同步到 '$DEST'..."
rclone sync "$SOURCE" "$DEST" $EXCLUDE_ARGS --progress --transfers=32 --checkers=16 --profile "$B2_PROFILE"
if [ $? -ne 0 ]; then
echo "错误:从 '$SOURCE' 到 '$DEST' 的 rclone 同步失败"
exit 1
fi
}

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

echo "备份成功完成。"
exit 0

带容器中断的 Rsync 作业

为了保持数据完整性,通常建议在冷文件系统上运行数据库备份。我们的默认模型备份作业可以稍作修改,在运行备份脚本之前关闭堆栈,然后在之后重新启动。

当然,这种方法的缺点是会导致实例停机。考虑在您不会使用实例的时间运行作业,或者进行"软件"每日备份(在运行数据上)和更稳健的每周备份(在冷数据上)。

#!/bin/bash

# 配置
COMPOSE_FILE="docker-compose.yml" # docker-compose.yml 文件的路径
B2_BUCKET="b2://OpenWebUI-backups" # 您的 Backblaze B2 存储桶
B2_PROFILE="your_rclone_profile" # 您的 rclone 配置文件名称
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"

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

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

# 执行带错误检查的 rclone 同步函数
rclone_sync() {
SOURCE="$1"
DEST="$2"
echo "正在将 '$SOURCE' 同步到 '$DEST'..."
rclone sync "$SOURCE" "$DEST" $EXCLUDE_ARGS --progress --transfers=32 --checkers=16 --profile "$B2_PROFILE"
if [ $? -ne 0 ]; then
echo "错误:从 '$SOURCE' 到 '$DEST' 的 rclone 同步失败"
exit 1
fi
}

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

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

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

echo "备份成功完成。"
exit 0

使用 SQLite 和 ChromaDB 备份函数到 B2 远程的模型备份脚本

#!/bin/bash
#
# 备份脚本,将 ChromaDB 和 SQLite 备份到 Backblaze B2 存储桶
# 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 存储桶名称和远程名称
B2_REMOTE="openwebuiweeklies"
B2_BUCKET="b2:$B2_REMOTE"

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

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

# B2 存储桶中备份目录的完整路径
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 "正在备份 ChromaDB..."

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

echo "ChromaDB 备份完成。"
}

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

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

echo "SQLite 备份完成。"
}

# 执行数据库备份
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 "备份已完成到 $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 "正在创建快照:$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 "快照创建成功。"
else
echo "错误:快照创建失败。"
exit 1
fi

exit 0

用于调度的 Crontab

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

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

商业实用程序

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


主机级备份

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

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

有些人可能希望将它们用作主要或唯一的保护措施,而其他人可能希望将它们作为额外的数据保护层。

我需要多少个备份?

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

一个涵盖许多家庭用户需求的示例备份计划:

模型备份计划 1(主要 + 2 个副本)

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

模型备份计划 2(主要 + 3 个副本)

这个备份计划稍微复杂一些,但也更全面... 它涉及每日推送到两个云存储提供商以获得额外的冗余。

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

其他主题

为了保持本指南的合理完整性,这些附加主题被省略了,但根据您有多少时间专门用于设置和维护实例的数据保护计划,可能值得考虑:

主题描述
SQLite 内置备份考虑使用 SQLite 的 .backup 命令作为一致的数据库备份解决方案。
加密修改备份脚本以集成静态加密以增强安全性。
灾难恢复和测试制定灾难恢复计划并定期测试备份和恢复过程。
替代备份工具探索其他命令行备份工具,如 borgbackuprestic 以获得高级功能。
电子邮件通知和 Webhooks实施电子邮件通知或 webhooks 来监控备份成功或失败。