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 命令作为一致的数据库备份解决方案。
加密修改备份脚本以集成静态加密以增强安全性。
灾难恢复和测试制定灾难恢复计划并定期测试备份和恢复过程。
替代备份工具探索其他命令行备份工具,如 borgbackup 或 restic 以获得高级功能。
电子邮件通知和 Webhooks实施电子邮件通知或 webhooks 来监控备份成功或失败。