1. 项目概述:为什么ChatGLM-6B需要Nginx与SSL?

如果你已经成功在本地或服务器上跑起了ChatGLM-6B的WebUI,看着它在浏览器里(通常是 http://localhost:7860 http://your-server-ip:7860 )欢快地运行,可能会觉得大功告成了。但作为一名有经验的部署者,我通常会立刻意识到两个核心问题: 安全 可用性 。直接暴露HTTP服务,尤其是在公网环境下,无异于“裸奔”——所有的对话数据、模型交互都是明文传输,极易被窃听或篡改。同时,一个IP加端口的访问方式既不专业,也难以记忆和分享。

这就是Nginx反向代理和SSL证书登场的时刻。简单来说,这个组合能帮你实现三件事:

  1. 加密通信 :通过HTTPS协议,为你的ChatGLM-6B WebUI套上一层坚固的“铠甲”,确保用户与AI助手之间的所有对话内容都是加密的。
  2. 统一入口 :你可以使用一个漂亮的域名(如 chat.yourdomain.com )来访问服务,隐藏后端复杂的端口和路径,提升专业度和易用性。
  3. 增强能力 :Nginx作为专业的Web服务器,能提供负载均衡、静态文件缓存、访问控制、限流等高级功能,为你的AI服务保驾护航。

本教程将手把手带你完成从零开始,为ChatGLM-6B WebUI配置Nginx反向代理并启用HTTPS的全过程。无论你是个人开发者想安全地对外提供服务,还是团队内部需要搭建一个可靠的AI对话平台,这套方案都经过了实战检验。

2. 环境准备与前置检查

在动手配置之前,我们需要确保基础环境是就绪的。这里假设你已经在一台Ubuntu 20.04或22.04 LTS的服务器上部署好了ChatGLM-6B的WebUI服务,并且它正运行在某个端口(例如7860)上。如果你还没部署,需要先完成那一步。

2.1 系统与网络环境确认

首先,通过SSH登录到你的服务器。我们需要确认几件关键事情:

检查ChatGLM-6B WebUI服务状态:

# 查看是否有Python进程在运行WebUI,通常与gradio或streamlit相关
ps aux | grep -E “(gradio|streamlit|python.*chat)”
# 或者直接检查7860端口是否被监听
sudo netstat -tulpn | grep :7860

如果看到类似 0.0.0.0:7860 127.0.0.1:7860 的监听信息,说明服务正常。 一个最佳实践是让WebUI仅监听本地回环地址(127.0.0.1) ,这样外部无法直接访问,只能通过Nginx代理,安全性更高。你可以在启动WebUI的命令中指定 --server-name 127.0.0.1 (对于Gradio)来实现。

检查服务器公网IP与防火墙: 确保你的服务器拥有一个公网IP地址,并且云服务商的安全组(或防火墙规则)已经放行了**80(HTTP) 443(HTTPS)**端口。这是后续申请SSL证书和提供Web服务的基础。你可以使用 curl ifconfig.me 查看公网IP,并用 sudo ufw status (如果使用UFW)检查防火墙规则。

准备一个域名: 你需要一个已经注册并可以管理的域名。这可以是向域名注册商购买的一级域名(如 yourdomain.com ),也可以是免费的二级域名。在域名的DNS管理后台,添加一条A记录,将你想要的子域名(例如 chat ai )指向你的服务器公网IP地址。DNS解析全球生效可能需要几分钟到几小时,你可以用 ping your-subdomain.yourdomain.com nslookup your-subdomain.yourdomain.com 来验证是否生效。

2.2 Nginx的安装与基础配置

如果你的系统还没有Nginx,安装它非常简单。我推荐使用官方仓库安装,以获得较新的稳定版本。

# 更新软件包列表
sudo apt update
# 安装Nginx
sudo apt install nginx -y

安装完成后,启动Nginx并设置开机自启:

sudo systemctl start nginx
sudo systemctl enable nginx

现在,在浏览器中访问你的服务器公网IP( http://<你的服务器IP> ),你应该能看到Nginx的默认欢迎页面。这说明Nginx已经成功安装并运行。

注意 :如果此时你无法访问欢迎页面,大概率是服务器的防火墙或云平台安全组没有放行80端口。请务必先去云服务商控制台检查“安全组”或“防火墙”设置,添加入站规则,允许TCP协议的80和443端口。

接下来,我们先清理一下默认配置,为我们的专属配置让路。Nginx的站点配置文件通常存放在 /etc/nginx/sites-available/ 目录,而通过创建符号链接到 /etc/nginx/sites-enabled/ 来启用。

# 移除默认站点的启用链接
sudo rm /etc/nginx/sites-enabled/default
# 可选:你也可以备份或删除sites-available里的默认文件
# sudo mv /etc/nginx/sites-available/default /etc/nginx/sites-available/default.backup

现在,环境准备就绪,我们可以进入核心的SSL证书申请环节了。

3. 申请与配置SSL证书(以Let‘s Encrypt为例)

要让我们的服务从HTTP升级到HTTPS,SSL证书是必需品。购买商业证书是一种选择,但对于个人项目和大多数场景, Let‘s Encrypt 提供的免费、自动化证书是绝佳选择。它的证书有效期为90天,但可以通过工具自动续期,实现永久免费。

3.1 安装Certbot客户端

Certbot是Let‘s Encrypt官方推荐的自动化证书管理工具。在Ubuntu上,我们可以通过Snap包管理器安装,这是目前最推荐的方式,能确保获得最新版本和最佳兼容性。

# 确保snapd已安装并运行
sudo apt install snapd -y
sudo snap install core
sudo snap refresh core
# 安装Certbot
sudo snap install --classic certbot
# 创建命令行软链接,方便直接使用certbot命令
sudo ln -s /snap/bin/certbot /usr/bin/certbot

3.2 使用Certbot申请证书

申请证书有多种验证方式,我们选择最通用的 --webroot 模式。这种方式下,Certbot会在你的Web根目录下创建一个临时文件,Let‘s Encrypt的服务器通过访问这个文件来验证你对域名的控制权。因此,需要确保你的Nginx正在运行,并且能够通过域名访问到。

首先,为你的域名创建一个Web根目录,并确保Nginx有读取权限:

sudo mkdir -p /var/www/chatglm-html
sudo chown -R www-data:www-data /var/www/chatglm-html
sudo chmod -R 755 /var/www/chatglm-html

然后,运行Certbot命令申请证书。请务必将 chat.yourdomain.com 替换为你实际解析到服务器的域名。

sudo certbot certonly --webroot \
  -w /var/www/chatglm-html \
  -d chat.yourdomain.com \
  --email your-email@example.com \
  --agree-tos \
  --non-interactive \
  --force-renewal

参数解释:

  • --webroot : 指定使用webroot验证模式。
  • -w /var/www/chatglm-html : 指定Web根目录路径,Certbot会在此创建 .well-known/acme-challenge/ 目录存放验证文件。
  • -d chat.yourdomain.com : 指定你要申请证书的域名。
  • --email : 用于接收证书过期提醒等重要通知的邮箱。
  • --agree-tos : 自动同意Let‘s Encrypt的服务条款。
  • --non-interactive : 非交互式运行,适合脚本自动化。
  • --force-renewal : 如果已有旧证书,强制更新。

如果一切顺利,你会看到类似 “Congratulations! Your certificate and chain have been saved at:” 的成功信息。证书和私钥通常存放在 /etc/letsencrypt/live/chat.yourdomain.com/ 目录下。关键文件有:

  • fullchain.pem : 完整的证书链(你的证书+中间CA证书),Nginx的 ssl_certificate 指令需要它。
  • privkey.pem : 你的私钥,Nginx的 ssl_certificate_key 指令需要它。

实操心得 :申请证书时最常见的错误是域名解析未生效或80端口被阻挡。务必先用 curl -I http://chat.yourdomain.com 测试一下,确保能收到Nginx的响应(哪怕是404),再进行申请。如果服务器在境内,且域名未备案,80端口可能被运营商拦截,这时可以尝试使用DNS验证模式( --preferred-challenges dns ),手动添加TXT记录来验证域名所有权,具体命令可查阅Certbot文档。

3.3 配置证书自动续期

Let‘s Encrypt证书只有90天有效期,手动续期太麻烦。幸运的是,Certbot提供了自动续期功能。实际上,安装Certbot时,它已经创建了一个systemd定时器(timer)或cron job来处理续期。我们可以手动测试一下续期流程是否畅通:

sudo certbot renew --dry-run

这个 --dry-run 参数会模拟续期过程而不真正操作,用于检查配置是否正确。如果看到 “The dry run was successful” 的提示,说明自动续期配置没问题。

Certbot的自动续期脚本会定期检查证书,并在到期前30天内自动续签。你无需额外操作。但为了保险起见,可以查看一下系统定时任务:

systemctl list-timers | grep certbot
# 或查看cron job
sudo cat /etc/cron.d/certbot

4. 配置Nginx反向代理与HTTPS

有了SSL证书,现在可以配置Nginx作为反向代理,将外部HTTPS请求安全地转发到内部运行的ChatGLM-6B WebUI服务。

4.1 创建Nginx服务器块(Server Block)配置

/etc/nginx/sites-available/ 目录下,为我们ChatGLM-6B服务创建一个新的配置文件,例如 chatglm

sudo nano /etc/nginx/sites-available/chatglm

将以下配置内容粘贴进去。 请务必替换所有 chat.yourdomain.com 为你的真实域名,并确认证书路径正确。

# HTTP服务器块,强制将所有HTTP请求重定向到HTTPS
server {
    listen 80;
    listen [::]:80; # 支持IPv6
    server_name chat.yourdomain.com; # 你的域名

    # 告诉Let‘s Encrypt验证程序,验证文件在这里
    location /.well-known/acme-challenge/ {
        root /var/www/chatglm-html;
    }

    # 将所有其他HTTP流量永久重定向(301)到HTTPS版本
    location / {
        return 301 https://$server_name$request_uri;
    }
}

# HTTPS服务器块
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name chat.yourdomain.com; # 你的域名

    # SSL证书路径(由Certbot申请)
    ssl_certificate /etc/letsencrypt/live/chat.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.yourdomain.com/privkey.pem;

    # SSL协议和加密套件配置,禁用不安全的旧版本
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # 启用SSL会话缓存,提升性能
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # 启用OCSP Stapling,提高SSL握手速度和隐私性
    ssl_stapling on;
    ssl_stapling_verify on;

    # 安全相关的HTTP响应头
    add_header Strict-Transport-Security “max-age=63072000; includeSubDomains; preload” always;
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection “1; mode=block” always;
    # 可选:内容安全策略,如果WebUI有复杂资源加载需求可能需要调整
    # add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’; style-src ‘self’ ‘unsafe-inline’; img-src ‘self’ data: https:;” always;

    # 核心:反向代理配置,将请求转发到本地的ChatGLM-6B WebUI
    location / {
        # 假设你的ChatGLM-6B WebUI运行在本地7860端口
        proxy_pass http://127.0.0.1:7860;

        # 传递原始客户端信息
        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; # 告诉后端这是HTTPS请求

        # WebSocket支持(Gradio等框架的WebUI常需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection “upgrade”;

        # 超时设置,AI模型推理可能耗时较长
        proxy_connect_timeout 300s;
        proxy_send_timeout 300s;
        proxy_read_timeout 300s;
        send_timeout 300s;

        # 禁用缓冲,对于流式响应(如ChatGLM的逐字输出)很重要
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_cache off;
    }

    # 可选:静态文件缓存,如果WebUI有大量静态资源可以提升性能
    # location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
    #     proxy_pass http://127.0.0.1:7860;
    #     proxy_cache_valid 200 302 6h;
    #     proxy_cache_valid 404 1m;
    #     add_header X-Cache-Status $upstream_cache_status;
    # }

    # 独立的访问日志和错误日志,便于排查问题
    access_log /var/log/nginx/chatglm_access.log;
    error_log /var/log/nginx/chatglm_error.log;
}

4.2 启用配置并测试Nginx

保存并退出编辑器(在nano中是 Ctrl+X ,然后按 Y ,再按 Enter )。接下来,启用这个站点配置:

# 创建从sites-available到sites-enabled的符号链接
sudo ln -s /etc/nginx/sites-available/chatglm /etc/nginx/sites-enabled/

在重启Nginx之前, 至关重要的一步是测试配置文件语法是否正确

sudo nginx -t

如果输出 nginx: configuration file /etc/nginx/nginx.conf test is successful ,恭喜你,配置语法没问题。如果有错误,它会明确指出错误行和原因,请根据提示回头检查配置文件。

测试通过后,重新加载Nginx配置使其生效:

sudo systemctl reload nginx
# 或者使用 restart,但reload更优雅,不会中断现有连接
# sudo systemctl restart nginx

4.3 验证HTTPS访问

现在,打开你的浏览器,访问 https://chat.yourdomain.com 。你应该能看到:

  1. 浏览器地址栏显示绿色的锁标志,表示连接是安全的。
  2. 成功加载ChatGLM-6B的WebUI界面。

你可以使用命令行工具快速验证:

curl -I https://chat.yourdomain.com

应该返回 HTTP/2 200 或者 HTTP/1.1 200 OK 的状态码。

注意事项 :如果遇到502 Bad Gateway错误,首要原因是Nginx无法连接到后端的ChatGLM-6B服务。请检查:

  1. ChatGLM-6B WebUI进程是否在运行? ps aux | grep :7860
  2. WebUI是否监听在 127.0.0.1:7860 而不是 0.0.0.0:7860 ?如果是后者,Nginx的 proxy_pass 也需要相应改为 http://服务器内网IP:7860 ,但监听本地回环地址更安全。
  3. 服务器本地防火墙(如UFW)是否允许Nginx进程访问7860端口? sudo ufw status verbose

5. 高级配置、优化与安全加固

基础配置完成后,我们的服务已经可以安全访问了。但对于生产环境,还需要一些优化和加固,以提升性能、稳定性和安全性。

5.1 性能优化配置

AI对话可能涉及较长的上下文和生成时间,我们需要调整Nginx的一些默认参数来适应。

在刚才的 server 块中,可以添加或调整以下指令:

# 在 server { ... } 块内添加
# 调整客户端请求体大小限制,如果上传大文件或长文本可能需要
client_max_body_size 50M;

# 增加各类超时时间,防止长对话或复杂推理超时
client_body_timeout 300s;
client_header_timeout 300s;
keepalive_timeout 300s;

# 启用Gzip压缩,减少网络传输量
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any; # 对代理的响应也进行压缩
gzip_comp_level 6;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/json
    application/javascript
    application/xml+rss
    application/atom+xml
    image/svg+xml;

5.2 安全加固配置

除了SSL和基础的安全头,我们还可以增加一些限制:

# 在 server { ... } 块内添加
# 限制HTTP请求方法,只允许GET, POST, HEAD等必要方法
if ($request_method !~ ^(GET|POST|HEAD|OPTIONS)$) {
    return 405;
}

# 限制特定目录的访问(如果WebUI有管理后台等路径)
# location /admin {
#     deny all;
#     return 404;
# }

# 防止非法Host头攻击
if ($host !~ ^(chat\.yourdomain\.com|yourdomain\.com)$ ) {
    return 444; # Nginx特有的444状态码,直接关闭连接
}

# 设置更严格的CSP(内容安全策略),根据WebUI实际加载的资源调整
# 初始配置可以较宽松,稳定后再收紧
# add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ https://cdn.jsdelivr.net; style-src ‘self’ ‘unsafe-inline’; img-src ‘self’ data: https:; font-src ‘self’ data:; connect-src ‘self’ wss:;” always;

5.3 负载均衡配置(可选)

如果你的ChatGLM-6B服务负载很高,或者为了高可用,可以在多台服务器上部署WebUI实例,然后用Nginx做负载均衡。

首先,在Nginx主配置文件( /etc/nginx/nginx.conf )的 http { ... } 块内,定义一个上游服务器组(upstream):

http {
    ...
    # 定义上游服务器组,名为chatglm_backend
    upstream chatglm_backend {
        # 假设你有三台运行WebUI的服务器
        server 192.168.1.101:7860 weight=3 max_fails=3 fail_timeout=30s; # 权重高,性能好
        server 192.168.1.102:7860 weight=2 max_fails=3 fail_timeout=30s;
        server 192.168.1.103:7860 weight=1 max_fails=3 fail_timeout=30s backup; # 备份服务器

        # 负载均衡算法,可选 least_conn(最少连接), ip_hash(会话保持)等
        # least_conn;
    }
    ...
}

然后,修改我们之前 server 块中的 location / 部分,将 proxy_pass 指向这个上游组:

location / {
    proxy_pass http://chatglm_backend;
    # 其余proxy_set_header等配置保持不变...
}

这样,Nginx就会将请求分发到上游服务器组中的各个实例。 weight 参数控制权重, backup 标记备份服务器(只有当主服务器都不可用时才启用)。 max_fails fail_timeout 定义了健康检查机制。

6. 故障排查、监控与日常维护

部署完成后,稳定的运行离不开持续的监控和及时的故障排查。

6.1 常见问题与解决方案速查表

问题现象 可能原因 排查命令与解决方案
502 Bad Gateway 后端ChatGLM-6B服务未启动或崩溃;端口不对;防火墙阻止。 1. ps aux | grep -E “(gradio|python)”
2. sudo netstat -tulpn | grep :7860
3. 检查WebUI日志。
4. curl -v http://127.0.0.1:7860 (在Nginx服务器上测试后端)。
SSL证书错误
(浏览器提示不安全)
证书路径错误;证书过期;证书域名不匹配。 1. sudo nginx -t 检查配置。
2. sudo certbot certificates 查看证书状态。
3. 检查Nginx配置中 ssl_certificate ssl_certificate_key 路径。
4. 使用 openssl x509 -in /path/to/fullchain.pem -text -noout 查看证书详情。
连接超时
(长时间无响应后断开)
Nginx或后端服务超时设置太短;服务器负载过高。 1. 在Nginx配置中增加 proxy_connect_timeout , proxy_read_timeout 等值(如300s)。
2. 检查服务器资源(CPU、内存、GPU)使用率: htop , nvidia-smi
3. 查看Nginx错误日志 tail -f /var/log/nginx/chatglm_error.log
413 Request Entity Too Large 客户端上传的数据(如长文本)超过了 client_max_body_size 限制。 在Nginx配置的 server http 块中增加 client_max_body_size 100M; (根据需求调整)。
WebSocket连接失败
(WebUI功能异常)
Nginx未正确配置WebSocket代理。 确保配置中包含 proxy_http_version 1.1; proxy_set_header Upgrade/Connection 指令。
域名访问跳转到默认页 Nginx配置中 server_name 未正确设置;默认站点未禁用。 1. 检查配置文件中 server_name 是否正确。
2. 确认 /etc/nginx/sites-enabled/ 下没有其他默认配置文件冲突。
3. sudo nginx -T | grep server_name 查看所有生效的server_name。

6.2 日志监控与分析

日志是排查问题的第一手资料。我们之前配置了独立的访问和错误日志。

  • 实时查看错误日志 sudo tail -f /var/log/nginx/chatglm_error.log 。当出现问题时,这里会有详细的错误信息。
  • 分析访问日志 sudo tail -f /var/log/nginx/chatglm_access.log 。可以查看访问来源、请求路径、状态码、响应时间等。
  • 使用日志分析工具 :对于长期运营,可以使用 goaccess awstats 等工具生成可视化的访问报告。
    sudo apt install goaccess
    goaccess /var/log/nginx/chatglm_access.log --log-format=COMBINED -o /var/www/html/report.html
    
    然后就可以通过浏览器查看详细的统计报告了。

6.3 自动化维护脚本

我们可以编写一个简单的Shell脚本,将日常维护任务自动化,比如检查证书有效期、清理旧日志、重载配置等。

创建脚本文件 /usr/local/bin/nginx_chatglm_maintain.sh

#!/bin/bash

echo “=== ChatGLM-6B Nginx 维护脚本开始运行 $(date) ===”

# 1. 检查SSL证书状态
echo “1. 检查SSL证书状态...”
sudo certbot certificates

# 2. 尝试续期即将过期的证书(Certbot会自动判断,这里只是手动触发检查)
echo -e “\n2. 尝试续期证书(模拟)...”
sudo certbot renew --dry-run
if [ $? -eq 0 ]; then
    echo “证书续期检查通过。”
else
    echo “警告:证书续期检查未通过,请手动检查。”
fi

# 3. 清理30天前的旧日志
echo -e “\n3. 清理旧日志文件...”
find /var/log/nginx -name “chatglm_*.log.*” -type f -mtime +30 -delete
echo “已清理30天前的日志压缩文件。”

# 4. 重新加载Nginx配置(如果配置测试成功)
echo -e “\n4. 测试并重载Nginx配置...”
if sudo nginx -t; then
    sudo systemctl reload nginx
    echo “Nginx配置已重载。”
else
    echo “错误:Nginx配置测试失败,请检查配置文件。”
    exit 1
fi

echo -e “\n=== 维护脚本执行完毕 $(date) ===”

给脚本添加执行权限,并添加到crontab中,例如每周一凌晨3点执行:

sudo chmod +x /usr/local/bin/nginx_chatglm_maintain.sh
sudo crontab -e
# 在crontab文件中添加一行
0 3 * * 1 /bin/bash /usr/local/bin/nginx_chatglm_maintain.sh >> /var/log/nginx_maintenance.log 2>&1

经过以上步骤,你的ChatGLM-6B WebUI就已经从一个简单的本地服务,升级为一个拥有自定义域名、HTTPS加密、经过性能优化和安全加固的准生产级应用了。这套Nginx反向代理+SSL的方案,其核心思想和配置同样适用于其他基于Web的AI模型服务,如Stable Diffusion WebUI、Ollama WebUI等,你只需要修改 proxy_pass 的后端地址和端口即可。

更多推荐