@lobehub/chat 1.20.3 → 1.20.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/Dockerfile +37 -49
- package/Dockerfile.database +37 -53
- package/docker-compose/local/zitadel/.env.example +33 -0
- package/docker-compose/local/zitadel/.env.zh-CN.example +32 -0
- package/docker-compose/local/zitadel/docker-compose.yml +86 -0
- package/docker-compose/local/zitadel/zitadel-config.yaml +26 -0
- package/docker-compose/local/zitadel/zitadel-init-steps.yaml +11 -0
- package/docker-compose/production/zitadel/.env.example +53 -0
- package/docker-compose/production/zitadel/.env.zh-CN.example +48 -0
- package/docker-compose/production/zitadel/docker-compose.yml +69 -0
- package/docker-compose/production/zitadel/zitadel-config.yaml +25 -0
- package/docker-compose/production/zitadel/zitadel-init-steps.yaml +11 -0
- package/docs/self-hosting/server-database/docker-compose.mdx +9 -9
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +9 -9
- package/package.json +2 -2
- package/scripts/serverLauncher/startServer.js +181 -0
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/index.tsx +7 -1
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +0 -2
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/TopicPanel.tsx +0 -2
- package/src/app/(main)/chat/@session/features/SessionListContent/Modals/ConfigGroupModal/index.tsx +1 -2
- package/src/components/DragUpload/index.tsx +0 -1
- package/src/components/FunctionModal/style.tsx +0 -1
- package/src/components/GuideModal/index.tsx +0 -1
- package/src/features/Conversation/components/VirtualizedList/index.tsx +2 -7
- package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -1
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,40 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.20.5](https://github.com/lobehub/lobe-chat/compare/v1.20.4...v1.20.5)
|
6
|
+
|
7
|
+
<sup>Released on **2024-09-29**</sup>
|
8
|
+
|
9
|
+
<br/>
|
10
|
+
|
11
|
+
<details>
|
12
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
13
|
+
|
14
|
+
</details>
|
15
|
+
|
16
|
+
<div align="right">
|
17
|
+
|
18
|
+
[](#readme-top)
|
19
|
+
|
20
|
+
</div>
|
21
|
+
|
22
|
+
### [Version 1.20.4](https://github.com/lobehub/lobe-chat/compare/v1.20.3...v1.20.4)
|
23
|
+
|
24
|
+
<sup>Released on **2024-09-28**</sup>
|
25
|
+
|
26
|
+
<br/>
|
27
|
+
|
28
|
+
<details>
|
29
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
30
|
+
|
31
|
+
</details>
|
32
|
+
|
33
|
+
<div align="right">
|
34
|
+
|
35
|
+
[](#readme-top)
|
36
|
+
|
37
|
+
</div>
|
38
|
+
|
5
39
|
### [Version 1.20.3](https://github.com/lobehub/lobe-chat/compare/v1.20.2...v1.20.3)
|
6
40
|
|
7
41
|
<sup>Released on **2024-09-28**</sup>
|
package/Dockerfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
## Base image for all
|
1
|
+
## Base image for all building stages
|
2
2
|
FROM node:20-slim AS base
|
3
3
|
|
4
4
|
ARG USE_CN_MIRROR
|
@@ -10,19 +10,22 @@ RUN \
|
|
10
10
|
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
11
11
|
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"; \
|
12
12
|
fi \
|
13
|
-
# Add required package
|
13
|
+
# Add required package
|
14
14
|
&& apt update \
|
15
|
-
&& apt install
|
16
|
-
|
17
|
-
&&
|
18
|
-
|
19
|
-
|
20
|
-
&&
|
21
|
-
|
22
|
-
&&
|
23
|
-
|
24
|
-
|
25
|
-
&&
|
15
|
+
&& apt install ca-certificates proxychains-ng -qy \
|
16
|
+
# Prepare required package to distroless
|
17
|
+
&& mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib \
|
18
|
+
# Copy proxychains to distroless
|
19
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4 \
|
20
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2 \
|
21
|
+
&& cp /usr/bin/proxychains4 /distroless/bin/proxychains \
|
22
|
+
&& cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf \
|
23
|
+
# Copy node to distroless
|
24
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6 \
|
25
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1 \
|
26
|
+
&& cp /usr/local/bin/node /distroless/bin/node \
|
27
|
+
# Copy CA certificates to distroless
|
28
|
+
&& cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt \
|
26
29
|
# Cleanup temp files
|
27
30
|
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
28
31
|
|
@@ -61,6 +64,7 @@ RUN \
|
|
61
64
|
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
62
65
|
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"; \
|
63
66
|
npm config set registry "https://registry.npmmirror.com/"; \
|
67
|
+
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc; \
|
64
68
|
fi \
|
65
69
|
# Set the registry for corepack
|
66
70
|
&& export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//') \
|
@@ -80,7 +84,9 @@ COPY . .
|
|
80
84
|
RUN npm run build:docker
|
81
85
|
|
82
86
|
## Application image, copy all the files for production
|
83
|
-
FROM
|
87
|
+
FROM busybox:latest AS app
|
88
|
+
|
89
|
+
COPY --from=base /distroless/ /
|
84
90
|
|
85
91
|
COPY --from=builder /app/public /app/public
|
86
92
|
|
@@ -90,13 +96,25 @@ COPY --from=builder /app/.next/standalone /app/
|
|
90
96
|
COPY --from=builder /app/.next/static /app/.next/static
|
91
97
|
COPY --from=builder /deps/node_modules/.pnpm /app/node_modules/.pnpm
|
92
98
|
|
99
|
+
# Copy server launcher
|
100
|
+
COPY --from=builder /app/scripts/serverLauncher/startServer.js /app/startServer.js
|
101
|
+
|
102
|
+
RUN \
|
103
|
+
# Add nextjs:nodejs to run the app
|
104
|
+
addgroup -S -g 1001 nodejs \
|
105
|
+
&& adduser -D -G nodejs -H -S -h /app -u 1001 nextjs \
|
106
|
+
# Set permission for nextjs:nodejs
|
107
|
+
&& chown -R nextjs:nodejs /app /etc/proxychains4.conf
|
108
|
+
|
93
109
|
## Production image, copy all the files and run next
|
94
|
-
FROM
|
110
|
+
FROM scratch
|
95
111
|
|
96
112
|
# Copy all the files from app, set the correct permission for prerender cache
|
97
|
-
COPY --from=app
|
113
|
+
COPY --from=app / /
|
98
114
|
|
99
115
|
ENV NODE_ENV="production" \
|
116
|
+
NODE_OPTIONS="--use-openssl-ca" \
|
117
|
+
NODE_EXTRA_CA_CERTS="/etc/ssl/certs/ca-certificates.crt" \
|
100
118
|
NODE_TLS_REJECT_UNAUTHORIZED=""
|
101
119
|
|
102
120
|
# set hostname to localhost
|
@@ -176,36 +194,6 @@ USER nextjs
|
|
176
194
|
|
177
195
|
EXPOSE 3210/tcp
|
178
196
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
IP_REGEX="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$"; \
|
183
|
-
# Set proxychains command
|
184
|
-
PROXYCHAINS="proxychains -q"; \
|
185
|
-
# Parse the proxy URL
|
186
|
-
host_with_port="${PROXY_URL#*//}"; \
|
187
|
-
host="${host_with_port%%:*}"; \
|
188
|
-
port="${PROXY_URL##*:}"; \
|
189
|
-
protocol="${PROXY_URL%%://*}"; \
|
190
|
-
# Resolve to IP address if the host is a domain
|
191
|
-
if ! [[ "$host" =~ "$IP_REGEX" ]]; then \
|
192
|
-
nslookup=$(nslookup -q="A" "$host" | tail -n +3 | grep 'Address:'); \
|
193
|
-
if [ -n "$nslookup" ]; then \
|
194
|
-
host=$(echo "$nslookup" | tail -n 1 | awk '{print $2}'); \
|
195
|
-
fi; \
|
196
|
-
fi; \
|
197
|
-
# Generate proxychains configuration file
|
198
|
-
printf "%s\n" \
|
199
|
-
'localnet 127.0.0.0/255.0.0.0' \
|
200
|
-
'localnet ::1/128' \
|
201
|
-
'proxy_dns' \
|
202
|
-
'remote_dns_subnet 224' \
|
203
|
-
'strict_chain' \
|
204
|
-
'tcp_connect_time_out 8000' \
|
205
|
-
'tcp_read_time_out 15000' \
|
206
|
-
'[ProxyList]' \
|
207
|
-
"$protocol $host $port" \
|
208
|
-
> "/etc/proxychains4.conf"; \
|
209
|
-
fi; \
|
210
|
-
# Run the server
|
211
|
-
${PROXYCHAINS} node "/app/server.js";
|
197
|
+
ENTRYPOINT ["/bin/node"]
|
198
|
+
|
199
|
+
CMD ["/app/startServer.js"]
|
package/Dockerfile.database
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
## Base image for all
|
1
|
+
## Base image for all building stages
|
2
2
|
FROM node:20-slim AS base
|
3
3
|
|
4
4
|
ARG USE_CN_MIRROR
|
@@ -10,19 +10,22 @@ RUN \
|
|
10
10
|
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
11
11
|
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"; \
|
12
12
|
fi \
|
13
|
-
# Add required package
|
13
|
+
# Add required package
|
14
14
|
&& apt update \
|
15
|
-
&& apt install
|
16
|
-
|
17
|
-
&&
|
18
|
-
|
19
|
-
|
20
|
-
&&
|
21
|
-
|
22
|
-
&&
|
23
|
-
|
24
|
-
|
25
|
-
&&
|
15
|
+
&& apt install ca-certificates proxychains-ng -qy \
|
16
|
+
# Prepare required package to distroless
|
17
|
+
&& mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib \
|
18
|
+
# Copy proxychains to distroless
|
19
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4 \
|
20
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2 \
|
21
|
+
&& cp /usr/bin/proxychains4 /distroless/bin/proxychains \
|
22
|
+
&& cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf \
|
23
|
+
# Copy node to distroless
|
24
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6 \
|
25
|
+
&& cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1 \
|
26
|
+
&& cp /usr/local/bin/node /distroless/bin/node \
|
27
|
+
# Copy CA certificates to distroless
|
28
|
+
&& cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt \
|
26
29
|
# Cleanup temp files
|
27
30
|
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
28
31
|
|
@@ -65,6 +68,7 @@ RUN \
|
|
65
68
|
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
|
66
69
|
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"; \
|
67
70
|
npm config set registry "https://registry.npmmirror.com/"; \
|
71
|
+
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc; \
|
68
72
|
fi \
|
69
73
|
# Set the registry for corepack
|
70
74
|
&& export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//') \
|
@@ -84,7 +88,9 @@ COPY . .
|
|
84
88
|
RUN npm run build:docker
|
85
89
|
|
86
90
|
## Application image, copy all the files for production
|
87
|
-
FROM
|
91
|
+
FROM busybox:latest AS app
|
92
|
+
|
93
|
+
COPY --from=base /distroless/ /
|
88
94
|
|
89
95
|
COPY --from=builder /app/public /app/public
|
90
96
|
|
@@ -103,13 +109,25 @@ COPY --from=builder /app/src/database/server/migrations /app/migrations
|
|
103
109
|
COPY --from=builder /app/scripts/migrateServerDB/docker.cjs /app/docker.cjs
|
104
110
|
COPY --from=builder /app/scripts/migrateServerDB/errorHint.js /app/errorHint.js
|
105
111
|
|
112
|
+
# Copy server launcher
|
113
|
+
COPY --from=builder /app/scripts/serverLauncher/startServer.js /app/startServer.js
|
114
|
+
|
115
|
+
RUN \
|
116
|
+
# Add nextjs:nodejs to run the app
|
117
|
+
addgroup -S -g 1001 nodejs \
|
118
|
+
&& adduser -D -G nodejs -H -S -h /app -u 1001 nextjs \
|
119
|
+
# Set permission for nextjs:nodejs
|
120
|
+
&& chown -R nextjs:nodejs /app /etc/proxychains4.conf
|
121
|
+
|
106
122
|
## Production image, copy all the files and run next
|
107
|
-
FROM
|
123
|
+
FROM scratch
|
108
124
|
|
109
125
|
# Copy all the files from app, set the correct permission for prerender cache
|
110
|
-
COPY --from=app
|
126
|
+
COPY --from=app / /
|
111
127
|
|
112
128
|
ENV NODE_ENV="production" \
|
129
|
+
NODE_OPTIONS="--use-openssl-ca" \
|
130
|
+
NODE_EXTRA_CA_CERTS="/etc/ssl/certs/ca-certificates.crt" \
|
113
131
|
NODE_TLS_REJECT_UNAUTHORIZED=""
|
114
132
|
|
115
133
|
# set hostname to localhost
|
@@ -208,40 +226,6 @@ USER nextjs
|
|
208
226
|
|
209
227
|
EXPOSE 3210/tcp
|
210
228
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
IP_REGEX="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$"; \
|
215
|
-
# Set proxychains command
|
216
|
-
PROXYCHAINS="proxychains -q"; \
|
217
|
-
# Parse the proxy URL
|
218
|
-
host_with_port="${PROXY_URL#*//}"; \
|
219
|
-
host="${host_with_port%%:*}"; \
|
220
|
-
port="${PROXY_URL##*:}"; \
|
221
|
-
protocol="${PROXY_URL%%://*}"; \
|
222
|
-
# Resolve to IP address if the host is a domain
|
223
|
-
if ! [[ "$host" =~ "$IP_REGEX" ]]; then \
|
224
|
-
nslookup=$(nslookup -q="A" "$host" | tail -n +3 | grep 'Address:'); \
|
225
|
-
if [ -n "$nslookup" ]; then \
|
226
|
-
host=$(echo "$nslookup" | tail -n 1 | awk '{print $2}'); \
|
227
|
-
fi; \
|
228
|
-
fi; \
|
229
|
-
# Generate proxychains configuration file
|
230
|
-
printf "%s\n" \
|
231
|
-
'localnet 127.0.0.0/255.0.0.0' \
|
232
|
-
'localnet ::1/128' \
|
233
|
-
'proxy_dns' \
|
234
|
-
'remote_dns_subnet 224' \
|
235
|
-
'strict_chain' \
|
236
|
-
'tcp_connect_time_out 8000' \
|
237
|
-
'tcp_read_time_out 15000' \
|
238
|
-
'[ProxyList]' \
|
239
|
-
"$protocol $host $port" \
|
240
|
-
> "/etc/proxychains4.conf"; \
|
241
|
-
fi; \
|
242
|
-
# Run migration
|
243
|
-
node "/app/docker.cjs"; \
|
244
|
-
if [ "$?" -eq "0" ]; then \
|
245
|
-
# Run the server
|
246
|
-
${PROXYCHAINS} node "/app/server.js"; \
|
247
|
-
fi;
|
229
|
+
ENTRYPOINT ["/bin/node"]
|
230
|
+
|
231
|
+
CMD ["/app/startServer.js"]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Required: LobeChat domain for tRPC calls
|
2
|
+
# Ensure this domain is whitelisted in your NextAuth providers and S3 service CORS settings
|
3
|
+
APP_URL=http://localhost:3210
|
4
|
+
|
5
|
+
# Postgres related environment variables
|
6
|
+
# Required: Secret key for encrypting sensitive information. Generate with: openssl rand -base64 32
|
7
|
+
KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
8
|
+
# Required: Postgres database connection string
|
9
|
+
DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobechat
|
10
|
+
|
11
|
+
# NEXT_AUTH related environment variables
|
12
|
+
NEXTAUTH_URL=http://localhost:3210/api/auth
|
13
|
+
NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
14
|
+
NEXT_AUTH_SSO_PROVIDERS=zitadel
|
15
|
+
# ZiTADEL provider configuration
|
16
|
+
# Please refer to:https://lobehub.com/zh/docs/self-hosting/advanced/auth/next-auth/zitadel
|
17
|
+
AUTH_ZITADEL_ID=285945938244075523
|
18
|
+
AUTH_ZITADEL_SECRET=hkbtzHLaCEIeHeFThym14UcydpmQiEB5JtAX08HSqSoJxhAlVVkyovTuNUZ5TNrT
|
19
|
+
AUTH_ZITADEL_ISSUER=http://localhost:8080
|
20
|
+
|
21
|
+
# MinIO S3 configuration
|
22
|
+
S3_ACCESS_KEY_ID=
|
23
|
+
S3_SECRET_ACCESS_KEY=
|
24
|
+
S3_ENDPOINT=http://localhost:9000
|
25
|
+
S3_BUCKET=lobe
|
26
|
+
S3_PUBLIC_DOMAIN=http://localhost:9000
|
27
|
+
S3_ENABLE_PATH_STYLE=1
|
28
|
+
LLM_VISION_IMAGE_USE_BASE64=1
|
29
|
+
|
30
|
+
# Other environment variables, as needed. You can refer to the environment variables configuration for the client version, making sure not to have ACCESS_CODE.
|
31
|
+
# OPENAI_API_KEY=sk-xxxx
|
32
|
+
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
33
|
+
# OPENAI_MODEL_LIST=...
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# LobeChat 域名
|
2
|
+
APP_URL=http://localhost:3210
|
3
|
+
|
4
|
+
# Postgres 相关,也即 DB 必须的环境变量
|
5
|
+
# 用于加密敏感信息的密钥,可以使用 openssl rand -base64 32 生成
|
6
|
+
KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
7
|
+
# Postgres 数据库连接字符串
|
8
|
+
DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobechat
|
9
|
+
|
10
|
+
# NEXT_AUTH 相关
|
11
|
+
NEXTAUTH_URL=http://localhost:3210/api/auth
|
12
|
+
NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
13
|
+
NEXT_AUTH_SSO_PROVIDERS=zitadel
|
14
|
+
# ZiTADEL 鉴权服务提供商部分
|
15
|
+
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/auth/next-auth/zitadel
|
16
|
+
AUTH_ZITADEL_ID=285945938244075523
|
17
|
+
AUTH_ZITADEL_SECRET=hkbtzHLaCEIeHeFThym14UcydpmQiEB5JtAX08HSqSoJxhAlVVkyovTuNUZ5TNrT
|
18
|
+
AUTH_ZITADEL_ISSUER=http://localhost:8080
|
19
|
+
|
20
|
+
# MinIO S3 配置
|
21
|
+
S3_ACCESS_KEY_ID=
|
22
|
+
S3_SECRET_ACCESS_KEY=
|
23
|
+
S3_ENDPOINT=http://localhost:9000
|
24
|
+
S3_BUCKET=lobe
|
25
|
+
S3_PUBLIC_DOMAIN=http://localhost:9000
|
26
|
+
S3_ENABLE_PATH_STYLE=1
|
27
|
+
LLM_VISION_IMAGE_USE_BASE64=1
|
28
|
+
|
29
|
+
# 其他环境变量,视需求而定,可以参照客户端版本的环境变量配置,注意不要有 ACCESS_CODE
|
30
|
+
# OPENAI_API_KEY=sk-xxxx
|
31
|
+
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
32
|
+
# OPENAI_MODEL_LIST=...
|
@@ -0,0 +1,86 @@
|
|
1
|
+
services:
|
2
|
+
network-service:
|
3
|
+
image: alpine
|
4
|
+
container_name: lobe-network
|
5
|
+
ports:
|
6
|
+
- '9000:9000' # MinIO API
|
7
|
+
- '9001:9001' # MinIO Console
|
8
|
+
- '8080:8080' # Zitadel Console
|
9
|
+
- '3210:3210' # LobeChat
|
10
|
+
command: tail -f /dev/null
|
11
|
+
networks:
|
12
|
+
- lobe-network
|
13
|
+
|
14
|
+
postgresql:
|
15
|
+
image: pgvector/pgvector:pg16
|
16
|
+
container_name: lobe-postgres
|
17
|
+
ports:
|
18
|
+
- "5432:5432"
|
19
|
+
volumes:
|
20
|
+
- './data:/var/lib/postgresql/data'
|
21
|
+
environment:
|
22
|
+
- 'POSTGRES_DB=lobechat'
|
23
|
+
- 'POSTGRES_PASSWORD=uWNZugjBqixf8dxC'
|
24
|
+
healthcheck:
|
25
|
+
test: ['CMD-SHELL', 'pg_isready -U postgres']
|
26
|
+
interval: 5s
|
27
|
+
timeout: 5s
|
28
|
+
retries: 5
|
29
|
+
restart: always
|
30
|
+
networks:
|
31
|
+
- lobe-network
|
32
|
+
|
33
|
+
minio:
|
34
|
+
image: minio/minio
|
35
|
+
container_name: lobe-minio
|
36
|
+
network_mode: 'service:network-service'
|
37
|
+
volumes:
|
38
|
+
- './s3_data:/etc/minio/data'
|
39
|
+
environment:
|
40
|
+
- 'MINIO_ROOT_USER=YOUR_MINIO_USER'
|
41
|
+
- 'MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD'
|
42
|
+
- 'MINIO_API_CORS_ALLOW_ORIGIN=http://localhost:3210'
|
43
|
+
restart: always
|
44
|
+
command: >
|
45
|
+
server /etc/minio/data --address ":9000" --console-address ":9001"
|
46
|
+
|
47
|
+
zitadel:
|
48
|
+
restart: 'always'
|
49
|
+
image: 'ghcr.io/zitadel/zitadel:latest'
|
50
|
+
container_name: lobe-zitadel
|
51
|
+
network_mode: 'service:network-service'
|
52
|
+
command: start-from-init --config /zitadel-config.yaml --steps
|
53
|
+
/zitadel-init-steps.yaml --masterkey "cft3Tekr/rQBOqwoQSCPoncA9BHbn7QJ"
|
54
|
+
--tlsMode disabled #MasterkeyNeedsToHave32Characters
|
55
|
+
volumes:
|
56
|
+
- ./zitadel-config.yaml:/zitadel-config.yaml:ro
|
57
|
+
- ./zitadel-init-steps.yaml:/zitadel-init-steps.yaml:ro
|
58
|
+
depends_on:
|
59
|
+
postgresql:
|
60
|
+
condition: service_healthy
|
61
|
+
|
62
|
+
lobe:
|
63
|
+
image: lobehub/lobe-chat-database
|
64
|
+
container_name: lobe-database
|
65
|
+
network_mode: 'service:network-service'
|
66
|
+
depends_on:
|
67
|
+
postgresql:
|
68
|
+
condition: service_healthy
|
69
|
+
network-service:
|
70
|
+
condition: service_started
|
71
|
+
minio:
|
72
|
+
condition: service_started
|
73
|
+
zitadel:
|
74
|
+
condition: service_started
|
75
|
+
env_file:
|
76
|
+
- .env
|
77
|
+
restart: always
|
78
|
+
|
79
|
+
volumes:
|
80
|
+
data:
|
81
|
+
driver: local
|
82
|
+
s3_data:
|
83
|
+
driver: local
|
84
|
+
networks:
|
85
|
+
lobe-network:
|
86
|
+
driver: bridge
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Log:
|
2
|
+
Level: 'info'
|
3
|
+
|
4
|
+
Port: 8080
|
5
|
+
ExternalPort: 8080
|
6
|
+
ExternalDomain: localhost
|
7
|
+
ExternalSecure: false
|
8
|
+
TLS:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
# If not using the docker compose example, adjust these values for connecting ZITADEL to your PostgreSQL
|
12
|
+
Database:
|
13
|
+
postgres:
|
14
|
+
Host: postgresql
|
15
|
+
Port: 5432
|
16
|
+
Database: zitadel
|
17
|
+
User:
|
18
|
+
Username: 'zitadel'
|
19
|
+
Password: 'zitadel'
|
20
|
+
SSL:
|
21
|
+
Mode: 'disable'
|
22
|
+
Admin:
|
23
|
+
Username: 'postgres'
|
24
|
+
Password: 'uWNZugjBqixf8dxC' #postgres password
|
25
|
+
SSL:
|
26
|
+
Mode: 'disable'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml
|
2
|
+
FirstInstance:
|
3
|
+
Org:
|
4
|
+
Human:
|
5
|
+
# use the loginname root@zitadel.localhost
|
6
|
+
Username: 'root'
|
7
|
+
# The password must be 8 characters or more and must contain uppercase letters, lowercase letters, symbols, and numbers. The first login will require a password change.
|
8
|
+
Password: 'Password1!'
|
9
|
+
Email:
|
10
|
+
# Optional, if set, can be used to log in with email.
|
11
|
+
Address: 'example@zitadel.com' # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Required: LobeChat domain for tRPC calls
|
2
|
+
# Ensure this domain is whitelisted in your NextAuth providers and S3 service CORS settings
|
3
|
+
APP_URL=https://lobe.example.com/
|
4
|
+
|
5
|
+
# Postgres related environment variables
|
6
|
+
# Required: Secret key for encrypting sensitive information. Generate with: openssl rand -base64 32
|
7
|
+
KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
8
|
+
# Required: Postgres database connection string
|
9
|
+
# Format: postgresql://username:password@host:port/dbname
|
10
|
+
# If using Docker, you can use the container name as the host
|
11
|
+
DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobe
|
12
|
+
|
13
|
+
# NEXT_AUTH related environment variables
|
14
|
+
# Required: NextAuth URL for callbacks
|
15
|
+
NEXTAUTH_URL=https://lobe.example.com/api/auth
|
16
|
+
# Required: NextAuth secret key. Generate with: openssl rand -base64 32
|
17
|
+
NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
18
|
+
# Required: Specify the authentication provider
|
19
|
+
NEXT_AUTH_SSO_PROVIDERS=zitadel
|
20
|
+
|
21
|
+
# ZiTADEL provider configuration
|
22
|
+
# Please refer to:https://lobehub.com/zh/docs/self-hosting/advanced/auth/next-auth/zitadel
|
23
|
+
AUTH_ZITADEL_ID=285934220675723622
|
24
|
+
AUTH_ZITADEL_SECRET=pe7Nh3lopXkZkfqh5YEDYI2xsbIz08eZKqInOUZxssd3refRia518Apbv3DZ
|
25
|
+
AUTH_ZITADEL_ISSUER=https://zitadel.example.com
|
26
|
+
|
27
|
+
# Proxy settings (if needed, e.g., when using GitHub as an auth provider)
|
28
|
+
# HTTP_PROXY=http://localhost:7890
|
29
|
+
# HTTPS_PROXY=http://localhost:7890
|
30
|
+
|
31
|
+
# S3 related environment variables (example using MinIO)
|
32
|
+
# Required: S3 Access Key ID (for MinIO, invalid until manually created in MinIO UI)
|
33
|
+
S3_ACCESS_KEY_ID=YOUR_S3_ACCESS_KEY_ID
|
34
|
+
# Required: S3 Secret Access Key (for MinIO, invalid until manually created in MinIO UI)
|
35
|
+
S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
36
|
+
# Required: S3 Endpoint for server/client connections to S3 API
|
37
|
+
S3_ENDPOINT=https://lobe-s3-api.example.com
|
38
|
+
# Required: S3 Bucket (invalid until manually created in MinIO UI)
|
39
|
+
S3_BUCKET=lobe
|
40
|
+
# Required: S3 Public Domain for client access to unstructured data
|
41
|
+
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
42
|
+
# Optional: S3 Enable Path Style
|
43
|
+
# Use 0 for mainstream S3 cloud providers; use 1 for self-hosted MinIO
|
44
|
+
# See: https://lobehub.com/docs/self-hosting/advanced/s3#s-3-enable-path-style
|
45
|
+
S3_ENABLE_PATH_STYLE=1
|
46
|
+
|
47
|
+
# Other basic environment variables (as needed)
|
48
|
+
# See: https://lobehub.com/docs/self-hosting/environment-variables/basic
|
49
|
+
# Note: For server versions, the API must support embedding models (OpenAI text-embedding-3-small) for file processing
|
50
|
+
# You don't need to specify this model in OPENAI_MODEL_LIST
|
51
|
+
# OPENAI_API_KEY=sk-xxxx
|
52
|
+
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
53
|
+
# OPENAI_MODEL_LIST=...
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# 必填,LobeChat 域名,用于 tRPC 调用
|
2
|
+
# 请保证此域名在你的 NextAuth 鉴权服务提供商、S3 服务商的 CORS 白名单中
|
3
|
+
APP_URL=https://lobe.example.com/
|
4
|
+
|
5
|
+
# Postgres 相关,也即 DB 必需的环境变量
|
6
|
+
# 必填,用于加密敏感信息的密钥,可以使用 openssl rand -base64 32 生成
|
7
|
+
KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
8
|
+
# 必填,Postgres 数据库连接字符串,用于连接到数据库
|
9
|
+
# 格式:postgresql://username:password@host:port/dbname,如果你的 pg 实例为 Docker 容器且位于同一 docker-compose 文件中,亦可使用容器名作为 host
|
10
|
+
DATABASE_URL=postgresql://postgres:uWNZugjBqixf8dxC@postgresql:5432/lobe
|
11
|
+
|
12
|
+
# NEXT_AUTH 相关,也即鉴权服务必需的环境变量
|
13
|
+
# 必填,NextAuth 的 URL,用于 NextAuth 的回调
|
14
|
+
NEXTAUTH_URL=https://lobe.example.com/api/auth
|
15
|
+
# 必填,用于 NextAuth 的密钥,可以使用 openssl rand -base64 32 生成
|
16
|
+
NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg
|
17
|
+
# 必填,指定鉴权服务提供商
|
18
|
+
NEXT_AUTH_SSO_PROVIDERS=zitadel
|
19
|
+
|
20
|
+
# ZiTADEL 鉴权服务提供商部分
|
21
|
+
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/auth/next-auth/zitadel
|
22
|
+
AUTH_ZITADEL_ID=285934220675723622
|
23
|
+
AUTH_ZITADEL_SECRET=pe7Nh3lopXkZkfqh5YEDYI2xsbIz08eZKqInOUZxssd3refRia518Apbv3DZ
|
24
|
+
AUTH_ZITADEL_ISSUER=https://zitadel.example.com
|
25
|
+
|
26
|
+
# S3 相关,也即非结构化数据(文件、图片等)存储必需的环境变量
|
27
|
+
# 这里以 MinIO 为例
|
28
|
+
# 必填,S3 的 Access Key ID,对于 MinIO 来说,直到在 MinIO UI 中手动创建之前都是无效的
|
29
|
+
S3_ACCESS_KEY_ID=YOUR_S3_ACCESS_KEY_ID
|
30
|
+
# 必填,S3 的 Secret Access Key,对于 MinIO 来说,直到在 MinIO UI 中手动创建之前都是无效的
|
31
|
+
S3_SECRET_ACCESS_KEY=YOUR_S3_SECRET_ACCESS_KEY
|
32
|
+
# 必填,S3 的 Endpoint,用于服务端/客户端连接到 S3 API
|
33
|
+
S3_ENDPOINT=https://lobe-s3-api.example.com
|
34
|
+
# 必填,S3 的 Bucket,直到在 MinIO UI 中手动创建之前都是无效的
|
35
|
+
S3_BUCKET=lobe
|
36
|
+
# 必填,S3 的 Public Domain,用于客户端通过公开连接访问非结构化数据
|
37
|
+
S3_PUBLIC_DOMAIN=https://lobe-s3-api.example.com
|
38
|
+
# 选填,S3 的 Enable Path Style
|
39
|
+
# 对于主流 S3 Cloud 服务商,一般填 0 即可;对于自部署的 MinIO,请填 1
|
40
|
+
# 请参考:https://lobehub.com/zh/docs/self-hosting/advanced/s3#s-3-enable-path-style
|
41
|
+
S3_ENABLE_PATH_STYLE=1
|
42
|
+
|
43
|
+
# 其他基础环境变量,视需求而定。注意不要有 ACCESS_CODE
|
44
|
+
# 请参考:https://lobehub.com/zh/docs/self-hosting/environment-variables/basic
|
45
|
+
# 请注意,对于服务端版本,其 API 必须支持嵌入(即 OpenAI text-embedding-3-small)模型,否则无法对上传文件进行处理,但你无需在 OPENAI_MODEL_LIST 中指定此模型
|
46
|
+
# OPENAI_API_KEY=sk-xxxx
|
47
|
+
# OPENAI_PROXY_URL=https://api.openai.com/v1
|
48
|
+
# OPENAI_MODEL_LIST=...
|
@@ -0,0 +1,69 @@
|
|
1
|
+
services:
|
2
|
+
postgresql:
|
3
|
+
image: pgvector/pgvector:pg16
|
4
|
+
container_name: lobe-postgres
|
5
|
+
ports:
|
6
|
+
- '5432:5432'
|
7
|
+
volumes:
|
8
|
+
- './data:/var/lib/postgresql/data'
|
9
|
+
environment:
|
10
|
+
- 'POSTGRES_DB=lobe'
|
11
|
+
- 'POSTGRES_PASSWORD=uWNZugjBqixf8dxC'
|
12
|
+
healthcheck:
|
13
|
+
test: ['CMD-SHELL', 'pg_isready -U postgres']
|
14
|
+
interval: 5s
|
15
|
+
timeout: 5s
|
16
|
+
retries: 5
|
17
|
+
restart: always
|
18
|
+
|
19
|
+
minio:
|
20
|
+
image: minio/minio
|
21
|
+
container_name: lobe-minio
|
22
|
+
ports:
|
23
|
+
- '9000:9000'
|
24
|
+
- '9001:9001'
|
25
|
+
volumes:
|
26
|
+
- './s3_data:/etc/minio/data'
|
27
|
+
environment:
|
28
|
+
- 'MINIO_ROOT_USER=YOUR_MINIO_USER'
|
29
|
+
- 'MINIO_ROOT_PASSWORD=YOUR_MINIO_PASSWORD'
|
30
|
+
- 'MINIO_DOMAIN=lobe-s3-api.example.com'
|
31
|
+
- 'MINIO_API_CORS_ALLOW_ORIGIN=https://lobe.example.com' # Your LobeChat's domain name.
|
32
|
+
restart: always
|
33
|
+
command: >
|
34
|
+
server /etc/minio/data --address ":9000" --console-address ":9001"
|
35
|
+
|
36
|
+
zitadel:
|
37
|
+
restart: always
|
38
|
+
image: ghcr.io/zitadel/zitadel:latest
|
39
|
+
container_name: lobe-zitadel
|
40
|
+
command: start-from-init --config /zitadel-config.yaml --steps
|
41
|
+
/zitadel-init-steps.yaml --masterkey "cft3Tekr/rQBOqwoQSCPoncA9BHbn7QJ"
|
42
|
+
--tlsMode external #MasterkeyNeedsToHave32Characters
|
43
|
+
ports:
|
44
|
+
- 8080:8080
|
45
|
+
volumes:
|
46
|
+
- ./zitadel-config.yaml:/zitadel-config.yaml:ro
|
47
|
+
- ./zitadel-init-steps.yaml:/zitadel-init-steps.yaml:ro
|
48
|
+
depends_on:
|
49
|
+
postgresql:
|
50
|
+
condition: service_healthy
|
51
|
+
|
52
|
+
lobe:
|
53
|
+
image: lobehub/lobe-chat-database
|
54
|
+
container_name: lobe-database
|
55
|
+
ports:
|
56
|
+
- '3210:3210'
|
57
|
+
depends_on:
|
58
|
+
- postgresql
|
59
|
+
- minio
|
60
|
+
- zitadel
|
61
|
+
env_file:
|
62
|
+
- .env
|
63
|
+
restart: always
|
64
|
+
|
65
|
+
volumes:
|
66
|
+
data:
|
67
|
+
driver: local
|
68
|
+
s3_data:
|
69
|
+
driver: local
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Log:
|
2
|
+
Level: 'info'
|
3
|
+
|
4
|
+
ExternalPort: 443
|
5
|
+
ExternalDomain: example.com #Your zitadel's domain name
|
6
|
+
ExternalSecure: true
|
7
|
+
TLS:
|
8
|
+
Enabled: false # ZITADEL_TLS_ENABLED
|
9
|
+
|
10
|
+
# If not using the docker compose example, adjust these values for connecting ZITADEL to your PostgreSQL
|
11
|
+
Database:
|
12
|
+
postgres:
|
13
|
+
Host: postgresql
|
14
|
+
Port: 5432
|
15
|
+
Database: zitadel
|
16
|
+
User:
|
17
|
+
Username: 'zitadel'
|
18
|
+
Password: 'zitadel'
|
19
|
+
SSL:
|
20
|
+
Mode: 'disable'
|
21
|
+
Admin:
|
22
|
+
Username: 'postgres'
|
23
|
+
Password: 'uWNZugjBqixf8dxC' #postgres password
|
24
|
+
SSL:
|
25
|
+
Mode: 'disable'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml
|
2
|
+
FirstInstance:
|
3
|
+
Org:
|
4
|
+
Human:
|
5
|
+
# use the loginname root@zitadel.localhost, replace localhost with your configured external domain
|
6
|
+
Username: 'root'
|
7
|
+
# The password must be 8 characters or more and must contain uppercase letters, lowercase letters, symbols, and numbers. The first login will require a password change.
|
8
|
+
Password: 'Password1!'
|
9
|
+
Email:
|
10
|
+
# Optional, if set, can be used to log in with email.
|
11
|
+
Address: 'example@zitadel.com' # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS
|
@@ -88,7 +88,7 @@ docker compose up -d
|
|
88
88
|
- `Redirect URI` should be `http://localhost:3210/api/auth/callback/logto`
|
89
89
|
- `Post sign-out redirect URI` should be `http://localhost:3210/`
|
90
90
|
|
91
|
-
3. Obtain the `App ID` and `App secrets`, and fill them into your `.env` file corresponding to `
|
91
|
+
3. Obtain the `App ID` and `App secrets`, and fill them into your `.env` file corresponding to `AUTH_LOGTO_ID` and `AUTH_LOGTO_SECRET`.
|
92
92
|
|
93
93
|
### Configure MinIO S3
|
94
94
|
|
@@ -258,9 +258,9 @@ You need to first access the WebUI for configuration:
|
|
258
258
|
src="https://github.com/user-attachments/assets/5b816379-c07b-40ea-bde4-df16e2e4e523"
|
259
259
|
/>
|
260
260
|
|
261
|
-
5. Obtain `App ID` and `App secrets`, and fill them into your `.env` file under `
|
261
|
+
5. Obtain `App ID` and `App secrets`, and fill them into your `.env` file under `AUTH_LOGTO_ID` and `AUTH_LOGTO_SECRET`.
|
262
262
|
|
263
|
-
6. Set `
|
263
|
+
6. Set `AUTH_LOGTO_ISSUER` in your `.env` file to `https://lobe-auth-api.example.com/oidc`.
|
264
264
|
|
265
265
|
<Image
|
266
266
|
alt="Configure environment variables"
|
@@ -349,8 +349,8 @@ To facilitate one-click copying, here are the example configuration files needed
|
|
349
349
|
|
350
350
|
```sh
|
351
351
|
# Logto secret
|
352
|
-
|
353
|
-
|
352
|
+
AUTH_LOGTO_ID=
|
353
|
+
AUTH_LOGTO_SECRET=
|
354
354
|
|
355
355
|
# MinIO S3 configuration
|
356
356
|
MINIO_ROOT_USER=YOUR_MINIO_USER
|
@@ -467,7 +467,7 @@ services:
|
|
467
467
|
- 'KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ='
|
468
468
|
- 'NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg'
|
469
469
|
- 'NEXTAUTH_URL=http://localhost:${LOBE_PORT}/api/auth'
|
470
|
-
- '
|
470
|
+
- 'AUTH_LOGTO_ISSUER=http://localhost:${LOGTO_PORT}/oidc'
|
471
471
|
- 'DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgresql:5432/${LOBE_DB_NAME}'
|
472
472
|
- 'S3_ENDPOINT=http://localhost:${MINIO_PORT}'
|
473
473
|
- 'S3_BUCKET=${MINIO_LOBE_BUCKET}'
|
@@ -519,9 +519,9 @@ NEXTAUTH_URL=https://lobe.example.com/api/auth
|
|
519
519
|
|
520
520
|
# NextAuth providers configuration (example using Logto)
|
521
521
|
# For other providers, see: https://lobehub.com/docs/self-hosting/environment-variables/auth
|
522
|
-
|
523
|
-
|
524
|
-
|
522
|
+
AUTH_LOGTO_ID=YOUR_LOGTO_CLIENT_ID
|
523
|
+
AUTH_LOGTO_SECRET=YOUR_LOGTO_CLIENT_SECRET
|
524
|
+
AUTH_LOGTO_ISSUER=https://lobe-auth-api.example.com/oidc
|
525
525
|
|
526
526
|
# Proxy settings (if needed, e.g., when using GitHub as an auth provider)
|
527
527
|
# HTTP_PROXY=http://localhost:7890
|
@@ -86,7 +86,7 @@ docker compose up -d
|
|
86
86
|
- `Redirect URI` 为 `http://localhost:3210/api/auth/callback/logto`
|
87
87
|
- `Post sign-out redirect URI` 为 `http://localhost:3210/`
|
88
88
|
|
89
|
-
3. 获取 `App ID` 和 `App secrets`,填入 `.env` 文件中对应的 `
|
89
|
+
3. 获取 `App ID` 和 `App secrets`,填入 `.env` 文件中对应的 `AUTH_LOGTO_ID` 、 `AUTH_LOGTO_SECRET`
|
90
90
|
|
91
91
|
### 配置 MinIO S3
|
92
92
|
|
@@ -256,9 +256,9 @@ docker compose up -d # 重新启动
|
|
256
256
|
src="https://github.com/user-attachments/assets/5b816379-c07b-40ea-bde4-df16e2e4e523"
|
257
257
|
/>
|
258
258
|
|
259
|
-
5. 获取 `App ID` 和 `App secrets`,填入你的 `.env` 文件中的 `
|
259
|
+
5. 获取 `App ID` 和 `App secrets`,填入你的 `.env` 文件中的 `AUTH_LOGTO_ID` 和 `AUTH_LOGTO_SECRET` 中
|
260
260
|
|
261
|
-
6. 配置你的 `.env` 文件中 `
|
261
|
+
6. 配置你的 `.env` 文件中 `AUTH_LOGTO_ISSUER` 为 `https://lobe-auth-api.example.com/oidc`
|
262
262
|
|
263
263
|
<Image
|
264
264
|
alt="配置 Logto 环境变量"
|
@@ -346,8 +346,8 @@ docker compose up -d # 重新启动
|
|
346
346
|
|
347
347
|
```sh
|
348
348
|
# Logto secret
|
349
|
-
|
350
|
-
|
349
|
+
AUTH_LOGTO_ID=
|
350
|
+
AUTH_LOGTO_SECRET=
|
351
351
|
|
352
352
|
# MinIO S3 配置
|
353
353
|
MINIO_ROOT_USER=YOUR_MINIO_USER
|
@@ -464,7 +464,7 @@ services:
|
|
464
464
|
- 'KEY_VAULTS_SECRET=Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ='
|
465
465
|
- 'NEXT_AUTH_SECRET=NX2kaPE923dt6BL2U8e9oSre5RfoT7hg'
|
466
466
|
- 'NEXTAUTH_URL=http://localhost:${LOBE_PORT}/api/auth'
|
467
|
-
- '
|
467
|
+
- 'AUTH_LOGTO_ISSUER=http://localhost:${LOGTO_PORT}/oidc'
|
468
468
|
- 'DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgresql:5432/${LOBE_DB_NAME}'
|
469
469
|
- 'S3_ENDPOINT=http://localhost:${MINIO_PORT}'
|
470
470
|
- 'S3_BUCKET=${MINIO_LOBE_BUCKET}'
|
@@ -515,9 +515,9 @@ NEXTAUTH_URL=https://lobe.example.com/api/auth
|
|
515
515
|
|
516
516
|
# NextAuth 鉴权服务提供商部分,以 Logto 为例
|
517
517
|
# 其他鉴权服务提供商所需的环境变量,请参考:https://lobehub.com/zh/docs/self-hosting/environment-variables/auth
|
518
|
-
|
519
|
-
|
520
|
-
|
518
|
+
AUTH_LOGTO_ID=YOUR_LOGTO_CLIENT_ID
|
519
|
+
AUTH_LOGTO_SECRET=YOUR_LOGTO_CLIENT_SECRET
|
520
|
+
AUTH_LOGTO_ISSUER=https://lobe-auth-api.example.com/oidc
|
521
521
|
|
522
522
|
# 代理相关,如果你需要的话(比如你使用 GitHub 作为鉴权服务提供商)
|
523
523
|
# HTTP_PROXY=http://localhost:7890
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.20.
|
3
|
+
"version": "1.20.5",
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
5
5
|
"keywords": [
|
6
6
|
"framework",
|
@@ -217,7 +217,7 @@
|
|
217
217
|
"systemjs": "^6.15.1",
|
218
218
|
"ts-md5": "^1.3.1",
|
219
219
|
"ua-parser-js": "^1.0.38",
|
220
|
-
"unstructured-client": "^0.
|
220
|
+
"unstructured-client": "^0.18.0",
|
221
221
|
"url-join": "^5.0.0",
|
222
222
|
"use-merge-value": "^1.2.0",
|
223
223
|
"utility-types": "^3.11.0",
|
@@ -0,0 +1,181 @@
|
|
1
|
+
const dns = require('dns').promises;
|
2
|
+
const fs = require('fs');
|
3
|
+
const tls = require('tls');
|
4
|
+
const { spawn } = require('child_process');
|
5
|
+
|
6
|
+
// Set file paths
|
7
|
+
const DB_MIGRATION_SCRIPT_PATH = '/app/docker.cjs';
|
8
|
+
const SERVER_SCRIPT_PATH = '/app/server.js';
|
9
|
+
const PROXYCHAINS_CONF_PATH = '/etc/proxychains4.conf';
|
10
|
+
|
11
|
+
// Function to check if a string is a valid IP address
|
12
|
+
const isValidIP = (ip, version = 4) => {
|
13
|
+
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/;
|
14
|
+
const ipv6Regex = /^(([0-9a-f]{1,4}:){7,7}[0-9a-f]{1,4}|([0-9a-f]{1,4}:){1,7}:|([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}|([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}|([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}|([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:((:[0-9a-f]{1,4}){1,6})|:((:[0-9a-f]{1,4}){1,7}|:)|fe80:(:[0-9a-f]{0,4}){0,4}%[0-9a-z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
|
15
|
+
|
16
|
+
switch (version) {
|
17
|
+
case 4:
|
18
|
+
return ipv4Regex.test(ip);
|
19
|
+
case 6:
|
20
|
+
return ipv6Regex.test(ip);
|
21
|
+
default:
|
22
|
+
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
// Function to check TLS validity of a URL
|
27
|
+
const isValidTLS = (url = '') => {
|
28
|
+
if (!url) {
|
29
|
+
console.log('⚠️ TLS Check: No URL provided. Skipping TLS check. Ensure correct setting ENV.');
|
30
|
+
console.log('-------------------------------------');
|
31
|
+
return Promise.resolve();
|
32
|
+
}
|
33
|
+
|
34
|
+
const { protocol, host, port } = parseUrl(url);
|
35
|
+
if (protocol !== 'https') {
|
36
|
+
console.log(`⚠️ TLS Check: Non-HTTPS protocol (${protocol}). Skipping TLS check for ${url}.`);
|
37
|
+
console.log('-------------------------------------');
|
38
|
+
return Promise.resolve();
|
39
|
+
}
|
40
|
+
|
41
|
+
const options = { host, port, servername: host };
|
42
|
+
return new Promise((resolve, reject) => {
|
43
|
+
const socket = tls.connect(options, () => {
|
44
|
+
if (socket.authorized) {
|
45
|
+
console.log(`✅ TLS Check: Valid certificate for ${host}:${port}.`);
|
46
|
+
console.log('-------------------------------------');
|
47
|
+
resolve();
|
48
|
+
}
|
49
|
+
socket.end();
|
50
|
+
});
|
51
|
+
|
52
|
+
socket.on('error', (err) => {
|
53
|
+
const errMsg = `❌ TLS Check: Error for ${host}:${port}. Details:`;
|
54
|
+
switch (err.code) {
|
55
|
+
case 'CERT_HAS_EXPIRED':
|
56
|
+
case 'DEPTH_ZERO_SELF_SIGNED_CERT':
|
57
|
+
console.error(`${errMsg} Certificate is not valid. Consider setting NODE_TLS_REJECT_UNAUTHORIZED="0" or mapping /etc/ssl/certs/ca-certificates.crt.`);
|
58
|
+
break;
|
59
|
+
case 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY':
|
60
|
+
console.error(`${errMsg} Unable to verify issuer. Ensure correct mapping of /etc/ssl/certs/ca-certificates.crt.`);
|
61
|
+
break;
|
62
|
+
default:
|
63
|
+
console.error(`${errMsg} Network issue. Check firewall or DNS.`);
|
64
|
+
break;
|
65
|
+
}
|
66
|
+
reject(err);
|
67
|
+
});
|
68
|
+
});
|
69
|
+
};
|
70
|
+
|
71
|
+
// Function to check TLS connections for OSS and Auth Issuer
|
72
|
+
const checkTLSConnections = async () => {
|
73
|
+
await Promise.all([
|
74
|
+
isValidTLS(process.env.S3_ENDPOINT),
|
75
|
+
isValidTLS(process.env.S3_PUBLIC_DOMAIN),
|
76
|
+
isValidTLS(getEnvVarsByKeyword('_ISSUER')),
|
77
|
+
]);
|
78
|
+
};
|
79
|
+
|
80
|
+
// Function to get environment variable by keyword
|
81
|
+
const getEnvVarsByKeyword = (keyword) => {
|
82
|
+
return Object.entries(process.env)
|
83
|
+
.filter(([key, value]) => key.includes(keyword) && value)
|
84
|
+
.map(([, value]) => value)[0] || null;
|
85
|
+
};
|
86
|
+
|
87
|
+
// Function to parse protocol, host and port from a URL
|
88
|
+
const parseUrl = (url) => {
|
89
|
+
const { protocol, hostname: host, port } = new URL(url);
|
90
|
+
return { protocol: protocol.replace(':', ''), host, port: port || 443 };
|
91
|
+
};
|
92
|
+
|
93
|
+
// Function to resolve host IP via DNS
|
94
|
+
const resolveHostIP = async (host, version = 4) => {
|
95
|
+
try {
|
96
|
+
const { address } = await dns.lookup(host, { family: version });
|
97
|
+
|
98
|
+
if (!isValidIP(address, version)) {
|
99
|
+
console.error(`❌ DNS Error: Invalid resolved IP: ${address}. IP address must be IPv${version}.`);
|
100
|
+
process.exit(1);
|
101
|
+
}
|
102
|
+
|
103
|
+
return address;
|
104
|
+
} catch (err) {
|
105
|
+
console.error(`❌ DNS Error: Could not resolve ${host}. Check DNS server.`, err);
|
106
|
+
process.exit(1);
|
107
|
+
}
|
108
|
+
};
|
109
|
+
|
110
|
+
// Function to generate proxychains configuration
|
111
|
+
const runProxyChainsConfGenerator = async (url) => {
|
112
|
+
const { protocol, host, port } = parseUrl(url);
|
113
|
+
|
114
|
+
if (!['http', 'socks4', 'socks5'].includes(protocol)) {
|
115
|
+
console.error(`❌ ProxyChains: Invalid protocol (${protocol}). Protocol must be 'http', 'socks4' and 'socks5'.`);
|
116
|
+
process.exit(1);
|
117
|
+
}
|
118
|
+
|
119
|
+
const validPort = parseInt(port, 10);
|
120
|
+
if (isNaN(validPort) || validPort <= 0 || validPort > 65535) {
|
121
|
+
console.error(`❌ ProxyChains: Invalid port (${port}). Port must be a number between 1 and 65535.`);
|
122
|
+
process.exit(1);
|
123
|
+
}
|
124
|
+
|
125
|
+
let ip = isValidIP(host, 4) ? host : await resolveHostIP(host, 4);
|
126
|
+
|
127
|
+
const configContent = `
|
128
|
+
localnet 127.0.0.0/255.0.0.0
|
129
|
+
localnet ::1/128
|
130
|
+
proxy_dns
|
131
|
+
remote_dns_subnet 224
|
132
|
+
strict_chain
|
133
|
+
tcp_connect_time_out 8000
|
134
|
+
tcp_read_time_out 15000
|
135
|
+
[ProxyList]
|
136
|
+
${protocol} ${ip} ${port}
|
137
|
+
`.trim();
|
138
|
+
|
139
|
+
fs.writeFileSync(PROXYCHAINS_CONF_PATH, configContent);
|
140
|
+
console.log(`✅ ProxyChains: All outgoing traffic routed via ${protocol}://${ip}:${port}.`);
|
141
|
+
console.log('-------------------------------------');
|
142
|
+
};
|
143
|
+
|
144
|
+
// Function to execute a script with child process spawn
|
145
|
+
const runScript = (scriptPath, useProxy = false) => {
|
146
|
+
const command = useProxy ? ['/bin/proxychains', '-q', '/bin/node', scriptPath] : ['/bin/node', scriptPath];
|
147
|
+
return new Promise((resolve, reject) => {
|
148
|
+
const process = spawn(command.shift(), command, { stdio: 'inherit' });
|
149
|
+
process.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`🔴 Process exited with code ${code}`))));
|
150
|
+
});
|
151
|
+
};
|
152
|
+
|
153
|
+
// Main function to run the server with optional proxy
|
154
|
+
const runServer = async () => {
|
155
|
+
const PROXY_URL = process.env.PROXY_URL || ''; // Default empty string to avoid undefined errors
|
156
|
+
|
157
|
+
if (PROXY_URL) {
|
158
|
+
await runProxyChainsConfGenerator(PROXY_URL);
|
159
|
+
return runScript(SERVER_SCRIPT_PATH, true);
|
160
|
+
}
|
161
|
+
return runScript(SERVER_SCRIPT_PATH);
|
162
|
+
};
|
163
|
+
|
164
|
+
// Main execution block
|
165
|
+
(async () => {
|
166
|
+
console.log('🌐 DNS Server:', dns.getServers());
|
167
|
+
console.log('-------------------------------------');
|
168
|
+
|
169
|
+
if (process.env.DATABASE_DRIVER) {
|
170
|
+
try {
|
171
|
+
await runScript(DB_MIGRATION_SCRIPT_PATH);
|
172
|
+
await checkTLSConnections();
|
173
|
+
} catch (err) {
|
174
|
+
console.error('❌ Error during DB migration or TLS connection check:', err);
|
175
|
+
process.exit(1);
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
// Run the server in either database or non-database mode
|
180
|
+
await runServer();
|
181
|
+
})();
|
@@ -3,6 +3,12 @@ import { ChatHeader } from '@lobehub/ui';
|
|
3
3
|
import HeaderAction from './HeaderAction';
|
4
4
|
import Main from './Main';
|
5
5
|
|
6
|
-
const Header = () =>
|
6
|
+
const Header = () => (
|
7
|
+
<ChatHeader
|
8
|
+
left={<Main />}
|
9
|
+
right={<HeaderAction />}
|
10
|
+
style={{ minHeight: 64, position: 'initial', zIndex: 11 }}
|
11
|
+
/>
|
12
|
+
);
|
7
13
|
|
8
14
|
export default Header;
|
@@ -6,7 +6,6 @@ import { rgba } from 'polished';
|
|
6
6
|
import { PropsWithChildren, memo } from 'react';
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
8
8
|
|
9
|
-
import SafeSpacing from '@/components/SafeSpacing';
|
10
9
|
import { CHAT_DOCK_TOOL_UI_WIDTH, CHAT_DOCK_WIDTH, MAX_WIDTH } from '@/const/layoutTokens';
|
11
10
|
import { useChatStore } from '@/store/chat';
|
12
11
|
import { chatPortalSelectors } from '@/store/chat/slices/portal/selectors';
|
@@ -69,7 +68,6 @@ const PortalPanel = memo(({ children }: PropsWithChildren) => {
|
|
69
68
|
minWidth: CHAT_DOCK_WIDTH,
|
70
69
|
}}
|
71
70
|
>
|
72
|
-
<SafeSpacing />
|
73
71
|
<Flexbox className={styles.panel}>{children}</Flexbox>
|
74
72
|
</DraggablePanelContainer>
|
75
73
|
</DraggablePanel>
|
@@ -5,7 +5,6 @@ import { createStyles, useResponsive } from 'antd-style';
|
|
5
5
|
import isEqual from 'fast-deep-equal';
|
6
6
|
import { PropsWithChildren, memo, useEffect, useState } from 'react';
|
7
7
|
|
8
|
-
import SafeSpacing from '@/components/SafeSpacing';
|
9
8
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
10
9
|
import { useChatStore } from '@/store/chat';
|
11
10
|
import { chatPortalSelectors } from '@/store/chat/slices/portal/selectors';
|
@@ -71,7 +70,6 @@ const TopicPanel = memo(({ children }: PropsWithChildren) => {
|
|
71
70
|
minWidth: CHAT_SIDEBAR_WIDTH,
|
72
71
|
}}
|
73
72
|
>
|
74
|
-
<SafeSpacing />
|
75
73
|
{children}
|
76
74
|
</DraggablePanelContainer>
|
77
75
|
</DraggablePanel>
|
package/src/app/(main)/chat/@session/features/SessionListContent/Modals/ConfigGroupModal/index.tsx
CHANGED
@@ -13,7 +13,7 @@ import { SessionGroupItem } from '@/types/session';
|
|
13
13
|
|
14
14
|
import GroupItem from './GroupItem';
|
15
15
|
|
16
|
-
const useStyles = createStyles(({ css, token
|
16
|
+
const useStyles = createStyles(({ css, token }) => ({
|
17
17
|
container: css`
|
18
18
|
height: 36px;
|
19
19
|
padding-inline: 8px;
|
@@ -21,7 +21,6 @@ const useStyles = createStyles(({ css, token, stylish }) => ({
|
|
21
21
|
transition: background 0.2s ease-in-out;
|
22
22
|
|
23
23
|
&:hover {
|
24
|
-
${stylish.blur};
|
25
24
|
background: ${token.colorFillTertiary};
|
26
25
|
}
|
27
26
|
`,
|
@@ -43,10 +43,9 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
|
|
43
43
|
|
44
44
|
const data = useChatStore((s) => {
|
45
45
|
const showInboxWelcome = chatSelectors.showInboxWelcome(s);
|
46
|
-
|
46
|
+
return showInboxWelcome
|
47
47
|
? [WELCOME_GUIDE_CHAT_ID]
|
48
48
|
: chatSelectors.currentChatIDsWithGuideMessage(s);
|
49
|
-
return ['empty', ...ids];
|
50
49
|
}, isEqual);
|
51
50
|
|
52
51
|
useEffect(() => {
|
@@ -71,11 +70,7 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
|
|
71
70
|
(index: number, id: string) => {
|
72
71
|
if (id === WELCOME_GUIDE_CHAT_ID) return <InboxWelcome />;
|
73
72
|
|
74
|
-
return
|
75
|
-
<div style={{ height: 24 + (mobile ? 0 : 64) }} />
|
76
|
-
) : (
|
77
|
-
<Item id={id} index={index - 1} />
|
78
|
-
);
|
73
|
+
return <Item id={id} index={index} />;
|
79
74
|
},
|
80
75
|
[mobile],
|
81
76
|
);
|