分类: 实战

  • 🚀 Gradio AI 应用云服务器部署总结文档


    📖 概述

    本文档记录了一个基于 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.0
    • DB_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.txt
    • utils/ 文件夹
    • 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

  • 第一份实战记录

    从零开始在云服务器上搭建WordPress博客并配置Redis缓存——一份完整的实战记录

    为什么要写这篇文章

    我有一台运行着Ubuntu Server 20.04 LTS的云服务器,一直想在上面搭建一个属于自己的个人博客。之前也断断续续折腾过,但总是半途而废。这次我决定认真地把这件事做完,从安装环境到网站上线,再到配置Redis缓存提升性能,整个过程都记录下来。

    这篇文章不是那种”几步搞定”的速成教程,而是一份真实的搭建日志。中间遇到了不少坑,也花了很多时间去排查和解决。如果你也在用1Panel搭建WordPress,或者正在为Redis缓存配置发愁,希望这篇记录能给你一些参考。

    如果你不想看我的反复犯错与纠错过程,教程是:

    在1Panel上搭建WordPress并配置Redis对象缓存:完整操作指南

    第一部分:基础环境搭建

    一、服务器与面板准备

    服务器是Ubuntu 20.04 LTS系统,我先在上面安装了1Panel面板。1Panel是一个基于Docker的服务器管理面板,界面友好,适合用来管理网站和各类应用。

    安装完成后,我通过1Panel的应用商店安装了以下基础组件:

    • OpenResty:基于Nginx的Web服务器,用于处理HTTP请求
    • MySQL 8.4.4:数据库,用于存储WordPress的数据

    这两步都很顺利,应用商店一键安装即可。

    二、创建PHP运行环境

    WordPress需要PHP环境来运行。1Panel自带了PHP环境,但为了后续方便安装Redis扩展,我决定手动创建一个新的PHP运行环境,版本选的是8.4.6。

    2.1 踩坑:Docker镜像拉取失败

    在创建PHP环境时,遇到了第一个拦路虎。构建过程中报错:

    镜像 build 失败: failed to solve: php:8.4.6-fpm-alpine: 
    failed to resolve source metadata ... 
    dial tcp: lookup docker.1panelproxy.com on 127.0.0.53:53: no such host

    原因是1Panel默认的Docker镜像加速地址 docker.1panelproxy.com 已经不可用了。1Panel的应用商店和运行环境都需要通过Docker拉取镜像,如果镜像加速地址无效,所有安装都会失败。

    解决方法:

    在1Panel的”容器”→”配置”→”镜像加速”中,将默认的加速地址替换为可用的源:

    https://docker.1panel.live

    修改保存后,再重新创建PHP环境,镜像拉取就成功了。

    2.2 选择合适的PHP扩展

    在创建PHP运行环境时,需要勾选一系列PHP扩展。对于WordPress,以下扩展是必要的:

    扩展作用
    opcachePHP脚本加速,必开
    redis连接Redis缓存(后续配置)
    imagick图片处理,比GD效果更好
    igbinary高效的序列化器,配合Redis使用
    bcmath某些高级插件需要
    exif图片元数据处理
    intl国际化支持

    2.3 踩坑:命名不规范导致识别问题

    第一次创建PHP环境时,我把名称填成了”Redis”,结果1Panel把它归类为应用商店的一个应用实例,而不是一个可选的PHP运行环境。在创建网站时,下拉列表里根本找不到这个环境。

    教训: 创建运行环境时,名称一定要规范清晰,比如 PHP8 或 php-8.4,方便后续识别和选择。

    三、创建WordPress网站

    3.1 选择合适的网站类型

    在1Panel中创建网站时,有两种相关类型:

    • “运行环境”类型:适用于需要PHP解释器的动态网站(如WordPress)
    • “反向代理”类型:适用于将请求转发到后端服务的场景

    如果要部署WordPress,应该选择”运行环境“类型,这样才能关联之前创建的PHP环境。

    3.2 踩坑:网站类型选错导致无法切换PHP环境

    我第一次创建时误选了”反向代理”类型,导致网站设置中根本没有”PHP运行环境”这个选项,无法切换到新创建的PHP8环境。

    解决方法: 删除错误的网站,重新选择”运行环境”类型创建。

    3.3 使用应用商店的WordPress还是手动部署?

    1Panel的应用商店提供了WordPress的一键安装,非常方便。我通过应用商店安装了WordPress,它会自动创建一个独立的Docker容器来运行WordPress。这种方式的好处是省去了手动下载和配置的步骤,但需要注意的是:

    • 应用商店安装的WordPress是一个独立的Docker容器,内部自带Apache和PHP
    • 它与我们在1Panel中创建的PHP运行环境是两套不同的PHP体系
    • 后续配置Redis扩展时,需要在WordPress容器内部操作

    四、配置反向代理让域名访问WordPress

    应用商店的WordPress容器默认运行在某个端口上(例如8964端口),我需要把域名指向这个容器。

    在1Panel的网站设置中,进入”反向代理”选项卡,添加规则:

    • 前端请求路径:/
    • 后端代理地址:http://[WordPress容器内部IP]:80

    踩坑:端口号要分清

    WordPress容器的端口映射是”宿主机8964端口→容器内部80端口”。OpenResty容器访问WordPress容器时,走的是容器内部网络,必须使用容器内部监听的端口(80),而不是宿主机映射的端口(8964)。

    如果写成8964,会报502错误,因为容器内部根本没有监听8964端口。

    第二部分:配置Redis对象缓存

    网站可以正常访问后,我决定进一步优化性能,为WordPress配置Redis对象缓存。

    五、安装Redis服务

    在1Panel应用商店中安装Redis,同样遇到了Docker镜像拉取失败的问题。解决方法一样:配置好镜像加速地址后重新安装。

    安全提醒:

    Redis安装成功后,默认会开放6379端口。务必在云服务器的安全组中关闭6379端口的外部访问。Redis默认没有强身份验证,暴露在公网很容易被扫描和攻击。

    六、在WordPress容器中安装Redis扩展

    6.1 为什么需要在容器内部安装?

    打开WordPress后台,安装”Redis Object Cache”插件后,诊断信息显示:

    PhpRedis: Not loaded
    PHP Version: 8.3.33

    这说明WordPress容器自带PHP 8.3.33,但这个PHP环境中没有安装Redis扩展。我们需要在容器内部手动安装。

    6.2 通过PECL编译安装Redis扩展

    进入WordPress容器的终端(在1Panel的容器列表中点击对应容器的”终端”按钮),执行以下步骤:

    第一步:安装编译工具

    apt-get update
    apt-get install -y gcc make autoconl

    第二步:安装PECL

    apt-get install -y php-pear

    第三步:编译安装Redis扩展

    pecl install redis

    编译过程中会询问一些选项(如是否启用igbinary、lzf等压缩支持),全部按回车使用默认值即可。

    第四步:启用扩展

    echo "extension=redis.so" > /usr/local/etc/php/conf.d/redis.ini
    php -m | grep redis  # 验证是否安装成功,应输出"redis"
    service apache2 restart

    七、配置Redis连接

    7.1 在wp-config.php中添加连接信息

    在WordPress容器的 /var/www/html/wp-config.php 文件中,添加Redis连接配置:

    define( 'WP_REDIS_HOST', '容器名' );
    define( 'WP_REDIS_PORT', 6379 );
    define( 'WP_REDIS_PASSWORD', '密码' );

    这里的”容器名”需要用实际的Redis容器名称替换。

    7.2 踩坑:连接地址写错了

    第一次配置时,我把 WP_REDIS_HOST 写成了 127.0.0.1。但WordPress容器和Redis容器是两个独立的Docker容器,WordPress容器内部的 127.0.0.1 指的是它自己,而不是Redis容器。

    解决方法: 用Redis容器的名称(如 1Panel-redis-[随机后缀])作为连接地址,因为同一Docker网络中的容器可以通过容器名互相访问。

    7.3 踩坑:密码认证失败

    Redis设置了密码,但WordPress没有提供密码。连接时被拒绝,报 NOAUTH Authentication required。

    解决方法: 在 wp-config.php 中添加 WP_REDIS_PASSWORD 常量。

    7.4 踩坑:wp-config.php中的常量未被读取

    即使正确配置了 wp-config.php,启用缓存后网站仍然报错。原因是 wp-config.php 中的常量定义位置不对——如果定义在 require_once(ABSPATH . 'wp-settings.php') 之后,object-cache.php 可能无法读取到这些常量。

    解决方法: 直接在 object-cache.php 文件开头强制定义连接常量。

    在 /var/www/html/wp-content/object-cache.php 的开头(<?php 之后)添加:

    if ( ! defined( 'WP_REDIS_HOST' ) ) {
        define( 'WP_REDIS_HOST', '1Panel-redis-[随机后缀]' );
    }
    if ( ! defined( 'WP_REDIS_PORT' ) ) {
        define( 'WP_REDIS_PORT', 6379 );
    }
    if ( ! defined( 'WP_REDIS_PASSWORD' ) ) {
        define( 'WP_REDIS_PASSWORD', '你的Redis密码' );
    }

    八、最终验证

    完成所有配置后,刷新WordPress后台的”设置→Redis”页面:

    • 状态显示为”已连接“
    • Redis版本显示为具体版本号
    • PhpRedis显示为”Loaded”

    此时,Redis对象缓存已经正式生效。网站的重复访问速度会有明显提升,数据库的查询压力也大大减轻。

    九、经验总结与架构梳理

    9.1 最终的架构

    用户浏览器
        ↓
    域名(your-domain.com)
        ↓
    OpenResty(监听80/443端口)
        ↓
    反向代理转发到 WordPress容器:80
        ↓
    WordPress容器(Apache + PHP + Redis扩展)
        ↓ ↓
    MySQL 8.4.4(数据库)  Redis(对象缓存)

    9.2 关键知识点

    1. Docker镜像加速必须配置好。1Panel默认的加速地址可能不可用,需要手动更换。
    2. 容器名比IP地址更可靠。Docker容器重启后IP可能变化,但同一网络中的容器名是稳定的。
    3. 分清”宿主机端口”和”容器内部端口”。反向代理时,容器间通信用的是容器内部端口。
    4. wp-config.php中的常量要尽早定义。最好放在 require_once(ABSPATH . 'wp-settings.php') 之前。
    5. object-cache.php是drop-in文件,优先级很高。只要这个文件存在,WordPress就会强制使用Redis缓存。
    6. PECL编译安装是apt-get的有力补充。当软件源中没有所需包时,PECL可以提供另一个安装途径。

    9.3 注意事项

    • 容器重建后扩展会丢失:如果WordPress容器被重建,之前用PECL安装的Redis扩展需要重新安装
    • 容器名可能会变化:每次重建应用时,容器名的随机后缀可能变化,记得同步更新配置
    • 安全第一:Redis的6379端口不要暴露到公网

    9.4 一点心得

    从安装面板到配置Redis缓存,一路遇到了不少问题:镜像拉取失败、网站类型选错、容器间网络不通、PHP扩展缺失、配置文件读取失败……每一个问题都花了不少时间去排查和解决。

    但也正是这些挫折让我对Docker容器、1Panel的工作机制、WordPress的缓存体系有了更深入的理解。

    如果你也在折腾同样的事情,希望这篇记录能帮你节省一些时间。遇到问题时,记住三步走:看日志、查配置、验证连通性。


    如果你在搭建过程中遇到类似的问题,欢迎在评论区交流。