使用 Nginx 配置 HTTPS
确保您的用户与 Open WebUI 之间的通信安全是至关重要的。HTTPS (HyperText Transfer Protocol Secure) 对传输的数据进行加密,保护其免受窃听和篡改。通过配置 Nginx 作为反向代理 (reverse proxy),您可以无缝地为 Open WebUI 部署添加 HTTPS,从而提高安全性和可信度。
本指南提供了三种设置 HTTPS 的方法:
- 自签名证书 (Self-Signed Certificates):适用于开发和内部使用,使用 Docker。
- Let's Encrypt:非常适合需要受信任 SSL 证书的生产环境,使用 Docker。
- Windows+自签名证书:针对 Windows 上开发和内部使用的简化说明,无需 Docker。
WebSocket 连接中一个非常常见且难以调试的问题是跨源资源共享 (CORS) 策略配置错误。当在 Nginx Proxy Manager 等反向代理后运行 Open WebUI 时,您必须在 Open WebUI 配置中设置 CORS_ALLOW_ORIGIN 环境变量。
如果未设置此变量,将导致 WebSocket 连接失败,即使您已在 Nginx Proxy Manager 中启用了“Websockets 支持”。
HTTP/2 与 WebSockets
如果您在 Nginx 服务器上启用了 HTTP/2,请确保您与 Open WebUI 后端连接的代理配置仍然使用 HTTP/1.1。这至关重要,因为大多数 WebUI 功能(如流式传输和实时更新)都依赖 WebSocket,而在许多代理环境中,通过 HTTP/1.1 Upgrade 处理 WebSocket 比使用较新的 RFC 8441(基于 H2 的 WebSockets)更加稳定。
在您的 Nginx location 块中,请始终包含以下内容:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";这是导致 Markdown 乱码和流式响应中断最常见的原因。
当启用 Nginx 的 proxy_buffering 时(默认启用!),它会任意对 SSE 流重新分块。这会在分块边界处打断 Markdown 标记(例如,**bold** 变成了 ** + bold + **),从而导致输出损坏,出现可见的 ##、**,或遗漏单词。
您必须在 Nginx location 块中包含以下指令:
# 关键设置:禁用 SSE 流式传输的缓冲
proxy_buffering off;
proxy_cache off;如果您遗漏此设置,可能会出现以下异常现象:
- 出现裸露的 Markdown 标记(如
##,**,###) - 粗体/标题标记显示不正确
- 响应中随机丢失单词或段落
- 禁用缓冲时流式传输完美运行,启用后则损坏
额外好处: 禁用缓冲还会使流式响应的渲染速度明显变快,因为内容会直接流向客户端,而无需经历 Nginx 的缓冲延迟。
请选择最适合您的部署需求的方法。
- Nginx Proxy Manager
- Let's Encrypt
- 自签名证书
- Windows
Nginx Proxy Manager
Nginx Proxy Manager (NPM) 允许您轻松管理反向代理,并使用 Let's Encrypt 的有效 SSL 证书保护像 Open WebUI 这样的本地应用程序。
这种设置启用了 HTTPS 访问,由于安全要求的限制,这对于在许多移动浏览器上使用语音输入功能是必需的,且无需将应用程序的具体端口直接暴露到互联网。
前提条件
- 一台运行着 Docker 且 open-webui 容器正在运行的本地服务器。
- 一个域名(免费的如 DuckDNS,或付费的如 Namecheap/GoDaddy)。
- 具备 Docker 和 DNS 配置的基础知识。
Nginx Proxy Manager 操作步骤
-
为 Nginx 文件创建目录:
mkdir ~/nginx_config cd ~/nginx_config -
使用 Docker 安装 Nginx Proxy Manager:
nano docker-compose.ymlservices: app: image: 'jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: - '80:80' - '81:81' - '443:443' volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt运行容器:
docker-compose up -d -
配置 DNS 和域名:
- 登录您的域名提供商(如 DuckDNS)并创建一个域名。
- 将该域名指向您代理服务器的本地 IP 地址(例如:192.168.0.6)。
- 如果使用 DuckDNS,请从其控制面板获取一个 API Token。
这是一个在 https://www.duckdns.org/domains 中操作的简单示例
-
设置 SSL 证书:
- 通 过 http://server_ip:81 访问 Nginx Proxy Manager。例如:
192.168.0.6:81 - 使用默认凭据(admin@example.com / changeme)进行登录。按要求修改默认凭据。
- 前往 SSL Certificates → Add SSL Certificate → Let's Encrypt。
- 输入您的电子邮箱以及从 DuckDNS 获取的域名。一个域名包含星号,另一个不包含。例如:
*.hello.duckdns.org和hello.duckdns.org。 - 选择 Use a DNS challenge(使用 DNS 挑战验证),选择 DuckDNS,然后粘贴您的 API Token。例如:
dns_duckdns_token=f4e2a1b9-c78d-e593-b0d7-67f2e1c9a5b8 - 同意 Let's Encrypt 的条款并保存。如有必要,可更改 DNS 传播时间(例如 120 秒)。
- 通 过 http://server_ip:81 访问 Nginx Proxy Manager。例如:
-
创建 Proxy Hosts:
- 对于每个服务(例如 openwebui、nextcloud),前往 Hosts → Proxy Hosts → Add Proxy Host。
- 填写域名(例如:
openwebui.hello.duckdns.org)。 - 将 Scheme(协议)设置为 HTTP(默认),启用
Websockets support,并指向您的 Docker IP(如果运行 open-webui 的 Docker 容器与 Nginx Manager 位于同一台电脑上,这将与之前的 IP 相同(例如:192.168.0.6))。 - 选择之前生成的 SSL 证书,启用 Force SSL(强制 SSL),并启用 HTTP/2。
WebSocket 连接中一个非常常见且难以调试的问题是跨源资源共享 (CORS) 策略配置错误。当在 Nginx Proxy Manager 等反向代理后运行 Open WebUI 时,您必须在 Open WebUI 配置中设置 CORS_ALLOW_ORIGIN 环境变量。
如果未设置此变量,将导致 WebSocket 连接失败,即使您已在 Nginx Proxy Manager 中启用了“Websockets 支持”。
这是导致 Markdown 乱码和流式响应中断最常见的原因。
在 Nginx Proxy Manager 中,前往您的 proxy host → Advanced(高级)标签页 → 并在 Custom Nginx Configuration(自定义 Nginx 配置)字段中添加以下指令:
proxy_buffering off;
proxy_cache off;如果不配置此项,Nginx 会对 SSE 流重新分块,从而破坏 Markdown 格式(出现可见的 ##、** 以及遗漏单词)。禁用缓冲同时也会使流式响应的速度明显变快。
耗时较长的 LLM 生成任务(如处理复杂任务时可能需要 30 分钟以上)可能会超出默认的 60 秒超时时间。请在 Advanced 标签页 → Custom Nginx Configuration 中添加以下指令:
proxy_read_timeout 1800;
proxy_send_timeout 1800;
proxy_connect_timeout 1800;这会将超时时间设置为 30 分钟。您可以根据自身使用场景进行调整。
虽然 Nginx Proxy Manager 会自动处理大部分配置,但请注意:
- 为了提升性能,默认会缓存静态资源(CSS, JS, 图片)
- 身份验证端点绝对不应该被缓存
- 如果您在 NPM 的 "Advanced" 标签页中添加了自定义缓存规则,请确保排除以下路径:
/api/、/auth/、/signup/、/signin/、/sso/、/admin/、/signout/、/oauth/、/login/以及/logout/。
NPM 的默认配置会正确处理这些内容 —— 除非您非常 清楚自己在做什么,否则请不要轻易修改缓存配置。
示例:
如果您通过 https://openwebui.hello.duckdns.org 访问您的 Web UI,您必须设置:
CORS_ALLOW_ORIGIN="https://openwebui.hello.duckdns.org"您还可以提供以分号分隔的允许域名列表。请勿跳过此步骤。
:::
- 在 open-webui 中配置您的 URL(否则会遇到 HTTPS 错误):
- 前往您的 open-webui → 管理面板 → 设置 → 通用
- 在 Webhook URL 文本框中,输入您将通过 Nginx 反向代理连接到 open-webui 的 URL。例如:
hello.duckdns.org(对于此项不是必填项)或openwebui.hello.duckdns.org(对于此项是必填项)。
访问 WebUI
通过 HTTPS 在 hello.duckdns.org 或 openwebui.hello.duckdns.org(取决于您的设置方式)访问 Open WebUI。
防火墙注意事项:请注意,本地防火墙软件(如 Portmaster)可能会阻止 Docker 内部网络流量或所需的端口。如果您遇到问题,请检查您的防火墙规则,确保允许此配置所需的必要通信。
Let's Encrypt
Let's Encrypt 提供了大多数浏览器都信任的免费 SSL 证书,是保护您生产环境安全的理想选择。 🔐
本指南使用双阶段方法:
- 第一阶段: 临时运行 Nginx 以证明您拥有该域名,并从 Let's Encrypt 获取证书。
- 第二阶段: 重新配置 Nginx 以使用新证书,从而建立安全的 HTTPS 连接。
前提条件
- 一个域名(例如:
my-webui.com),且其 DNSA记录 已指向您服务器的公网 IP 地址。 - 服务器上已安装 Docker 和 Docker Compose。
- 具备在终端运行命令的基础知识。
请注意! Let's Encrypt 无法为 IP 地址签发证书。您必须使用域名。
步骤 1:证书验证的初始设置
首先,我们将设置必要的文件和临时的 Nginx 配置,以便 Let's Encrypt 的服务器验证您的域名。
-
确保您已满足上述前提条件。
-
创建目录结构
在您的项目根目录下,运行以下命令为 Nginx 配置和 Let's Encrypt 证书创建文件夹:
mkdir -p nginx/conf.d ssl/certbot/conf ssl/certbot/www -
创建临时 Nginx 配置
创建
nginx/conf.d/open-webui.conf文件。该初始配置仅监听 80 端口,并为 Certbot 提供验证文件服务。⚠️ 请务必将
<YOUR_DOMAIN_NAME>替换为 您的实际域名。# nginx/conf.d/open-webui.conf server { listen 80; listen [::]:80; server_name <YOUR_DOMAIN_NAME>; # 用于 Let's Encrypt 验证挑战的路由 location /.well-known/acme-challenge/ { root /var/www/certbot; } # 暂时忽略所有其他请求 location / { return 404; } } -
更新您的
docker-compose.yml将
nginx服务添加到您的docker-compose.yml中,并确保您的open-webui服务配置为使用共享的 Docker 网络。services: nginx: image: nginx:alpine restart: always ports: # 暴露 HTTP 和 HTTPS 端口到宿主机 - "80:80" - "443:443" volumes: # 挂载 Nginx 配置和 SSL 证书数据 - ./nginx/conf.d:/etc/nginx/conf.d - ./ssl/certbot/conf:/etc/letsencrypt - ./ssl/certbot/www:/var/www/certbot depends_on: - open-webui networks: - open-webui-network open-webui: # 您现有的 open-webui 配置... # ... # 确保它位于同一个网络中 networks: - open-webui-network # 在 Docker 网络内部暴露端口。 # 您不需要将其发布到宿主机(即此处不需要 `ports` 部分)。 expose: - 8080 networks: open-webui-network: driver: bridge
步骤 2:获取 SSL 证书
现在我们将运行一个使用 Docker 来获取证书的脚本。
-
创建证书请求脚本
在您的项目根目录中创建一个名为
enable_letsencrypt.sh的可执行脚本。⚠️ 请务必将
<YOUR_DOMAIN_NAME>和<YOUR_EMAIL_ADDRESS>替换为 您的实际信息。#!/bin/bash # enable_letsencrypt.sh DOMAIN="<YOUR_DOMAIN_NAME>" EMAIL="<YOUR_EMAIL_ADDRESS>" echo "### 正在获取 $DOMAIN 的 SSL 证书 ###" # 启动 Nginx 以服务于验证挑战 docker compose up -d nginx # 在容器中运行 Certbot 以获取证书 docker run --rm \ -v "./ssl/certbot/conf:/etc/letsencrypt" \ -v "./ssl/certbot/www:/var/www/certbot" \ certbot/certbot certonly \ --webroot \ --webroot-path=/var/www/certbot \ --email "$EMAIL" \ --agree-tos \ --no-eff-email \ --force-renewal \ -d "$DOMAIN" if [[ $? != 0 ]]; then echo "错误:获取 SSL 证书失败。" docker compose stop nginx exit 1 fi # 在应用最终配置之前停止 Nginx docker compose stop nginx echo "### 证书获取成功! ###" -
使脚本可执行
chmod +x enable_letsencrypt.sh -
运行脚本
执行脚本。它将自动启动 Nginx,请求证书,然后停止 Nginx。
./enable_letsencrypt.sh
重要提示:缓存配置
当将 Nginx 与 Open WebUI 结合使用时,合理的缓存对于性能至关重要,同时需要确保身份验证保持安全。以下配置包含:
- 已缓存的资源:静态资源(CSS, JS, 字体, 图片)以获得更好的性能
- 未缓存的资源:身份验证端点、API 调用、SSO/OAuth 回调和会话数据
- 效果:更快的页面加载速度,且不会破坏登录功能
以下配置将自动应用这些规则。
步骤 3:完成 Nginx 的 HTTPS 配置
证书保存到您的 ssl 目录后,您现在可以更新 Nginx 配置以启用 HTTPS。
-
更新 SSL 的 Nginx 配置
替换
nginx/conf.d/open-webui.conf的全部内容为以下最终配置。⚠️ 请将所有 4 处的
<YOUR_DOMAIN_NAME>替换为 您的域名。# nginx/conf.d/open-webui.conf # 将所有 HTTP 流量重定向到 HTTPS server { listen 80; listen [::]:80; server_name <YOUR_DOMAIN_NAME>; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name <YOUR_DOMAIN_NAME>; ssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN_NAME>/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/<YOUR_DOMAIN_NAME>/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256'; ssl_prefer_server_ciphers off; location ~* ^/(auth|api|oauth|admin|signin|signup|signout|login|logout|sso)/ { proxy_pass http://open-webui:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 10m; proxy_buffering off; proxy_cache off; client_max_body_size 20M; proxy_no_cache 1; proxy_cache_bypass 1; add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always; add_header Pragma "no-cache" always; expires -1; } # 用户头像和模型图片 - 缓存以提升性能 location ~ ^/api/v1/(users/[^/]+/profile/image|models/model/profile/image)$ { proxy_pass http://open-webui:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 缓存图片 1 天 expires 1d; add_header Cache-Control "public, max-age=86400"; } location ~* \.(css|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { proxy_pass http://open-webui:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 缓存静态资源 7 天 expires 7d; add_header Cache-Control "public, immutable"; } location / { proxy_pass http://open-webui:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 延长针对较长 LLM 生成时间的超时配置(30 分钟) proxy_read_timeout 1800; proxy_send_timeout 1800; proxy_connect_timeout 1800; proxy_buffering off; proxy_cache off; client_max_body_size 20M; add_header Cache-Control "public, max-age=300, must-revalidate"; } } -
启动所有服务
使用最终的安全配置启动 Nginx 和 Open WebUI。
docker compose up -d
步骤 4:访问您的安全 WebUI
您现在可以通过 HTTPS 安全地访问您的 Open WebUI 实例。
➡️ https://<YOUR_DOMAIN_NAME>
(可选)步骤 5:设置自动续期
Let's Encrypt 证书的有效期为 90 天。您应该设置一个 cron 定时任务来自动续期它们。
-
打开 crontab 编辑器:
sudo crontab -e -
添加以下行以在每天凌晨 3:30 运行续期检查。它只会在证书接近过期时进行续期。
30 3 * * * /usr/bin/docker run --rm -v "<absolute_path>/ssl/certbot/conf:/etc/letsencrypt" -v "<absolute_path>/ssl/certbot/www:/var/www/certbot" certbot/certbot renew --quiet --webroot --webroot-path=/var/www/certbot --deploy-hook "/usr/bin/docker compose -f <absolute_path>/docker-compose.yml restart nginx"
自签名证书
使用自签名证书适合于开发调 试或内部局域网环境,在这些场景下,证书是否由受信任的机构签发并不是首要考虑的因素。
自签名证书配置步骤
-
为 Nginx 文件创建目录:
mkdir -p conf.d ssl -
创建 Nginx 配置文件:
conf.d/open-webui.conf:server { listen 443 ssl; server_name your_domain_or_IP; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; ssl_protocols TLSv1.2 TLSv1.3; location ~* ^/(auth|api|oauth|admin|signin|signup|signout|login|logout|sso)/ { proxy_pass http://host.docker.internal:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_cache off; client_max_body_size 20M; proxy_read_timeout 10m; # 禁用身份验证端点的缓存 proxy_no_cache 1; proxy_cache_bypass 1; add_header Cache-Control "no-store, no-cache, must-revalidate" always; expires -1; } # 用户头像和模型图片 - 缓存以提升性能 location ~ ^/api/v1/(users/[^/]+/profile/image|models/model/profile/image)$ { proxy_pass http://host.docker.internal:3000; proxy_http_version 1.1; proxy_set_header Host $host; # 缓存图片 1 天 expires 1d; add_header Cache-Control "public, max-age=86400"; } location ~* \.(css|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { proxy_pass http://host.docker.internal:3000; proxy_http_version 1.1; proxy_set_header Host $host; # 缓存静态资源 7 天 expires 7d; add_header Cache-Control "public, immutable"; } location / { proxy_pass http://host.docker.internal:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_cache off; client_max_body_size 20M; # 针对较长 LLM 生成时间延长超时时间(30 分钟) proxy_read_timeout 1800; proxy_send_timeout 1800; proxy_connect_timeout 1800; add_header Cache-Control "public, max-age=300, must-revalidate"; } } -
生成自签名 SSL 证书:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout ssl/nginx.key \ -out ssl/nginx.crt \ -subj "/CN=your_domain_or_IP" -
更新 Docker Compose 配置:
在您的
docker-compose.yml中添加 Nginx 服务:services: nginx: image: nginx:alpine ports: - "443:443" volumes: - ./conf.d:/etc/nginx/conf.d - ./ssl:/etc/nginx/ssl depends_on: - open-webui -
启动 Nginx 服务:
docker compose up -d nginx
访问 WebUI
通过 HTTPS 访问 Open WebUI,地址如下:
在 Windows 上无需 Docker 使用自签名证书和 Nginx
对于基础的内部/开发部署,您可以使用 Nginx 和自签名证书将 Open WebUI 代理到 HTTPS,这允许在局域网 (LAN) 内使用麦克风输入等功能。(默认情况下,大多数浏览器不允许在不安全的非 localhost URL 上使用麦克风输入)。
本指南假设您是使用 pip 安装 Open WebUI,并且正在通过 open-webui serve 运行它。
步骤 1:安装 OpenSSL 以进行证书生成
您首先需要安装 OpenSSL。
您可以从 Shining Light Productions (SLP) 网站下载并安装预编译的二进制文件。
或者,如果您安装了 Chocolatey,可以使用它快速安装 OpenSSL:
-
打开命令提示符或 PowerShell。
-
运行以下命令安装 OpenSSL:
choco install openssl -y
验证安装
安装完成后,打开命令提示符并输入:
openssl version如果它显示了 OpenSSL 版本信息(例如 OpenSSL 3.x.x ...),则说明已成功安装。
步骤 2:安装 Nginx
从 nginx.org 下载官方适用于 Windows 的 Nginx,或使用像 Chocolatey 这样的包管理器。
将下载的 ZIP 文件解压到一个目录(例如 C:\nginx)。
步骤 3:生成证书
运行以下命令:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx.key -out nginx.crt将生成的 nginx.key 和 nginx.crt 文件移至您喜欢的文件夹中,或移至 C:\nginx 目录下。
步骤 4:配置 Nginx
在文本编辑器中打开 C:\nginx\conf\nginx.conf。
如果您希望在本地局域网 (LAN) 内访问 Open WebUI,请确保使用 ipconfig 命令记录下您的局域网 IP 地址,例如 192.168.1.15。
如下进行配置:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 120;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name 192.168.1.15;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name 192.168.1.15;
ssl_certificate C:\\nginx\\nginx.crt;
ssl_certificate_key C:\\nginx\\nginx.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
location ~* ^/(auth|api|oauth|admin|signin|signup|signout|login|logout|sso)/ {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
client_max_body_size 20M;
proxy_read_timeout 10m;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
expires -1;
}
# 用户头像和模型图片 - 缓存以提升性能
location ~ ^/api/v1/(users/[^/]+/profile/image|models/model/profile/image)$ {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
# 缓存图片 1 天
expires 1d;
add_header Cache-Control "public, max-age=86400";
}
location ~* \.(css|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
# 缓存静态资源 7 天
expires 7d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
client_max_body_size 20M;
# 针对较长 LLM 生成时间延长超时时间(30 分钟)
proxy_read_timeout 1800;
proxy_send_timeout 1800;
proxy_connect_timeout 1800;
add_header Cache-Control "public, max-age=300, must-revalidate";
}
}
}保存文件,并运行 nginx -t 检查配置是否无错误或语法问题。取决于您的安装方式,您可能需要先 cd C:\nginx。
通过运行 nginx 来启动 Nginx 服务。如果 Nginx 服务已经启动,您可以通过运行 nginx -s reload 来重新加载新配置 。
现在,您应该能够通过 https://192.168.1.15(或您自己的局域网 IP 地址)访问 Open WebUI。根据实际需要,确保在 Windows 防火墙中允许相关访问。
完整优化的 Nginx 配置
本部分提供了一个开箱即用的 Nginx 配置,针对 Open WebUI 的流式传输、WebSocket 连接和高并发部署进行了优化。
Upstream 配置
定义一个具有 keepalive 连接的 upstream,以减少连接建立的开销:
upstream openwebui {
server 127.0.0.1:3000;
keepalive 128; # 持久连接
keepalive_timeout 1800s; # 30 分钟
keepalive_requests 10000;
}超时配置
运行时间较长的 LLM 生成任务需要更长的超时时间:
location /api/ {
proxy_connect_timeout 1800; # 30 分钟
proxy_send_timeout 1800;
proxy_read_timeout 1800;
}
# WebSocket 连接需要更长的超时时间
location ~ ^/(ws/|socket\.io/) {
proxy_connect_timeout 86400; # 24 小时
proxy_send_timeout 86400;
proxy_read_timeout 86400;
}请求头和请求体大小限制
防止大请求或 OAuth 令牌导致的错误:
# 写入 http {} 或 server {} 块中
client_max_body_size 100M; # 大文件上传
proxy_buffer_size 128k; # 大请求头(如 OAuth 令牌)
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
large_client_header_buffers 4 32k;常见的流式传输错误
| 设置 | 对流式传输的影响 |
|---|---|
gzip on 伴随 application/json | 🔴 为了压缩而进行缓冲 |
proxy_buffering on | 🔴 缓冲整个响应 |
proxy_request_buffering on | 应该关闭 |
tcp_nodelay on | 🔴 最关键: 禁用 Nagle 算法以立即发送数据包(防止 200ms 延迟) |
chunked_transfer_encoding on | 🟡 可能会损坏 SSE |
在 /api/ 上启用 proxy_cache | 🟡 增加额外开销 |
X-Accel-Buffering "yes" | 为了额外安全起见,此标头应设置为 "no" |
HTTP/2 | 如果您遇到流式传输问题、卡顿,或在前端接收到最后一个分块之前流式传输就已结束,那么使用 HTTP 1.1 代替 HTTP/2 可能会有所帮助 |
完整示例配置
upstream openwebui {
server 127.0.0.1:3000;
keepalive 128;
keepalive_timeout 1800s;
keepalive_requests 10000;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL 配置...
# 压缩 - 排除流式传输的内容类型
gzip on;
gzip_types text/plain text/css application/javascript image/svg+xml;
# 绝对不要包含:application/json, text/event-stream
# API 端点 - 流式传输优化
location /api/ {
proxy_pass http://openwebui;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 关键设置:禁用流式传输的所有缓冲
gzip off;
proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;
tcp_nodelay on;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-store" always;
# 针对 LLM 响应延长超时时间
proxy_connect_timeout 1800;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
}
# WebSocket 端点
location ~ ^/(ws/|socket\.io/) {
proxy_pass http://openwebui;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
gzip off;
proxy_buffering off;
proxy_cache off;
# 针对持久连接使用 24 小时超时
proxy_connect_timeout 86400;
proxy_send_timeout 86400;
proxy_read_timeout 86400;
}
# 静态资源 - 可以进行缓冲和缓存
location /static/ {
proxy_pass http://openwebui;
proxy_buffering on;
proxy_cache_valid 200 7d;
add_header Cache-Control "public, max-age=604800, immutable";
}
# 默认路径
location / {
proxy_pass http://openwebui;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}缓存配置
合理的缓存可以通过减少后端负载并加快页面加载速度,显著提升 Open WebUI 的性能。本部分为希望实现服务器端和客户端缓存的高级用户提供指导。
缓存区域
在 Nginx 的 http 块中定义缓存区域以存储缓存的响应:
# 适用于页面和资源的基础缓存
proxy_cache_path /var/cache/nginx/openwebui levels=1:2
keys_zone=OPENWEBUI_CACHE:10m max_size=1g inactive=60m use_temp_path=off;
# 适用于头像图片的专用缓存(用户头像、模型头像)
proxy_cache_path /var/cache/nginx/openwebui_images levels=1:2
keys_zone=OPENWEBUI_IMAGES:10m max_size=2g inactive=7d use_temp_path=off;在 Nginx 使用这些目录之前,您必须创建它们并设置正确的权限:
sudo mkdir -p /var/cache/nginx/openwebui /var/cache/nginx/openwebui_images
sudo chown -R www-data:www-data /var/cache/nginx请将 www-data 替换为您的 Nginx 运行用户(通过 ps aux | grep nginx 查看)。常见的替代用户有:nginx、nobody。
缓存哪些内容
| 内容类型 | 缓存时长 | 备注 |
|---|---|---|
| 静态资源 (CSS, JS, 字体) | 7-30 天 | 对带有版本的资源使用 immutable |
| 用户/模型头像图片 | 1 天 | 权衡新鲜度与性能 |
静态文件 (/static/) | 7 天 | Favicon 图标、默认头像 |
| HTML 页面 | 5 分钟 | 带重新验证的短期缓存 |
| 上传的文件内容 | 1 天 | 用户上传的文件、生成的图像 |
绝对不能缓存的内容
以下路径绝对不能被缓存,以防安全隐患和登录失败问题:
/api/v1/auths/- 身份验证端点/oauth/- OAuth/SSO 回调/api/(通用) - 动态 API 响应/ws/- WebSocket 连接
请务必为身份验证端点包含以下指令:
proxy_no_cache 1;
proxy_cache_bypass 1;
add_header Cache-Control "no-store, no-cache, must-revalidate";示例:图片缓存
用户头像和模型图标能从缓存中大为受益:
# 用户和模型的头像图片
location ~ ^/api/v1/(users/[^/]+/profile/image|models/model/profile/image)$ {
proxy_pass http://your_backend;
proxy_cache OPENWEBUI_IMAGES;
proxy_cache_valid 200 302 1d;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
proxy_cache_key "$request_uri$is_args$args";
# 即使后端未设置缓存标头,也强制缓存
proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_hide_header Set-Cookie;
# 客户端缓存
add_header Cache-Control "public, max-age=86400, stale-while-revalidate=604800" always;
add_header X-Cache-Status $upstream_cache_status always;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}示例:静态资源缓存
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|otf|eot)$ {
proxy_pass http://your_backend;
proxy_cache OPENWEBUI_CACHE;
proxy_cache_valid 200 302 60m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header Cache-Control "public, max-age=2592000"; # 30 天
add_header X-Cache-Status $upstream_cache_status;
etag on;
if_modified_since exact;
}缓存调试
添加 X-Cache-Status 标头以验证缓存是否正常工作:
add_header X-Cache-Status $upstream_cache_status always;在浏览器的开发者工具中检查该标头:
HIT- 从缓存中提供服务MISS- 从后端获取,现在已缓存EXPIRED- 缓存已过期,已刷新BYPASS- 故意跳过缓存
权衡与取舍
如果积极地进行图片缓存,用户在修改头像后可能不会立即看到更新。您可以考虑:
- 较短的缓存时长(例如 1 小时),如果用户频繁更新图片
- 较长的缓存时长(例如 1 天),以在稳定的部署中获得更好的性能
- 可通过以下命令手动清除缓存:
rm -rf /var/cache/nginx/openwebui_images/*
后续步骤
设置 HTTPS 后,可通过以下方式安全地访问 Open WebUI:
如果您使用的是域名,请确保您的 DNS 记录已正确配置。对于生产环境,推荐使用 Let's Encrypt 获取可信的 SSL 证书。