跳到主要内容

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

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";
重要提示:为 SSE 流式传输禁用代理缓冲

这是导致 Markdown 乱码和流式响应中断最常见的原因。

当启用 Nginx 的 proxy_buffering 时(默认启用!),它会任意对 SSE 流重新分块。这会在分块边界处打断 Markdown 标记(例如,**bold** 变成了 ** + bold + **),从而导致输出损坏,出现可见的 ##**,或遗漏单词。

您必须在 Nginx location 块中包含以下指令:

# 关键设置:禁用 SSE 流式传输的缓冲
proxy_buffering off;
proxy_cache off;

如果您遗漏此设置,可能会出现以下异常现象:

  • 出现裸露的 Markdown 标记(如 ##, **, ###
  • 粗体/标题标记显示不正确
  • 响应中随机丢失单词或段落
  • 禁用缓冲时流式传输完美运行,启用后则损坏

额外好处: 禁用缓冲还会使流式响应的渲染速度明显变快,因为内容会直接流向客户端,而无需经历 Nginx 的缓冲延迟。

请选择最适合您的部署需求的方法。

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 操作步骤

  1. 为 Nginx 文件创建目录:

    mkdir ~/nginx_config
    cd ~/nginx_config
  2. 使用 Docker 安装 Nginx Proxy Manager:

    nano docker-compose.yml
    services:
      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
  3. 配置 DNS 和域名:

    • 登录您的域名提供商(如 DuckDNS)并创建一个域名。
    • 将该域名指向您代理服务器的本地 IP 地址(例如:192.168.0.6)。
    • 如果使用 DuckDNS,请从其控制面板获取一个 API Token。
这是一个在 https://www.duckdns.org/domains 中操作的简单示例
  1. 设置 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.orghello.duckdns.org
    • 选择 Use a DNS challenge(使用 DNS 挑战验证),选择 DuckDNS,然后粘贴您的 API Token。例如: dns_duckdns_token=f4e2a1b9-c78d-e593-b0d7-67f2e1c9a5b8
    • 同意 Let's Encrypt 的条款并保存。如有必要,可更改 DNS 传播时间(例如 120 秒)。
  2. 创建 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

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 响应延长超时时间

耗时较长的 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"

您还可以提供以分号分隔的允许域名列表。请勿跳过此步骤。

:::

  1. 在 open-webui 中配置您的 URL(否则会遇到 HTTPS 错误):
  • 前往您的 open-webui → 管理面板 → 设置 → 通用
  • Webhook URL 文本框中,输入您将通过 Nginx 反向代理连接到 open-webui 的 URL。例如:hello.duckdns.org(对于此项不是必填项)或 openwebui.hello.duckdns.org(对于此项是必填项)。

访问 WebUI

通过 HTTPS 在 hello.duckdns.orgopenwebui.hello.duckdns.org(取决于您的设置方式)访问 Open WebUI。

备注

防火墙注意事项:请注意,本地防火墙软件(如 Portmaster)可能会阻止 Docker 内部网络流量或所需的端口。如果您遇到问题,请检查您的防火墙规则,确保允许此配置所需的必要通信。

完整优化的 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 查看)。常见的替代用户有:nginxnobody

缓存哪些内容

内容类型缓存时长备注
静态资源 (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 证书。


This content is for informational purposes only and does not constitute a warranty, guarantee, or contractual commitment. Open WebUI is provided "as is." See your license for applicable terms.