基于1Panel搭建LobeChat 服务端数据库版本

基于1Panel搭建LobeChat 服务端数据库版本

此版本独立安装PostgreSQL、(Casdoor或Logto),使用Cloudflare R2 进行替代S3进行存储。

我们先安装PostgreSQL和身份验证(Casdoor或Logto二选一)

域名和配套服务端口说明如下:

  • https://chat.xxx.com, LobeChat 服务端域名,需要反向代理到 LobeChat 服务端口,默认为 3210
  • https://auth.xxx.com, Logto 服务端域名,需要反向代理到 Logto API 服务端口,默认为 3003
  • https://auth-admin.xxx.com, Logto UI 域名,需要反向代理到 Logto WebUI 服务端口,默认为 3004
  • https://chat.xxx.com/api/auth/callback/logto, Logto重定向网址
  • https://casdoor-cdn.xxx.com,Casdoor S3 访问网址
  • https://s3-for-chat.xxx.com, LobeChat S3 公开访问网址

PostgreSQL

由于其他服务也需要使用PostgreSQL,所以就不重复安装PostgreSQL容器,多个业务使用同一个容器的不同数据库即可。
LobeChat需要使用pgvector,所以我在安装PostgreSQL的时候直接使用LobeChat推荐的镜像:pgvector/pgvector:pg16,直接使用1Panel应用商店进行安装,在安装的时候勾上编辑 compose 文件,然后将镜像更换一下安装即可。

PostgreSQL安装

身份证验证

Casdoor

docker-compose.yml

services:
  casdoor:
    image: casbin/casdoor:latest
    ports:
      - "8121:8000"
    volumes:
      - ./app.conf:/conf/app.conf

    networks:
      - 1panel-network  # 使用已有的网络

networks:
  1panel-network:  # 引用已存在的网络
    external: true  # 标记为外部网络

app.conf:

appname = casdoor
httpport = 8000
runmode = prod # dev或prod
copyrequestbody = true
driverName = mysql
dataSourceName = casdoor:123456@tcp(1Panel-mysql-bnhU:3306)/ # MySQL信息
dbName = casdoor # 数据库名称
tableNamePrefix =
showSql = false
redisEndpoint =1Panel-redis-hvtn:6379,100,redis_SdrfzC # Redis信息,100是指定数据库,便于后期迁移备份
defaultStorageProvider =
isCloudIntranet = false
authState = "casdoor"
socks5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10
initScore = 0
logPostOnly = true
isUsernameLowered = false
origin = "https://auth.xxx.com" #
originFrontend =
staticBaseUrl = "https://casdoor-cdn.xxx.com"
isDemoMode = false
batchSize = 100
enableErrorMask = false
enableGzip = true
ldapServerPort = 389
radiusServerPort = 1812
radiusSecret = "secret"
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
logConfig = {"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
initDataFile = "./init_data.json"
frontendBaseDir = "../casdoor"

app.conf 主要修改了runmode,dataSourceName,dbName,redisEndpoint,origin,staticBaseUrl,其中staticBaseUrl我设置的是cloudflare R2的访问网址。

按照以上配置以后,会出现casdoor后台图片都无法正常显示,所以我把对应的图片都上传到R2,从仓库 https://github.com/casbin/static 里下载对应的图片,将仓库下的flag-iconsimg两个文件夹上传到R2.

CORS策略:

[
  {
    "AllowedOrigins": [
      "https://auth.xxx.com"
    ],
    "AllowedMethods": [
      "GET",
      "PUT",
      "HEAD",
      "POST",
      "DELETE"
    ],
    "AllowedHeaders": [
      "*"
    ]
  }
]

R2FileManager.py

import boto3
import os
from botocore.client import Config
from concurrent.futures import ThreadPoolExecutor, as_completed

# Cloudflare R2 相关配置
R2_ACCESS_KEY_ID = '你的 Access Key ID'
R2_SECRET_ACCESS_KEY = '你的 Secret Access Key'
R2_ENDPOINT_URL = 'https://<你的AccountID>.r2.cloudflarestorage.com'  # 替换 <你的AccountID>
R2_BUCKET_NAME = '你的存储桶名称'

# 创建 S3 兼容的客户端
s3 = boto3.client(
    's3',
    endpoint_url=R2_ENDPOINT_URL,
    aws_access_key_id=R2_ACCESS_KEY_ID,
    aws_secret_access_key=R2_SECRET_ACCESS_KEY,
    config=Config(signature_version='s3v4'),
    region_name='auto'
)

# 上传单个文件到 R2 指定文件夹
def upload_single_file_to_r2(local_file_path, bucket_name, target_folder):
    file_name = os.path.basename(local_file_path)
    r2_key = os.path.join(target_folder, file_name).replace("\\", "/")  # 确保兼容Windows系统路径
    try:
        s3.upload_file(local_file_path, bucket_name, r2_key)
        print(f'文件已上传: {r2_key}')
    except Exception as e:
        print(f'文件上传失败: {r2_key}, 错误: {e}')

# 上传整个文件夹到 R2
def upload_folder_to_r2(local_folder, bucket_name, target_folder, max_workers=5):
    futures = []
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        for root, dirs, files in os.walk(local_folder):
            for file in files:
                local_file_path = os.path.join(root, file)
                relative_path = os.path.relpath(local_file_path, local_folder)
                # 提交任务给线程池
                futures.append(executor.submit(upload_single_file_to_r2, local_file_path, bucket_name, target_folder))

        # 等待所有任务完成
        for future in as_completed(futures):
            future.result()  # 检查任务的执行结果,便于捕获异常

# 删除 R2 中的指定文件
def delete_file_from_r2(bucket_name, target_file_key):
    try:
        s3.delete_object(Bucket=bucket_name, Key=target_file_key)
        print(f'文件已删除: {target_file_key}')
    except Exception as e:
        print(f'删除文件失败: {target_file_key}, 错误: {e}')

# 清空 R2 中指定文件夹的所有文件
def clear_folder_in_r2(bucket_name, target_folder_key):
    try:
        response = s3.list_objects_v2(Bucket=bucket_name, Prefix=target_folder_key)
        if 'Contents' in response:
            files_to_delete = [{'Key': obj['Key']} for obj in response['Contents']]
            delete_response = s3.delete_objects(Bucket=bucket_name, Delete={'Objects': files_to_delete})
            deleted_files = delete_response.get('Deleted', [])
            for file in deleted_files:
                print(f'文件已删除: {file["Key"]}')
        else:
            print(f'文件夹为空或不存在: {target_folder_key}')
    except Exception as e:
        print(f'清空文件夹失败: {target_folder_key}, 错误: {e}')

# 删除 R2 中的文件夹及其所有文件
def delete_folder_in_r2(bucket_name, target_folder_key):
    clear_folder_in_r2(bucket_name, target_folder_key)  # 首先清空文件夹
    try:
        s3.delete_object(Bucket=bucket_name, Key=target_folder_key)
        print(f'文件夹已删除: {target_folder_key}')
    except Exception as e:
        print(f'删除文件夹失败: {target_folder_key}, 错误: {e}')

# 示例调用:
# 上传整个文件夹
upload_folder_to_r2('/Users/UserName/static/img', R2_BUCKET_NAME, 'img/', max_workers=10)

# 上传单个文件
# upload_single_file_to_r2('/path/to/local/file.jpg', R2_BUCKET_NAME, 'img/')

# 删除文件
# delete_file_from_r2(R2_BUCKET_NAME, 'img/somefile.jpg')

# 清空文件夹
# clear_folder_in_r2(R2_BUCKET_NAME, 'img/')

# 删除文件夹
# delete_folder_in_r2(R2_BUCKET_NAME, 'img/')

Logto

docker-compose.yml:

services:
  logto:
    image: svhd/logto
    container_name: logto
    ports:
      - '3003:3001'
      - '3004:3002'
    networks:
      - 1panel-network  # 使用已有的网络
    restart: always
    environment:
      - 'TRUST_PROXY_HEADER=1'
      - 'DB_URL=postgres://logto:123456@postgresql:5432/logto'
      - 'ENDPOINT=https://auth.xxx.com'
      - 'ADMIN_ENDPOINT=https://auth-admin.xxx.com'
    entrypoint: ['sh', '-c', 'npm run cli db seed -- --swe && npm start']

networks:
    1panel-network:  # 引用已存在的网络
      external: true  # 标记为外部网络

反代将3003端口对应auth.xxx.com,3004端口对应auth-admin.xxx.com

创建 Logto 应用

Applications 里创建一个Next.js (App Router) 应用,名称随意

配置 Logto

  • 配置 Redirect URI 为 https://chat.xxx.com/api/auth/callback/logto,`Post sign-out redirect URI` 为 https://chat.xxx.com/
  • 配置 CORS allowed origins 为 https://chat.xxx.com/
    创建成功后, 将 Client IDClient Secret 保存下来。
    配置 Logto

配置环境变量

将获取到的 Client IDClient Secret,设为 LobeChat 环境变量中的 LOGTO_CLIENT_IDLOGTO_CLIENT_SECRET
配置环境变量

配置 LobeChat 环境变量中 LOGTO_ISSUER 为:https://auth.xxx.com/oidc,
在部署 LobeChat 时,你需要配置以下环境变量:

环境变量 类型 描述
NEXT_AUTH_SECRET 必选 用于加密 Auth.js 会话令牌的密钥。您可以使用以下命令生成秘钥: openssl rand -base64 32
NEXT_AUTH_SSO_PROVIDERS 必选 选择 LoboChat 的单点登录提供商。使用 Logto 请填写 logto
LOGTO_CLIENT_ID 必选 Logto App 详情页的 Client ID
LOGTO_CLIENT_SECRET 必选 Logto App 详情页的 Client Secret
LOGTO_ISSUER 必选 Logto 提供程序的 OpenID Connect 颁发者
NEXTAUTH_URL 可选 该 URL 用于指定 Auth.js 在执行 OAuth 验证时的回调地址,当默认生成的重定向地址发生不正确时才需要设置,https://chat.xxx.com/api/auth

更多信息查看官方教程

LobeChat

docker-compose.yml:

services:
  lobe:
    image: lobehub/lobe-chat-database
    container_name: lobe-database
    ports:
      - '3210:3210'
    networks:
      - 1panel-network  # 使用已有的网络
    env_file:
      - .env
    restart: always

volumes:
  data:
    driver: local

networks:
  1panel-network:  # 引用已存在的网络
    external: true  # 标记为外部网络

.env:

# 必填,LobeChat 域名,用于 tRPC 调用
# 请保证此域名在你的 NextAuth 鉴权服务提供商、S3 服务商的 CORS 白名单中
APP_URL=https://chat.xxx.com/

# Postgres 相关,也即 DB 必需的环境变量
# 必填,用于加密敏感信息的密钥,可以使用 openssl rand -base64 32 生成
KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
# 必填,Postgres 数据库连接字符串,用于连接到数据库
# 格式:postgresql://username:password@host:port/dbname,如果你的 pg 实例为 Docker 容器且位于同一 docker-compose 文件中,亦可使用容器名作为 host
DATABASE_URL=postgresql://lobechat:123456@postgresql:5432/lobechat

# NEXT_AUTH 相关,也即鉴权服务必需的环境变量
# 可以使用 auth0、Azure AD、GitHub、Authentik、Zitadel、Logto 等,如有其他接入诉求欢迎提 PR
# 目前支持的鉴权服务提供商请参考:https://lobehub.com/zh/docs/self-hosting/advanced/auth#next-auth
# 如果你有 ACCESS_CODE,请务必清空,我们以 NEXT_AUTH 作为唯一鉴权来源
# 必填,用于 NextAuth 的密钥,可以使用 openssl rand -base64 32 生成
NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
# 必填,指定鉴权服务提供商,这里以 Logto 为例
NEXT_AUTH_SSO_PROVIDERS=logto
# 必填,NextAuth 的 URL,用于 NextAuth 的回调
NEXTAUTH_URL=https://chat.xxx.com/api/auth

# NextAuth 鉴权服务提供商部分,以 Logto 为例
# 其他鉴权服务提供商所需的环境变量,请参考:https://lobehub.com/zh/docs/self-hosting/environment-variables/auth
AUTH_LOGTO_ID=YOUR_LOGTO_CLIENT_ID
AUTH_LOGTO_SECRET=YOUR_LOGTO_CLIENT_SECRET
AUTH_LOGTO_ISSUER=https://auth.xxx.com/oidc

# 代理相关,如果你需要的话(比如你使用 GitHub 作为鉴权服务提供商)
# HTTP_PROXY=http://localhost:7890
# HTTPS_PROXY=http://localhost:7890

# S3 相关,也即非结构化数据(文件、图片等)存储必需的环境变量
# 必填,S3 的 Access Key ID
S3_ACCESS_KEY_ID=YOUR_S3_ACCESS_KEY_ID
# 必填,S3 的 Secret Access Key
S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
# 必填,S3 的 Endpoint,用于服务端/客户端连接到 S3 API
S3_ENDPOINT=https://<cloudflare账户ID>.r2.cloudflarestorage.com
# 必填,S3 的 Bucket
S3_BUCKET=lobe-chat
# 必填,S3 的 Public Domain,用于客户端通过公开连接访问非结构化数据
S3_PUBLIC_DOMAIN=https://s3-for-chat.xxx.com
# 选填,S3 的 Enable Path Style
# 对于主流 S3 Cloud 服务商,一般填 0 即可;对于自部署的 MinIO,请填 1
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/s3#s-3-enable-path-style
S3_ENABLE_PATH_STYLE=0

# 其他基础环境变量,视需求而定。注意不要有 ACCESS_CODE
# 请参考:https://lobehub.com/zh/docs/self-hosting/environment-variables/basic
# 请注意,对于服务端版本,其 API 必须支持嵌入(OpenAI text-embedding-3-small)模型,否则无法对上传文件进行处理,但你无需在 OPENAI_MODEL_LIST 中指定此模型
ENABLED_OPENAI=1
OPENAI_API_KEY=sk-xxxx
OPENAI_PROXY_URL=https://one.xxx.com/v1
OPENAI_MODEL_LIST=-all,+gemini-1.5-flash=Gemini 1.5 Flash<16000:vision:fc:file>,+gemini-1.5-pro=Gemini 1.5 Pro<16000:vision:fc:file>,+deepseek-chat=DeepSeek V2.5<128000:fc>
DEFAULT_AGENT_CONFIG=model=deepseek-chat;plugins=search-engine,lobe-image-designer;params.max_tokens=300;chatConfig.historyCount=5
上一篇 2024年6月23日 下午10:58
下一篇 2024年11月6日 下午11:32

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注