OpenWebUI

目前最强大的AI前后端(但是也很吃性能)

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),然后替换即可

但是需要自己搭建数据库,并且服务器到期之后需要手动迁移数据库,先说说怎么搭建:

PostgreSQL官网下载页:https://www.postgresql.org/download/

Ubuntu直接安装即可:

apt install postgresql

如果要安装别的版本的下方也有教程,不过还有一种方案是也在同一个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 即可:

crontab -e

默认使用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

然后检查一下系统时区设置:

timedatectl status

超级进阶配置

自动备份数据库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

数据库清理

当我逐步壮大到拥有了600用户之后,每天产生的聊天记录就有超过3GB,同时也会有很多无关的人注册,这时就需要通过数据库清理来提高系统的稳定性了。

首先进入容器数据库(如果是本地安装就不需要):

docker exec -it postgre bash
psql -U st -d openwebui

清理所有未激活的用户:

DELETE FROM "user" WHERE role = 'pending';

清理所有超过10天未登录的用户(但是排除某些特定用户):

DELETE FROM "user"
WHERE last_active_at < EXTRACT(EPOCH FROM NOW()) - (10 * 24 * 60 * 60)
AND name NOT IN ('wyk', 'wwf');

清理所有超过7天未更新、且未归档、未置顶的聊天记录:

DELETE FROM chat
WHERE
    updated_at <= EXTRACT(EPOCH FROM DATE_TRUNC('day', NOW() - INTERVAL '7 day'))::INTEGER
    AND pinned = false
    AND archived = false;

一些脚本汇总

上面有很多的条目,找起来可能比较繁琐,并且我陆续将很多命令都整合成了sh脚本,方便运行。

数据库清理脚本(仅适用于docker容器安装的数据库,直接进入docker,因此与端口无关):

#!/bin/bash

# 定义Docker容器名称和PostgreSQL用户
CONTAINER_NAME="postgre"
PG_USER="st"
DATABASE_NAME="openwebui" # 假设数据库名为 openwebui,如果不是,请修改

# 清理待审核用户
echo "清理待审核用户..."
docker exec -it ${CONTAINER_NAME} psql -U ${PG_USER} -d ${DATABASE_NAME} -c "DELETE FROM \"user\" WHERE role = 'pending';"

# 清理长时间未活跃的用户 (14天)
echo "清理长时间未活跃的用户 (14天)..."
docker exec -it ${CONTAINER_NAME} psql -U ${PG_USER} -d ${DATABASE_NAME} -c "DELETE FROM \"user\" WHERE last_active_at < EXTRACT(EPOCH FROM NOW()) - (14 * 24 * 60 * 60) AND name NOT IN ('wyk', 'wwf','syx');"

# 清理10天前未置顶和未归档的聊天记录
echo "清理10天前未置顶和未归档的聊天记录..."
docker exec -it ${CONTAINER_NAME} psql -U ${PG_USER} -d ${DATABASE_NAME} -c "DELETE FROM chat WHERE updated_at <= EXTRACT(EPOCH FROM DATE_TRUNC('day', NOW() - INTERVAL '10 day'))::INTEGER AND pinned = false AND archived = false;"

echo "数据库清理完成。"

本地备份脚本(备份到本地data数据盘/backup目录,并仅保留最近3天的备份):

#!/bin/bash

# --- 本地 PostgreSQL 数据库配置 ---
# 要备份的数据库所在的主机(本地)
LOCAL_PG_HOST="127.0.0.1"
# 本地 PostgreSQL 服务的端口
LOCAL_PG_PORT="3333"
# 要备份的数据库名称
POSTGRESQL_DBNAME="openwebui"
# 连接数据库的用户名
POSTGRESQL_USERNAME="st"
# 连接数据库的密码 (建议使用 .pgpass 文件或环境变量等更安全的方式)
POSTGRESQL_PASSWORD="STshentong"

# --- 备份目的地配置 ---
# 备份文件存储的目录
BACKUP_DEST_DIR="/data/backup"
# 备份文件名格式 (包含时间戳)
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# 最终的备份文件完整路径 (使用 .dump 扩展名,并采用 custom 格式)
BACKUP_FILE_PATH="${BACKUP_DEST_DIR}/openwebui_${TIMESTAMP}.dump"

# --- 主逻辑 ---

# 1. 确保备份目标目录存在
echo "检查并创建备份目录 ${BACKUP_DEST_DIR}..."
mkdir -p "${BACKUP_DEST_DIR}"
if [ $? -ne 0 ]; then
    echo "错误:无法创建备份目录 ${BACKUP_DEST_DIR}!"
    exit 1
fi
echo "备份目录准备就绪。"

# 2. 执行本地数据库备份 (使用 pg_dump)
echo "开始备份本地 PostgreSQL 数据库 (${POSTGRESQL_DBNAME}) 到 ${BACKUP_FILE_PATH}..."
echo "连接信息: Host=${LOCAL_PG_HOST}, Port=${LOCAL_PG_PORT}, User=${POSTGRESQL_USERNAME}"

# 设置 PGPASSWORD 环境变量,pg_dump 会自动使用它
export PGPASSWORD="${POSTGRESQL_PASSWORD}"

pg_dump \
    -h "${LOCAL_PG_HOST}" \
    -p "${LOCAL_PG_PORT}" \
    -U "${POSTGRESQL_USERNAME}" \
    -d "${POSTGRESQL_DBNAME}" \
    -Fc \
    -f "${BACKUP_FILE_PATH}"

# 检查 pg_dump 的退出状态
if [ $? -eq 0 ]; then
    echo "数据库备份成功!"
    echo "备份文件已保存到: ${BACKUP_FILE_PATH}"
else
    echo "错误:数据库备份失败!"
    # 可选:删除可能不完整的备份文件
    rm -f "${BACKUP_FILE_PATH}"
    # 取消设置 PGPASSWORD 环境变量
    unset PGPASSWORD
    exit 1
fi

# 取消设置 PGPASSWORD 环境变量
unset PGPASSWORD

# 3. 可选:清理旧的备份文件 (例如,删除超过3天的备份)
echo "开始清理旧备份文件 (保留最近3天)..."
# -mtime +3: 查找修改时间在3天之前的文件
find "${BACKUP_DEST_DIR}" -name "openwebui_*.dump" -type f -mtime +2 -print -delete
echo "旧备份清理完成。"

echo "--- 备份脚本执行完毕 ---"
exit 0

数据库恢复脚本(需指定恢复文件,调整线程数):

#!/bin/bash
set -e # If any command fails, immediately exit the script

# --- Configuration (Specific to this target server) ---
POSTGRESQL_DBNAME="openwebui"
POSTGRESQL_USERNAME="st"
# !!! Ensure this password is correct for the 'st' DATABASE user !!!
POSTGRESQL_PASSWORD="STshentong"

# --- Connection Info (Running locally) ---
TARGET_HOST="127.0.0.1"
# !!! Port for the PostgreSQL instance on THIS server !!!
TARGET_PORT="3333"

# --- Backup File Path (Located in /root directory on THIS server) ---
# !!! Modified to point to the /root directory !!!
BACKUP_FILE_PATH="/data/openwebui_20250505_020001.dump"

# --- pg_restore Configuration ---
# Adjusted for an 8-core server, you can tweak this (e.g., 6 or 8)
PG_RESTORE_JOBS=8

# --- Restore Logic ---
echo "--- Starting local restore process on ${TARGET_HOST}:${TARGET_PORT} ---"
echo "Running script as OS user: $(whoami)"
echo "Connecting to DB as PostgreSQL user: ${POSTGRESQL_USERNAME}"
echo "Using backup file: ${BACKUP_FILE_PATH}"

# Check if backup file exists
if [ ! -f "${BACKUP_FILE_PATH}" ]; then
    echo "ERROR: Backup file not found at ${BACKUP_FILE_PATH}"
    exit 1
fi

# --- Attempt to terminate existing connections ---
echo "[${TARGET_HOST}:${TARGET_PORT}] Attempting to terminate existing connections to database ${POSTGRESQL_DBNAME}..."
TERMINATE_SQL="SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${POSTGRESQL_DBNAME}' AND pid <> pg_backend_pid();"
# IMPORTANT: The DATABASE user '${POSTGRESQL_USERNAME}' needs permission for this,
# even if the script runs as the OS 'root' user.
if ! PGPASSWORD="${POSTGRESQL_PASSWORD}" psql \
    --host "${TARGET_HOST}" \
    --port "${TARGET_PORT}" \
    --username "${POSTGRESQL_USERNAME}" \
    --dbname "postgres" \
    -tAc "${TERMINATE_SQL}" > /dev/null; then
    echo "[${TARGET_HOST}:${TARGET_PORT}] WARNING: Failed to execute terminate command (maybe no connections, insufficient DB permissions for user '${POSTGRESQL_USERNAME}', or failed to connect to 'postgres' DB). Continuing..."
else
    echo "[${TARGET_HOST}:${TARGET_PORT}] Terminate command sent successfully."
    sleep 3
fi

# --- Drop Database ---
echo "[${TARGET_HOST}:${TARGET_PORT}] Attempting to drop database ${POSTGRESQL_DBNAME} (if it exists)..."
# The DATABASE user '${POSTGRESQL_USERNAME}' needs permission for this.
# Consider using --force if PG >= 13 and DB user has permissions.
if PGPASSWORD="${POSTGRESQL_PASSWORD}" dropdb \
    --host "${TARGET_HOST}" \
    --port "${TARGET_PORT}" \
    --username "${POSTGRESQL_USERNAME}" \
    --if-exists \
    "${POSTGRESQL_DBNAME}"; then
    echo "[${TARGET_HOST}:${TARGET_PORT}] Database dropped or did not exist."
else
     echo "[${TARGET_HOST}:${TARGET_PORT}] WARNING: dropdb failed. Continuing to attempt creation (will fail if DB still exists)..."
     # set -e will likely cause script exit here if dropdb truly failed and DB still exists before createdb
fi

# --- Create Database ---
echo "[${TARGET_HOST}:${TARGET_PORT}] Attempting to create database ${POSTGRESQL_DBNAME}..."
# The DATABASE user '${POSTGRESQL_USERNAME}' needs CREATEDB privilege or similar.
PGPASSWORD="${POSTGRESQL_PASSWORD}" createdb \
    --host "${TARGET_HOST}" \
    --port "${TARGET_PORT}" \
    --username "${POSTGRESQL_USERNAME}" \
    "${POSTGRESQL_DBNAME}"
echo "[${TARGET_HOST}:${TARGET_PORT}] Database creation successful."

# --- Execute Restore ---
echo "[${TARGET_HOST}:${TARGET_PORT}] Starting database restore from local file using ${PG_RESTORE_JOBS} parallel jobs..."
# Using 'time' to measure duration of the restore operation
time PGPASSWORD="${POSTGRESQL_PASSWORD}" pg_restore \
    --host "${TARGET_HOST}" \
    --port "${TARGET_PORT}" \
    --username "${POSTGRESQL_USERNAME}" \
    --dbname "${POSTGRESQL_DBNAME}" \
    --jobs "${PG_RESTORE_JOBS}" \
    --verbose \
    "${BACKUP_FILE_PATH}"

echo "[${TARGET_HOST}:${TARGET_PORT}] Database restore completed!"
exit 0

备份文件迁移脚本:

#!/bin/bash

# 备份文件所在的目录
BACKUP_DIR="/data/backup"
# 目标服务器的SSH用户名
TARGET_USER="st"  # 你的目标用户
# 目标服务器的IP地址或主机名
TARGET_HOST="100.120.194.27"
# 目标目录
TARGET_DIR="/home/st/openwebui_backup"
# 目标服务器的SSH端口
TARGET_PORT="22"
# 目标服务器的密码 - !!! 极不安全 !!!
TARGET_PASSWORD="030722"  # 将这里替换为你的实际密码
# 日志文件
LOG_FILE="/var/log/send_dump.log"

# 检查备份目录是否存在
if [ ! -d "$BACKUP_DIR" ]; then
  echo "$(date) - Error: Backup directory $BACKUP_DIR not found." >> "$LOG_FILE"
  exit 1
fi

# 查找最新的备份文件
# ls -t 按修改时间倒序排列文件
# head -n 1 取第一个文件
SOURCE_FILE=$(ls -t "$BACKUP_DIR"/openwebui_*.dump 2>/dev/null | head -n 1)

# 检查是否找到备份文件
if [ -z "$SOURCE_FILE" ]; then
  echo "$(date) - Error: No backup files found in $BACKUP_DIR." >> "$LOG_FILE"
  exit 1
fi

# 检查源文件是否存在 (再次检查,以防 race condition)
if [ ! -f "$SOURCE_FILE" ]; then
  echo "$(date) - Error: Source file $SOURCE_FILE not found after selection." >> "$LOG_FILE"
  exit 1
fi

echo "$(date) - Found latest backup file: $SOURCE_FILE" >> "$LOG_FILE"

# 使用 sshpass 结合 scp 命令传输文件
# -p 参数指定 sshpass 的密码
# scp -P 指定 scp 的端口
sshpass -p "$TARGET_PASSWORD" scp -P "$TARGET_PORT" -q "$SOURCE_FILE" "$TARGET_USER@$TARGET_HOST:$TARGET_DIR/" 2>> "$LOG_FILE"

# 检查 scp 命令的退出状态
if [ $? -eq 0 ]; then
  echo "$(date) - Successfully sent $SOURCE_FILE to $TARGET_USER@$TARGET_HOST:$TARGET_DIR/" >> "$LOG_FILE"
else
  echo "$(date) - Error sending $SOURCE_FILE to $TARGET_USER@$TARGET_HOST:$TARGET_DIR/" >> "$LOG_FILE"
  exit 1
fi

exit 0

这个命令需要安装sshpass ,直接 apt-get install sshpass即可

最后更新于