docker compose:
复制 services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
ports:
- "3000:8080"
volumes:
- open-webui:/app/backend/data
environment:
- STORAGE_PROVIDER=s3
- S3_ACCESS_KEY_ID=581c5b7e7304837ffa6b0c5410e869ed
- S3_BUCKET_NAME=web
- S3_ENDPOINT_URL=https://fccb494a4985b211afbfe26e87e1c7bc.r2.cloudflarestorage.com
- S3_KEY_PREFIX=openwebui
- S3_REGION_NAME=auto
- S3_SECRET_ACCESS_KEY=f40fe409cea27d970660a1abe1fcea06f701d56306adf347bfd26f0c0ed251e2
- DATABASE_URL=postgresql://openwebui_owner:npg_dStx0e3KNgEM@ep-late-snow-a192dz9a-pooler.ap-southeast-1.aws.neon.tech/openwebui?sslmode=require
- ENABLE_WEBSOCKET_SUPPORT=True
- WEBSOCKET_REDIS_URL=redis://redis:6379 # 修改为服务名 "redis"
- REDIS_URL=redis://redis:6379 # 修改为服务名 "redis"
- WEBUI_NAME=ChatWeb ST
- USER_AGENT=${USER_AGENT:-Mozilla/5.0 (compatible; OpenWebUI/1.0; +https://github.com/open-webui)}
build:
args:
USER_AGENT: $USER_AGENT
networks:
- openwebui # 指定自定义网络
depends_on:
- redis # 确保 Redis 先启动
redis: # 新增 Redis 服务
image: redis:latest
container_name: redis
networks:
- openwebui
watchtower:
image: containrrr/watchtower
container_name: open-webui-watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 3600 open-webui
depends_on:
- open-webui
networks:
- openwebui
networks:
openwebui: # 定义自定义网络
driver: bridge
volumes:
open-webui:
经过几天的探索进行的优化,我们特别优化了一个很少有人提及的点,就是OpenWebUI默认会启用langchain但是又没有设置UA,导致会在那一步卡很久,我们设置了UA就成功过了langchain的检查(仅适用于国内服务器配置,海外服务器仍然使用上面的)
如果还想进一步简化,可以去掉S3服务,但是去掉后文件上传等等可能会出现问题,最核心的就是数据库的问题,数据库是影响性能的核心要素,所以我在国内的服务器专门新建了一个postgresql数据库,链接也直接换成了IP的方式,并且去掉了SSL
P.S. 如果是运行在本地的数据库,修改成:host.docker.internal:5432 路径即可(有时候用这个会出现无法连接的情况,那就先用 docker network inspect bridge
查看桥接网络IP(一般是172.17.0.1),然后替换即可
但是需要自己搭建数据库,并且服务器到期之后需要手动迁移数据库,先说说怎么搭建:
Ubuntu直接安装即可:
如果要安装别的版本的下方也有教程,不过还有一种方案是也在同一个docker网络中进行安装,示例如下:
复制 services:
postgre: # 新增 PostgreSQL 服务
image: docker.1panel.live/library/postgres:latest
container_name: postgre
restart: always
environment:
- POSTGRES_USER=st
- POSTGRES_PASSWORD=STshentong
- POSTGRES_DB=openwebui
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- openwebui
open-webui:
image: docker.1panel.live/dyrnq/open-webui:latest
container_name: open-webui
ports:
- "3000:8080"
volumes:
- open-webui:/app/backend/data
restart: always
environment:
- STORAGE_PROVIDER=s3
- S3_ACCESS_KEY_ID=581c5b7e7304837ffa6b0c5410e869ed
- S3_BUCKET_NAME=box
- S3_ENDPOINT_URL=https://fccb494a4985b211afbfe26e87e1c7bc.r2.cloudflarestorage.com
- S3_KEY_PREFIX=openwebui
- S3_REGION_NAME=auto
- S3_SECRET_ACCESS_KEY=f40fe409cea27d970660a1abe1fcea06f701d56306adf347bfd26f0c0ed251e2
- DATABASE_URL=postgresql://st:STshentong@postgre:5432/openwebui # 修改为本地 PostgreSQL
- ENABLE_WEBSOCKET_SUPPORT=True
- WEBSOCKET_REDIS_URL=redis://redis:6379
- REDIS_URL=redis://redis:6379
- WEBUI_NAME=ChatWeb ST
- AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST=1
- AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST=1
- USER_AGENT=${USER_AGENT:-Mozilla/5.0 (compatible; OpenWebUI/1.0; +https://github.com/open-webui)}
build:
args:
USER_AGENT: $USER_AGENT
networks:
- openwebui
depends_on:
- postgre # 确保 PostgreSQL 先启动
- redis
redis:
image: docker.1panel.live/library/redis:latest
container_name: redis
restart: always
networks:
- openwebui
watchtower:
image: docker.1panel.live/containrrr/watchtower
container_name: open-webui-watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 3600 open-webui
depends_on:
- open-webui
networks:
- openwebui
networks:
openwebui:
driver: bridge
volumes:
open-webui:
postgres_data:
外部也同样可以通过5432端口访问数据库,同样可以借助DBreaver进行备份和恢复(另外,如果要指定版本,将latest标签改成16即可)
(本地部署,不方便)但是Ubuntu版本不同的情况下,自带的软件仓库中的PostgreSQL版本也不同,如果要为了迁移时保证版本相同来最大化兼容性,建议用官方仓库指定版本,比如我开始部署时的最新版本17:
复制 # 1. 下载并保存密钥到 trusted.gpg.d 目录
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/trusted.gpg.d/postgresql.asc.gpg > /dev/null
# 2. 添加仓库源
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list
# 3. 更新包列表并安装
sudo apt update && sudo apt install postgresql-17
安装完成后验证一下服务状态:
复制 sudo systemctl status postgresql
然后需要修改配置文件(路径:/etc/postgresql/版本号/main/postgresql.conf)
复制 listen_addresses = '*' # 允许所有IP连接
port = 5432 # 默认端口
修改连接认证文件(路径同上,文件名pg_hba.conf),用这些把原有的规则全部替换掉:
复制 # Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# 本地 Unix 套接字连接(使用 md5 密码认证)
local all all password
# IPv4 网络连接(允许所有 IP,使用 md5 认证)
host all all 0.0.0.0/0 password
# IPv6 网络连接(允许所有 IP,使用 md5 认证)
host all all ::/0 password
重启服务让配置生效:
复制 sudo systemctl restart postgresql
然后创建用户和数据库:
复制 sudo -u postgres psql
CREATE USER st WITH PASSWORD 'STshentong';
CREATE DATABASE openwebui OWNER st;
GRANT ALL PRIVILEGES ON DATABASE openwebui TO st;
然后就可以用DBeaver连接数据库了,连接后可以对数据库进行备份、恢复等操作
在备份PostgreSQL数据库时,强烈建议备份成PostgreSQL专属的 .backup 格式而不是 .sql 格式,兼容性会好很多,只是恢复时稍微麻烦些。使用DBeaver备份时,如下图所示,格式选择Custom,并在文件名后自行加上后缀 .backup 不然默认会备份成 .sql 格式。
得到 backup 文件后,可以直接在DBreaver进行恢复,但在某些特殊的情景下,需要到服务器的终端进行恢复,SSH链接服务器后,将备份文件上传,然后使用 pg_restore 命令进行恢复(需要注意要先创建openwebui数据库):
复制 pg_restore -U st -d openwebui -h localhost -p 5432 --clean /root/backup.backup
输入密码即可覆盖恢复,注意这里的 --clean命令会清除原先数据库中的所有内容,来确保恢复时不会产生冲突。
一些另外的附加事项:
经过实际使用发现这个项目容器运行久了会变得非常卡顿,重启容器即可恢复,对于大多数服务器,直接使用 crontab 即可:
默认使用nano编辑,直接在末尾添加:
复制 0 3 * * * /usr/local/bin/docker restart open-webui
添加后按 Ctrl+O 保存,回车确认,然后 Ctrl+X 退出编辑器。注意这里的路径是docker服务的路径,使用命令 which docker
即可查看,多数机器一般是没有local的。这个crontab的意思是在每天凌晨3点重启容器。
对于一些比较特别的机器,无法使用crontab的(比如腾讯Cloud Studio),我的解决方案是使用另一台服务器,创建SSH连接脚本,然后使用crontab自动化执行,具体如下:
创建 restart.sh 文件,填入脚本(注意替换成实际的SSH连接命令):
复制 #!/bin/bash
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no b5d478c55f6199d68d75cb21b26f66af2467f033-bhqknx@bhqknx.88q5n6vn.ssh.cloudstudio.work 'docker restart open-webui'
然后再到crontab中创建自动执行该脚本的计划:
复制 0 3 * * * /root/restart.sh
另外顺便讲讲 CloudStudio保活 也是这个思路,使用脚本:
复制 #!/bin/bash
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no b5d478c55f6199d68d75cb21b26f66af2467f033-bhqknx@bhqknx.88q5n6vn.ssh.cloudstudio.work 'date'
创建每分钟连接SSH的计划:
复制 * * * * * /root/keep_alive.sh
不过要注意在设置这些重启计划时有一个细节,就是要注意系统时间,大多数Ubuntu系统默认使用的是UTC标准时间,可以使用 date 命令查看当前时间,修改成北京时间如下:
复制 sudo timedatectl set-timezone Asia/Shanghai
然后检查一下系统时区设置:
超级进阶配置
自动备份数据库backup脚本(注意修改本地保存路径):
复制 #!/bin/bash
# 定义PostgreSQL连接信息
POSTGRESQL_HOST="8.148.7.85"
POSTGRESQL_PORT="5432"
POSTGRESQL_DBNAME="openwebui"
POSTGRESQL_USERNAME="st"
POSTGRESQL_PASSWORD="STshentong"
# 定义备份文件路径
BACKUP_DIR="/home/st/openwebui_backup"
BACKUP_FILE="${BACKUP_DIR}/openwebui.backup"
# 确保备份目录存在
mkdir -p "${BACKUP_DIR}"
if [ $? -ne 0 ]; then
echo "创建备份目录失败!"
exit 1
fi
# 备份PostgreSQL数据库
echo "开始备份PostgreSQL数据库..."
PGPASSWORD="${POSTGRESQL_PASSWORD}" pg_dump -h "${POSTGRESQL_HOST}" -p "${POSTGRESQL_PORT}" -U "${POSTGRESQL_USERNAME}" -d "${POSTGRESQL_DBNAME}" > "${BACKUP_FILE}"
if [ $? -ne 0 ]; then
echo "备份失败!"
exit 1
fi
echo "备份完成! 备份文件保存到: ${BACKUP_FILE}"
这是我写的一个在一台服务器上自动连接到主数据库进行备份的脚本,备份文件会自动覆盖到S3兼容的R2对象存储。运行脚本的环境需要安装awscli和postgresql客户端工具:(对于海外服务器)
复制 sudo apt-get update && sudo apt-get install -y postgresql-client
(对于国内服务器使用阿里云镜像安装postgresql客户端工具)
复制 sudo sed -i 's/https:\/\/mirrors.aliyun.com/http:\/\/deb.debian.org/g' /etc/apt/sources.list
#使用阿里云镜像
sudo sh -c 'echo "deb https://mirrors.aliyun.com/ubuntu/ $(lsb_release -cs) main restricted" > /etc/apt/sources.list'
sudo sh -c 'echo "deb-src https://mirrors.aliyun.com/ubuntu/ $(lsb_release -cs) main restricted" >> /etc/apt/sources.list'
sudo sh -c 'echo "deb https://mirrors.aliyun.com/ubuntu/ $(lsb_release -cs) universe multiverse" >> /etc/apt/sources.list'
sudo apt update
#使用阿里云镜像安装
sudo sh -c 'echo "deb https://mirrors.aliyun.com/ubuntu/ $(lsb_release -cs) main restricted" >> /etc/apt/sources.list'
sudo apt update
sudo apt install -y postgresql-client
#验证版本:
pg_dump --version
不过这里需要注意的是阿里云的镜像仓库貌似没有17版本的客户端,还是要用官方仓库安装:
复制 #清除错误的仓库(若有)
sudo rm /etc/apt/sources.list.d/pgdg.list
sudo rm /etc/apt/sources.list.d/postgresql.list
#添加官方仓库
sudo sh -c 'echo "deb [arch=amd64] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
#更新包列表并安装
sudo apt-get update
sudo apt-get install postgresql-client-17
#验证版本号
psql --version
环境配置完成后需要给脚本权限然后运行:
复制 chmod +x backup.sh
./backup.sh
自动恢复backup文件到其他服务器数据库脚本(请自行替换链接地址):
复制 #!/bin/bash
declare -A POSTGRESQL_HOSTS=(
["127.0.0.1"]="5432"
["115.175.29.237"]="5432"
["222.187.254.73"]="10212"
)
POSTGRESQL_DBNAME="openwebui"
POSTGRESQL_USERNAME="st"
POSTGRESQL_PASSWORD="STshentong"
BACKUP_DIR="/home/st/openwebui_backup"
BACKUP_FILE="${BACKUP_DIR}/openwebui.backup"
for HOST in "${!POSTGRESQL_HOSTS[@]}"; do
PORT="${POSTGRESQL_HOSTS[$HOST]}"
echo "开始清空数据库: ${HOST}:${PORT}"
# 使用 dropdb 删除数据库(需确保无活跃连接)
PGPASSWORD="${POSTGRESQL_PASSWORD}" dropdb \
--host "${HOST}" \
--port "${PORT}" \
--username "${POSTGRESQL_USERNAME}" \
"${POSTGRESQL_DBNAME}"
# 重新创建空数据库
PGPASSWORD="${POSTGRESQL_PASSWORD}" createdb \
--host "${HOST}" \
--port "${PORT}" \
--username "${POSTGRESQL_USERNAME}" \
"${POSTGRESQL_DBNAME}"
echo "开始恢复数据库到服务器: ${HOST}:${PORT}"
PGPASSWORD="${POSTGRESQL_PASSWORD}" psql \
--host "${HOST}" \
--port "${PORT}" \
--username "${POSTGRESQL_USERNAME}" \
--dbname "${POSTGRESQL_DBNAME}" \
-f "${BACKUP_FILE}"
done
同样的也要记得先赋予权限:
复制 chmod +x restore.sh
./restore.sh
如果这两个脚本测试运行一段时间都没有问题的话还可以整合起来成一个 sync.sh,下面这个脚本进行了很多改进,包括并行处理(需要根据你运行该脚本的服务器内核数调整并行处理数)、时间戳多版本管理、dump自定义压缩等,大大加快了整体执行速度:
复制 #!/bin/bash
# PostgreSQL数据库配置
POSTGRESQL_DBNAME="openwebui"
POSTGRESQL_USERNAME="st"
POSTGRESQL_PASSWORD="STshentong"
# 备份源服务器配置
BACKUP_HOST="115.175.29.237"
BACKUP_PORT="5432"
BACKUP_DIR="/home/st/openwebui_backup"
# 修改备份文件名以反映格式变化,并添加时间戳(可选但推荐)
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/openwebui_${TIMESTAMP}.dump" # 使用 .dump 或 .backupc 作为后缀
# 恢复目标服务器配置
declare -A RESTORE_HOSTS=(
["127.0.0.1"]="5432"
#["8.148.7.85"]="5432"
["2404:8c80:82:1056::105"]="5432"
["23.94.255.45"]="5432"
)
# --- 配置项 ---
# pg_restore 并行任务数 (根据目标服务器CPU核心数调整, 比如 2 或 4)
PG_RESTORE_JOBS=4
# 是否并行处理多个目标服务器 (true/false)
PARALLEL_HOST_PROCESSING=true
# --- 函数定义 ---
# 单个服务器的恢复逻辑
restore_single_host() {
local HOST="$1"
local PORT="$2"
local BACKUP_FILE_PATH="$3"
echo "--- 开始处理目标服务器: ${HOST}:${PORT} ---"
# 清空并重建数据库
echo "[${HOST}:${PORT}] 清空并重建数据库..."
if PGPASSWORD="${POSTGRESQL_PASSWORD}" dropdb \
--host "${HOST}" \
--port "${PORT}" \
--username "${POSTGRESQL_USERNAME}" \
"${POSTGRESQL_DBNAME}" --if-exists; then
echo "[${HOST}:${PORT}] 旧数据库已删除。"
else
# dropdb 在数据库不存在时可能返回非0,但我们仍需尝试创建
echo "[${HOST}:${PORT}] 删除数据库失败或数据库不存在,继续尝试创建..."
fi
if PGPASSWORD="${POSTGRESQL_PASSWORD}" createdb \
--host "${HOST}" \
--port "${PORT}" \
--username "${POSTGRESQL_USERNAME}" \
"${POSTGRESQL_DBNAME}"; then
echo "[${HOST}:${PORT}] 数据库 ${POSTGRESQL_DBNAME} 创建成功。"
else
echo "[${HOST}:${PORT}] 创建数据库失败! 跳过此服务器..."
return 1 # 返回错误码
fi
# 恢复数据库 (使用 pg_restore)
echo "[${HOST}:${PORT}] 开始恢复数据库 (使用 ${PG_RESTORE_JOBS} 个并行任务)..."
if PGPASSWORD="${POSTGRESQL_PASSWORD}" pg_restore \
--host "${HOST}" \
--port "${PORT}" \
--username "${POSTGRESQL_USERNAME}" \
--dbname "${POSTGRESQL_DBNAME}" \
--jobs "${PG_RESTORE_JOBS}" \
--verbose \
"${BACKUP_FILE_PATH}"; then # 不再需要 -f,直接给文件名
echo "[${HOST}:${PORT}] 数据库恢复完成!"
return 0 # 返回成功码
else
echo "[${HOST}:${PORT}] 恢复数据库失败!"
return 1 # 返回错误码
fi
}
# --- 主逻辑 ---
# 创建备份目录
echo "创建备份目录 ${BACKUP_DIR}..."
mkdir -p "${BACKUP_DIR}" || {
echo "创建备份目录失败!"
exit 1
}
# 备份数据库 (使用 -Fc 自定义格式)
echo "开始备份PostgreSQL数据库从 ${BACKUP_HOST}:${BACKUP_PORT} (格式: custom)..."
if PGPASSWORD="${POSTGRESQL_PASSWORD}" pg_dump \
-h "${BACKUP_HOST}" \
-p "${BACKUP_PORT}" \
-U "${POSTGRESQL_USERNAME}" \
-d "${POSTGRESQL_DBNAME}" \
-Fc \
-f "${BACKUP_FILE}"; then # 使用 -f 指定输出文件
echo "备份完成! 备份文件保存到: ${BACKUP_FILE}"
else
echo "备份失败!"
# 可选:删除可能不完整的备份文件
rm -f "${BACKUP_FILE}"
exit 1
fi
# 恢复数据库到所有目标服务器
echo -e "\n开始恢复数据库到目标服务器..."
declare -A PIDS # 用于存储后台进程PID
declare -A FAILED_HOSTS # 用于记录失败的主机
if [ "$PARALLEL_HOST_PROCESSING" = true ]; then
echo "模式: 并行处理多个目标服务器"
for HOST in "${!RESTORE_HOSTS[@]}"; do
PORT="${RESTORE_HOSTS[$HOST]}"
# 在后台运行恢复函数
restore_single_host "$HOST" "$PORT" "$BACKUP_FILE" &
PIDS["$HOST:$PORT"]=$! # 存储PID
done
# 等待所有后台恢复进程完成,并检查退出状态
for HOST_PORT in "${!PIDS[@]}"; do
wait "${PIDS[$HOST_PORT]}"
if [ $? -ne 0 ]; then
echo "错误: 主机 ${HOST_PORT} 的恢复进程失败。"
FAILED_HOSTS["$HOST_PORT"]=1
fi
done
else
echo "模式: 顺序处理目标服务器"
for HOST in "${!RESTORE_HOSTS[@]}"; do
PORT="${RESTORE_HOSTS[$HOST]}"
if ! restore_single_host "$HOST" "$PORT" "$BACKUP_FILE"; then
FAILED_HOSTS["$HOST:$PORT"]=1
fi
done
fi
# --- 总结 ---
echo -e "\n--- 所有操作完成 ---"
if [ ${#FAILED_HOSTS[@]} -eq 0 ]; then
echo "所有目标服务器均已成功恢复。"
else
echo "以下服务器在恢复过程中遇到错误:"
for FAILED in "${!FAILED_HOSTS[@]}"; do
echo " - ${FAILED}"
done
exit 1 # 以失败状态退出
fi
# 可选:清理旧的备份文件 (保留最近N个)
echo "清理旧备份..."
find "${BACKUP_DIR}" -name "openwebui_*.dump" -type f -mtime +7 -delete # 删除7天前的备份
exit 0
同样的也要记得先赋予权限:
复制 chmod +x sync.sh
./sync.sh
然后可以添加crontab自动执行(比如我下面的每天凌晨0点30自动执行):
复制 30 0 * * * /home/st/sync.sh