📖 概述
本文档记录了一个基于 Gradio + MySQL + OpenAI 兼容接口 的 Python Web 应用,如何从本地环境打包,通过 1Panel 面板 部署到腾讯云轻量应用服务器,并最终绑定自定义域名和 HTTPS 证书的完整过程。
部署架构: 用户浏览器 -> HTTPS (Nginx/OpenResty) -> 反向代理 -> Docker 容器 (Gradio 应用) -> Docker 容器 (MySQL)
🛠️ 第一阶段:本地项目准备与改造
1.1 代码修改 (app.py)
为了让 Gradio 应用能正常运行在 Docker 和反向代理后面,对 app.py 做了以下关键修改:
- 网络绑定:将
APP_HOST默认值改为0.0.0.0,允许外部访问。 - 代理路径:增加
GRADIO_ROOT_PATH环境变量读取,适配反向代理的子路径。 - 访问控制:增加
APP_AUTH_USER和APP_AUTH_PASS环境变量,便于测试阶段加锁防止 API 被滥用。 - 启动参数:将
theme从Blocks构造器移动到launch()方法,消除 Gradio 6.x 的警告。
1.2 依赖清单修正 (requirements.txt)
- 发现并补全了缺失的 PDF 导出依赖
fpdf2>=2.7.0。
1.3 编写 Dockerfile
创建了基于 python:3.11-slim 的 Dockerfile,关键优化点:
- 设置了
TZ=Asia/Shanghai保证日志时间正确。 - 更换国内镜像源:
RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt,解决了在云服务器上构建时因网络问题导致的超时失败。 - 暴露
7860端口,启动命令CMD ["python", "app.py"]。
1.4 准备服务器端 .env 文件
本地 .env 中的 DB_HOST=127.0.0.1 在 Docker 中会导致连接失败。服务器端的 .env 做了如下调整:
APP_HOST=0.0.0.0DB_HOST=[MySQL容器名称](而不是127.0.0.1)DB_USER和DB_PASSWORD使用独立创建的数据库账号,不使用root。
🗄️ 第二阶段:服务器数据库与文件准备
2.1 独立数据库隔离
在 1Panel 的【数据库】中新建了 MySQL 数据库:
- 数据库名:
ai_jianli - 用户名:
ai_jianli_user(独立账号,避免与博客数据库冲突) - 权限:
所有人 (%)(允许 Docker 容器网络访问)
2.2 上传项目文件
将项目文件上传到服务器 /opt/ai_jianli 目录,排除了不需要的文件(如 .venv、__pycache__、本地 .env、openspec 等),只保留:
app.py、requirements.txtutils/文件夹modules/文件夹Dockerfile- 服务器专用的
.env文件
🐳 第三阶段:构建镜像与启动容器
3.1 构建 Docker 镜像
在 1Panel 的【容器】->【镜像】中构建:
- 名称:
ai-jianli - 路径:
/opt/ai_jianli/Dockerfile - 标签:
latest
踩坑记录:第一次构建因 pip install 网络超时卡死,产生了一个悬空的“幽灵容器”占用镜像导致无法删除。通过强制停止并删除该容器,并修改 Dockerfile 加入清华源后,第二次构建成功(镜像体积约 523MB)。
3.2 创建并运行容器
在 1Panel 的【容器】中创建:
- 镜像:
ai-jianli:latest - 端口映射:
7860:7860 - 网络:必须与 MySQL 容器处于同一个 Docker 网络(如
1panel-network),否则无法连接数据库。 - 重启策略:失败后重启 / 总是重启。
- 存储卷挂载(推荐):将宿主机
/opt/ai_jianli/.env挂载到容器/app/.env,方便后续修改配置无需重新构建镜像。
3.3 验证启动日志
容器启动后,日志显示:
MySQL OK(数据库连接成功)数据库结构 OK,导入种子题目 38 道LLM OK,模型: [模型名称]启动 Gradio @ 0.0.0.0:7860- 此时通过
http://[服务器IP]:7860已可正常访问。
🌐 第四阶段:域名解析与反向代理
4.1 DNS 解析(关键踩坑)
- 域名在阿里云购买,但服务器在腾讯云,且域名 NS 已切换至腾讯云 DNSPod。
- 教训:必须在实际生效的 DNS 服务商(腾讯云 DNSPod)处添加解析记录,在阿里云控制台添加是无效的。
- 添加记录:主机记录
ai,类型A,记录值[服务器公网IP]。
4.2 创建反向代理网站
在 1Panel 的【网站】->【创建网站】中:
- 类型:反向代理
- 主域名:
ai.example.com - 代理地址:
127.0.0.1:7860(注意:不要写http://127.0.0.1:7860,1Panel 的输入框左边已经默认有http下拉框,重复会导致invalid port报错)。
🔒 第五阶段:SSL 证书与 HTTPS 配置
5.1 申请 Let’s Encrypt 证书
- 踩坑:最初使用“DNS账号”方式申请,因 NS 不在阿里云导致验证卡在“申请中”。
- 解决:放弃 DNS 验证,改为 “HTTP 文件验证”。由于域名已解析且 80 端口畅通,HTTP 验证 1 分钟内即签发成功。
- 在网站设置 -> HTTPS 中,开启 HTTPS,选择刚申请的证书,开启“强制 HTTPS”和 HSTS。
5.2 Nginx 配置调优(Gradio 专属)
Gradio 极度依赖 WebSocket 和流式输出。在【网站】->【配置文件】中确认 location / 块包含以下配置:
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 86400;
- 解决流式输出失效问题:如果发现 AI 翻译或回答是“一次性全部显示”而不是“打字机式流式输出”,在 Nginx 配置中加入
proxy_buffering off;并重载。
🛡️ 第六阶段:测试与安全加固
6.1 功能测试
- 访问
https://ai.example.com,页面正常加载,带有安全锁。 - 测试“翻译润色”和“简历生成”模块,功能正常。
- 测试“导出 DOCX”,文件可正常下载(PDF 导出因 Linux 缺少微软雅黑字体,暂时乱码,建议使用 DOCX)。
6.2 安全建议
- 关闭 7860 端口:在 1Panel 防火墙和腾讯云安全组中,关闭
7860端口的外部访问,仅保留 80 和 443,防止别人通过IP:7860绕过域名。 - 添加访问认证:在
.env中开启APP_AUTH_USER和APP_AUTH_PASS,重启容器生效,防止 API 额度被恶意消耗。 - 密钥轮换:如果在部署过程中不小心暴露过 API Key 或数据库密码,务必去对应控制台重新生成并更新
.env。
📋 附录:常见问题速查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
构建镜像时卡在 pip install | 网络超时 | Dockerfile 中加入清华源 -i https://pypi.tuna.tsinghua.edu.cn/simple |
容器启动后日志报 MySQL 不可达 | 网络不通或 DB_HOST 错误 | 确认 Gradio 容器与 MySQL 容器在同一 Docker 网络,DB_HOST 写 MySQL 容器名 |
反向代理创建报错 invalid port | 代理地址重复写了 http:// | 改为纯 IP + 端口格式 127.0.0.1:7860 |
| SSL 证书一直卡在“申请中” | DNS 验证失败(NS 不在当前平台) | 改用“HTTP 文件验证”方式申请证书 |
| 域名访问白屏或按钮点不动 | WebSocket 未配置 | Nginx 配置中加入 proxy_http_version 1.1 和 Upgrade 头 |
| AI 输出不是打字机效果 | Nginx 缓冲了响应 | Nginx 配置中加入 proxy_buffering off; |
文档生成时间:2026-09-11
部署环境:腾讯云轻量服务器 + Ubuntu + 1Panel + Docker