Python 项目部署与启动排错 SOP
停止。执行任何操作前,必须完整阅读本文档。
本 Skill 的工具均指 bt_agent_mcp 插件暴露的 MCP 工具;同一能力在宝塔 AI 内置端可能有不同命名,按当前环境可用工具调用。
本 SOP 只覆盖两个主场景:① 部署 Python 项目;② 环境准备/启动排错。其他简单操作(状态查看、启停、日志、域名、改配置、装包、删除)不做 SOP,直接使用工具。
核心规则
- 先只读侦察,再执行变更 —— 部署前必须完成项目分析;排错先读日志,不盲目重启。
- 创建成功 ≠ 启动成功 —— Python 创建项目后环境准备(装依赖+生成启动脚本+尝试启动)是后台异步的。必须用
PythonProjectInfo 轮询 prep_status 到 complete,再核验进程存活 + 监听端口 + 日志无致命错误;prep_status=failure 立即转场景二。这是本场景最容易栽的坑。
- 建项目前必须有虚拟环境 —— 面板要求
python_bin 是已托管的 venv/conda(can_use_directly)。部署顺序:版本 → 环境 → 项目。
- Python 版本安装走 Bash 后台 —— 源码编译极慢(10-30 分钟),不得用同步工具卡住;必须
Bash(run_in_background=true) + BashStatus 轮询。
- 删除项目保留虚拟环境 —— venv 与项目非强绑定(可复用/共享),删除不删 venv(面板语义);如需移除单独用
PythonEnv(action='remove')。删除本身仍高风险(停进程/清配置/删记录),先确认。
- 绑域名 = 外网映射 + 反代 ——
add_domain 只写域名,需 bind_extranet 生成 nginx 配置(proxy 到 127.0.0.1:port);path→port 反代(add_proxy)必须先开启外网映射。
- 每个任务最多调用 15 次工具,超出后汇总当前发现并停止。
- 禁止操作:删除项目目录/源码、
rm -rf 项目目录、修改宝塔/插件自身文件、读取插件 data/ 凭据。
场景一:部署 Python 项目
Step 0 —— 预检
- 确认任务确为"部署新 Python 项目"(非排错/运维)。
- 确定运行方式
stype:uwsgi / gunicorn / command(直跑,python 文件方式已并入 command)。
- 确认协议:
wsgi(Flask/Django 传统)/ asgi(FastAPI/Sanic/uvicorn)。
- 需要外网域名访问时,确认 Nginx 已安装;否则只能本机/内网访问。
Step 1 —— 定位项目目录
- 用户给出
project_path(项目根,含 *.py),或:
- 用文件工具
Glob(pattern='**/*.py') / LS(path=...) 定位(排除 node_modules、dist、.venv、venv 等)。
- 校验:目录存在、含入口
*.py(或 requirements.txt)、非敏感目录(/etc、/boot、插件 data/ 等)。
Step 2 —— 分析项目(部署前必须)
调用 PythonProjectCreate(project_path=..., analyze_only=true)(只读,不创建)。返回:
framework:django/flask/sanic/fastapi 等(按 requirement/入口代码识别)。
runfile:入口文件、xsgi(wsgi/asgi)、call_app(可调用对象名)。
requirement_path:requirements 文件(缺 → 需先补)。
has_venv / port / port_hints:目录是否自带 venv、启发式端口(仅供参考)。
决策:
- 选
stype:Django/Flask 传统 → gunicorn(或 uwsgi);FastAPI/Sanic → gunicorn + xsgi='asgi';无框架/自写 socket → command(project_cmd='{python_bin} -u {runfile} {parm}')。
- 确认
rfile(启动文件绝对路径)与 call_app(app/application,或自动探测)。
- 无端口或启发式不准 → 询问用户,创建时显式传
port(uwsgi/gunicorn 必填;command 可空)。
Step 3 —— Python 版本确认 / 虚拟环境准备
PythonVersion(action='list') 查看已装 Python 版本与当前默认;返回含 install_hint。
- 需要新版本时
PythonVersion(action='online', ...) 浏览可安装版本(每项含 install_command),用 Bash 后台安装:
Bash(command=<install_command>, run_in_background=true) → 得到 task_id;
BashStatus(task_id, wait=true) 轮询到完成(后台最长 30 分钟,超时强杀;若超时汇报并让用户决定重跑/换源)。
PythonEnv(action='list') 查看虚拟环境:找 can_use_directly=true 的 venv;若需新建,看每项 source 与顶层 source_priority 判断源优先级。
- 没有可用 venv →
PythonEnv(action='create', venv_name=<项目名或自定义>, python_bin=<源环境bin>, ps=<备注>) 创建,得到 python_bin(venv_path + python_bin)。创建较慢(venv + ensurepip),创建成功返回后必须再跑一次 PythonEnv(action='list') 确认该 venv 出现在列表里且目录真实存在——工具已规避面板 create_venv_sync 的"只写记录不建目录"假成功缺陷并做磁盘校验,但仍建议复核。
源 python_bin 选择优先级(重要):① 面板安装的 Python 版本(source=panel_installed,如 /www/server/pyporject_evn/versions/<ver>/bin/python,推荐)→ ② 系统 Python(source=system,如 /usr/bin/python3,需有 venv/pip,缺则自动安装可能失败)→ ③ 面板自带 pyenv(source=panel_pyenv,/www/server/panel/pyenv——打包时移除过大量非必要文件,不适合普通用户,工具会直接拒绝)。优先用 PythonVersion 装好版本再作源。
Step 4 —— 创建项目(注册)
调用 PythonProjectCreate(project_name=..., project_path=..., python_bin=<第3步的venv>, stype=..., ...)。
按类型传参:
- uwsgi:
rfile + call_app + port(+ processes/threads)。
- gunicorn:
rfile + call_app + port;FastAPI/Sanic 加 xsgi='asgi'。
- command:
project_cmd(如 '{python_bin} -u {runfile}',占位符由工具替换为实际路径),port 可留 0。
- 通用:
user(默认 root)、env_list=[{"k","v"}](必须 dict 格式,如 [{"k":"PORT","v":"9000"}],字符串 "K=V" 会被 schema 拒绝)、env_file、requirement_path(有则自动装依赖)、auto_run、release_firewall(需外网访问时 true)、initialize(可选初始化命令)。
创建返回 prep_status=running(或 complete/failure)+ prep_log 路径。
Step 5 —— 环境准备等待 + 启动验证(强制)
PythonProjectInfo(project_name=...) 轮询 prep_status:running → 等待后重查(本地 sleep 即可,不调长工具);到 complete 继续,到 failure 立即转场景二分支 A。
- 核验启动:
run=true、应用端口在 listen 列表。
- 用返回的
log_files 里应用日志路径,调 filesystem Read 看尾部无致命异常(ImportError/ModuleNotFoundError/Address already in use/Error: [Errno 98])。
- 有域名映射的项目核验
services(关联进程)与反代。
- 全通过 → 按"完成汇报"收尾。
- 任一失败 → 转场景二排错。
场景二:环境准备 / 启动排错
适用:部署后验证失败(prep_status=failure / run=false)、或用户报"Python 项目启动失败/访问异常"。
Step 0 —— 快速定位现状(只读)
并行收集,不跳过:
PythonProjectInfo(project_name=...):prep_status、run、listen、log_files(区分"环境没准备好 / 进程没起来 / 起来了但访问不了")。
- 按症状读日志:
prep_status=failure 读环境准备日志(log_files 里 "环境准备日志");run=false 读应用日志(log_files 里 stype 对应项:error.log / uwsgi.log / gunicorn_error.log)。
- 已知配置:stype、入口文件、虚拟环境、端口、是否已装依赖。
收集后按症状进分支。
分支 A —— 环境准备失败(prep_status=failure)
- 读
log_files 里的"环境准备日志"(/www/server/python_project/vhost/logs/<name>.log)找根因:
| 日志特征 |
根因 |
处置 |
pip ... Could not find a version that satisfies |
依赖源/包名错 |
换 pip 源或 PythonEnv 手动装对应包;PythonProjectControl(action='restart') 重拉 |
ImportError / ModuleNotFoundError: No module named 'x' |
缺依赖 |
PythonEnv(action='package', python_bin=<env>, package_action='install', package_name='x') 后重启 |
configure: error / make: *** Error(装托管依赖失败) |
编译缺系统库 |
汇报,需安装系统依赖库后再 re_prep_env 或重建 |
uwsgi/gunicorn 命令 not found |
托管依赖没装上 |
同上 |
- 修复后
PythonProjectControl(action='restart')(或 action='start')重新拉取,回场景一 Step 5 复检。
分支 B —— 启动失败(进程起不来 / run=false,但 prep_status=complete)
按应用日志根因对号入座:
| 日志特征 |
根因 |
处置 |
ModuleNotFoundError / ImportError: No module named 'x' |
依赖未装 |
PythonEnv(action='package', python_bin=..., package_action='install', package_name='x') 后重启 |
Error: [Errno 98] Address already in use |
端口被占 |
PythonProjectModify(action='config', port=新端口) 后 PythonProjectControl(action='restart') |
[Errno 13] Permission denied |
目录/日志权限 |
PythonProjectModify(action='config', user=<有权限用户>) 或修目录属主 |
No module named 'app' / gunicorn.errors.HaltServer |
rfile/call_app 错 |
PythonProjectModify(action='config', rfile=/call_app=正确值) |
Command '('...')' returned non-zero exit status |
command 命令本身失败 |
检查 project_cmd 与环境变量 |
django.core.exceptions.ImproperlyConfigured |
Django settings 问题 |
检查 env_list 里的 DJANGO_SETTINGS_MODULE 等 |
| 进程起来但 pid 无/端口没监听 |
启动后立即退出 |
读日志尾找 Traceback 根因 |
- 无明确报错 → 查
PythonProjectInfo:run、listen、启动脚本(project_config)是否完整。
- 修复后回场景一 Step 5 重新验证。
分支 C —— 访问异常(502/无法访问,但进程活着)
PythonProjectInfo:进程在跑、端口在听吗?→ 不在则回分支 B。
- 映射/反代核对:
- 域名是否绑定、
bind_extranet 是否开启(未开启 → PythonProjectModify(action='add_domain', domains=[...]) + action='bind_extranet')。
listen(实际监听端口)vs project_config.port(反代目标)是否一致;grep proxy_pass python_<name>.conf(/www/server/panel/vhost/nginx/python_<name>.conf)确认反代指向 127.0.0.1:{实际端口}。
- path→port 反代缺失/指错 →
PythonProjectModify(action='add_proxy', proxy_path='/', proxy_port=实际端口)(需已开启外网映射)。
- 读 nginx error log(
/www/wwwlogs/<name>.error.log)进一步定位。
- 修正后验证。
分支 D —— 关联进程异常(celery worker 等)
PythonProjectService(project_name=..., action='list') 看各服务 pid/ports(主服务 sid='main' 之外为关联进程)。
- 某服务异常 →
action='log'(sid=...)读服务日志;action='start'/'stop'/'restart'(sid=...)重拉。
- 缺 celery →
PythonEnv(action='package', python_bin=..., package_action='install', package_name='celery')。
- 修正后
action='list' 复检 pid 存在。
分支 E —— 依赖问题(环境内包管理)
PythonEnv(action='package', python_bin=<虚拟环境>, package_action='list') 看已装包。
package_action='install'(package_name + 可选 package_version + 可选 pip_source)/ package_action='uninstall'(package_name)。安装慢,返回 log_tail。
- 修完回场景一 Step 5 验证。
日常运维速查(简单操作,直接按工具描述调用)
| 需求 |
工具 |
| 查看项目列表/状态 |
PythonProjectInfo()(project_name 留空) |
| 查看单项目详情(prep_status/run/listen/日志路径/服务) |
PythonProjectInfo(project_name=...) |
| 启动 / 停止 / 重启(含关联进程) |
PythonProjectControl(project_name, action='start'/'stop'/'restart') |
| 只启动 / 只停止主服务 |
PythonProjectControl(project_name, action='start_main'/'stop_main') |
| 看应用 / 环境准备 / 服务日志 |
PythonProjectInfo 返回 log_files → filesystem Read |
| 改端口/启动方式/入口/用户/环境变量/日志路径 |
PythonProjectModify(action='config', ...)(重启生效) |
| 加 / 删域名、开 / 关外网映射、path→port 反代 |
PythonProjectModify(action='add_domain'/'remove_domain'/'bind_extranet'/'unbind_extranet'/'add_proxy', ...) |
| Python 版本检测 / 在线浏览 / 移除 |
PythonVersion(action='list'/'online'/'remove', ...) |
| 安装 Python 版本(编译慢,后台) |
PythonVersion online 取 install_command → Bash(run_in_background=true) + BashStatus 轮询 |
| 虚拟环境列表 / 创建 / 移除 / 设默认 |
PythonEnv(action='list'/'create'/'remove'/'set_default', ...) |
| 环境内 pip 装 / 卸 / 列表 |
PythonEnv(action='package', python_bin=<env>, package_action='install'/'uninstall'/'list', ...) |
| 关联进程列表 / 启停 / 日志 / 删除(先停再删) |
PythonProjectService(project_name, action='list'/'start'/'stop'/'restart'/'log'/'remove', sid=...) |
删除项目(高风险,先确认;保留虚拟环境,需删除用 PythonEnv(action='remove')) |
PythonProjectDelete(project_name=...)(保留目录源码) |
⚠️ remove_domain 注意:面板移除域名会连带停止项目服务(主服务+协同服务,与是否剩最后一个域名无关,已实证、根因待定位)。工具不自动恢复(避免掩盖根因):移除后必须用 PythonProjectInfo 复核运行态,被停则手动 PythonProjectControl(action='start') 拉起。
add_domain 注意:对已存在的域名面板返回"已存在"=实际已绑定/可访问,工具按逐域结果如实上报(非失败);只有格式错误等才报错。
完成汇报模板(部署成功)
返回:项目名 / 运行方式(stype)/ 目录 / 虚拟环境 python_bin / 运行用户 / 监听端口;若绑域名:访问地址 + nginx 配置路径;环境准备状态(prep_status=complete)与启动验证结果(进程/端口/日志);关联进程清单;遗留隐患提示(依赖未装、requirements 缺失、env 未注入、端口启发不准等)。
1---2name: bt-python-project-deploy3description: 在宝塔面板上部署 Python 项目(uwsgi/gunicorn/command 三种运行方式,含虚拟环境配置、 Python 版本安装、requirements 依赖、Nginx 域名/反代),并在环境准备或启动失败时排错。 当用户要求把本机已有的 Python 项目目录部署成面板可管理的项目(含 Python 版本安装、 虚拟环境创建、pip 依赖、uwsgi/gunicorn 托管或自定义命令启动),或 Python 项目 启动失败/访问异常/环境准备失败需要排查根因时使用。 触发关键词:部署 Python、Python 项目部署、django/flask/fastapi/sanic 部署、 uvicorn/gunicorn/uwsgi、虚拟环境 venv、pip install、Python 项目启动失败、 ImportError、ModuleNotFoundError、502、访问异常、celery、关联进程、requirements。 日常的启停/状态/日志/改配置/装包等简单操作不依赖本 SOP,直接按工具描述调用即可。4---56# Python 项目部署与启动排错 SOP78> **停止。执行任何操作前,必须完整阅读本文档。**9> 本 Skill 的工具均指 bt_agent_mcp 插件暴露的 MCP 工具;同一能力在宝塔 AI 内置端可能有不同命名,按当前环境可用工具调用。10> 本 SOP 只覆盖两个主场景:**① 部署 Python 项目;② 环境准备/启动排错**。其他简单操作(状态查看、启停、日志、域名、改配置、装包、删除)不做 SOP,直接使用工具。1112---1314## 核心规则15161. **先只读侦察,再执行变更** —— 部署前必须完成项目分析;排错先读日志,不盲目重启。172. **创建成功 ≠ 启动成功** —— Python 创建项目后环境准备(装依赖+生成启动脚本+尝试启动)是**后台异步**的。必须用 `PythonProjectInfo` 轮询 `prep_status` 到 `complete`,再核验进程存活 + 监听端口 + 日志无致命错误;`prep_status=failure` 立即转场景二。**这是本场景最容易栽的坑。**183. **建项目前必须有虚拟环境** —— 面板要求 `python_bin` 是已托管的 venv/conda(`can_use_directly`)。部署顺序:版本 → 环境 → 项目。194. **Python 版本安装走 Bash 后台** —— 源码编译极慢(10-30 分钟),不得用同步工具卡住;必须 `Bash(run_in_background=true)` + `BashStatus` 轮询。205. **删除项目保留虚拟环境** —— venv 与项目非强绑定(可复用/共享),删除不删 venv(面板语义);如需移除单独用 `PythonEnv(action='remove')`。删除本身仍高风险(停进程/清配置/删记录),先确认。216. **绑域名 = 外网映射 + 反代** —— `add_domain` 只写域名,需 `bind_extranet` 生成 nginx 配置(proxy 到 127.0.0.1:port);path→port 反代(`add_proxy`)**必须先开启外网映射**。227. **每个任务最多调用 15 次工具**,超出后汇总当前发现并停止。238. **禁止操作**:删除项目目录/源码、`rm -rf` 项目目录、修改宝塔/插件自身文件、读取插件 `data/` 凭据。2425---2627# 场景一:部署 Python 项目2829## Step 0 —— 预检301. 确认任务确为"部署新 Python 项目"(非排错/运维)。312. 确定**运行方式 `stype`**:`uwsgi` / `gunicorn` / `command`(直跑,python 文件方式已并入 command)。323. 确认**协议**:`wsgi`(Flask/Django 传统)/ `asgi`(FastAPI/Sanic/uvicorn)。334. 需要外网域名访问时,确认 Nginx 已安装;否则只能本机/内网访问。3435## Step 1 —— 定位项目目录36- 用户给出 `project_path`(项目根,含 `*.py`),或:37- 用文件工具 `Glob(pattern='**/*.py')` / `LS(path=...)` 定位(排除 `node_modules`、`dist`、`.venv`、`venv` 等)。38- **校验**:目录存在、含入口 `*.py`(或 `requirements.txt`)、非敏感目录(`/etc`、`/boot`、插件 `data/` 等)。3940## Step 2 —— 分析项目(部署前必须)41调用 `PythonProjectCreate(project_path=..., analyze_only=true)`(只读,不创建)。返回:421. `framework`:django/flask/sanic/fastapi 等(按 requirement/入口代码识别)。432. `runfile`:入口文件、`xsgi`(wsgi/asgi)、`call_app`(可调用对象名)。443. `requirement_path`:requirements 文件(缺 → 需先补)。454. `has_venv` / `port` / `port_hints`:目录是否自带 venv、启发式端口(仅供参考)。4647**决策**:48- 选 `stype`:Django/Flask 传统 → `gunicorn`(或 `uwsgi`);FastAPI/Sanic → `gunicorn` + `xsgi='asgi'`;无框架/自写 socket → `command`(`project_cmd='{python_bin} -u {runfile} {parm}'`)。49- 确认 `rfile`(启动文件绝对路径)与 `call_app`(app/application,或自动探测)。50- 无端口或启发式不准 → 询问用户,创建时显式传 `port`(uwsgi/gunicorn 必填;command 可空)。5152## Step 3 —— Python 版本确认 / 虚拟环境准备531. `PythonVersion(action='list')` 查看已装 Python 版本与当前默认;返回含 `install_hint`。542. 需要新版本时 `PythonVersion(action='online', ...)` 浏览可安装版本(每项含 `install_command`),**用 Bash 后台安装**:55 - `Bash(command=<install_command>, run_in_background=true)` → 得到 `task_id`;56 - `BashStatus(task_id, wait=true)` 轮询到完成(后台最长 30 分钟,超时强杀;若超时汇报并让用户决定重跑/换源)。573. `PythonEnv(action='list')` 查看虚拟环境:找 `can_use_directly=true` 的 venv;若需新建,看每项 `source` 与顶层 `source_priority` 判断源优先级。584. 没有可用 venv → `PythonEnv(action='create', venv_name=<项目名或自定义>, python_bin=<源环境bin>, ps=<备注>)` 创建,得到 `python_bin`(venv_path + python_bin)。创建较慢(venv + ensurepip),**创建成功返回后必须再跑一次 `PythonEnv(action='list')` 确认该 venv 出现在列表里且目录真实存在**——工具已规避面板 `create_venv_sync` 的"只写记录不建目录"假成功缺陷并做磁盘校验,但仍建议复核。59 **源 python_bin 选择优先级(重要)**:① 面板安装的 Python 版本(`source=panel_installed`,如 `/www/server/pyporject_evn/versions/<ver>/bin/python`,**推荐**)→ ② 系统 Python(`source=system`,如 `/usr/bin/python3`,需有 venv/pip,缺则自动安装可能失败)→ ③ 面板自带 pyenv(`source=panel_pyenv`,`/www/server/panel/pyenv`——打包时移除过大量非必要文件,**不适合普通用户**,工具会直接拒绝)。优先用 `PythonVersion` 装好版本再作源。6061## Step 4 —— 创建项目(注册)62调用 `PythonProjectCreate(project_name=..., project_path=..., python_bin=<第3步的venv>, stype=..., ...)`。63按类型传参:64- **uwsgi**:`rfile` + `call_app` + `port`(+ `processes`/`threads`)。65- **gunicorn**:`rfile` + `call_app` + `port`;FastAPI/Sanic 加 `xsgi='asgi'`。66- **command**:`project_cmd`(如 `'{python_bin} -u {runfile}'`,**占位符由工具替换为实际路径**),`port` 可留 0。67- **通用**:`user`(默认 root)、`env_list=[{"k","v"}]`(**必须 dict 格式**,如 `[{"k":"PORT","v":"9000"}]`,字符串 "K=V" 会被 schema 拒绝)、`env_file`、`requirement_path`(有则自动装依赖)、`auto_run`、`release_firewall`(需外网访问时 true)、`initialize`(可选初始化命令)。68创建返回 `prep_status=running`(或 complete/failure)+ `prep_log` 路径。6970## Step 5 —— 环境准备等待 + 启动验证(强制)711. `PythonProjectInfo(project_name=...)` 轮询 `prep_status`:**`running` → 等待后重查**(本地 sleep 即可,不调长工具);到 `complete` 继续,到 `failure` **立即转场景二分支 A**。722. 核验启动:`run=true`、应用端口在 `listen` 列表。733. 用返回的 `log_files` 里应用日志路径,调 filesystem `Read` 看尾部无致命异常(`ImportError`/`ModuleNotFoundError`/`Address already in use`/`Error: [Errno 98]`)。744. 有域名映射的项目核验 `services`(关联进程)与反代。7576- 全通过 → 按"完成汇报"收尾。77- 任一失败 → **转场景二排错**。7879---8081# 场景二:环境准备 / 启动排错8283> 适用:部署后验证失败(prep_status=failure / run=false)、或用户报"Python 项目启动失败/访问异常"。8485## Step 0 —— 快速定位现状(只读)86并行收集,不跳过:871. `PythonProjectInfo(project_name=...)`:`prep_status`、`run`、`listen`、`log_files`(区分"环境没准备好 / 进程没起来 / 起来了但访问不了")。882. 按症状读日志:`prep_status=failure` 读**环境准备日志**(`log_files` 里 "环境准备日志");`run=false` 读**应用日志**(`log_files` 里 stype 对应项:error.log / uwsgi.log / gunicorn_error.log)。893. 已知配置:stype、入口文件、虚拟环境、端口、是否已装依赖。9091收集后按症状进分支。9293## 分支 A —— 环境准备失败(prep_status=failure)94- 读 `log_files` 里的"环境准备日志"(`/www/server/python_project/vhost/logs/<name>.log`)找根因:95 | 日志特征 | 根因 | 处置 |96 |---|---|---|97 | `pip ... Could not find a version that satisfies` | 依赖源/包名错 | 换 pip 源或 `PythonEnv` 手动装对应包;`PythonProjectControl(action='restart')` 重拉 |98 | `ImportError` / `ModuleNotFoundError: No module named 'x'` | 缺依赖 | `PythonEnv(action='package', python_bin=<env>, package_action='install', package_name='x')` 后重启 |99 | `configure: error` / `make: *** Error`(装托管依赖失败) | 编译缺系统库 | 汇报,需安装系统依赖库后再 `re_prep_env` 或重建 |100 | `uwsgi/gunicorn` 命令 not found | 托管依赖没装上 | 同上 |101- 修复后 `PythonProjectControl(action='restart')`(或 `action='start'`)重新拉取,回场景一 Step 5 复检。102103## 分支 B —— 启动失败(进程起不来 / run=false,但 prep_status=complete)104按应用日志根因对号入座:105| 日志特征 | 根因 | 处置 |106|---|---|---|107| `ModuleNotFoundError` / `ImportError: No module named 'x'` | 依赖未装 | `PythonEnv(action='package', python_bin=..., package_action='install', package_name='x')` 后重启 |108| `Error: [Errno 98] Address already in use` | 端口被占 | `PythonProjectModify(action='config', port=新端口)` 后 `PythonProjectControl(action='restart')` |109| `[Errno 13] Permission denied` | 目录/日志权限 | `PythonProjectModify(action='config', user=<有权限用户>)` 或修目录属主 |110| `No module named 'app'` / `gunicorn.errors.HaltServer` | rfile/call_app 错 | `PythonProjectModify(action='config', rfile=/call_app=正确值)` |111| `Command '('...')' returned non-zero exit status` | command 命令本身失败 | 检查 `project_cmd` 与环境变量 |112| `django.core.exceptions.ImproperlyConfigured` | Django settings 问题 | 检查 env_list 里的 DJANGO_SETTINGS_MODULE 等 |113| 进程起来但 pid 无/端口没监听 | 启动后立即退出 | 读日志尾找 `Traceback` 根因 |114115- 无明确报错 → 查 `PythonProjectInfo`:run、listen、启动脚本(`project_config`)是否完整。116- 修复后回场景一 Step 5 重新验证。117118## 分支 C —— 访问异常(502/无法访问,但进程活着)1191. `PythonProjectInfo`:进程在跑、端口在听吗?→ 不在则回分支 B。1202. **映射/反代核对**:121 - 域名是否绑定、`bind_extranet` 是否开启(未开启 → `PythonProjectModify(action='add_domain', domains=[...])` + `action='bind_extranet'`)。122 - `listen`(实际监听端口)vs `project_config.port`(反代目标)是否一致;grep `proxy_pass` `python_<name>.conf`(`/www/server/panel/vhost/nginx/python_<name>.conf`)确认反代指向 `127.0.0.1:{实际端口}`。123 - path→port 反代缺失/指错 → `PythonProjectModify(action='add_proxy', proxy_path='/', proxy_port=实际端口)`(**需已开启外网映射**)。1243. 读 nginx error log(`/www/wwwlogs/<name>.error.log`)进一步定位。1254. 修正后验证。126127## 分支 D —— 关联进程异常(celery worker 等)1281. `PythonProjectService(project_name=..., action='list')` 看各服务 pid/ports(主服务 sid='main' 之外为关联进程)。1292. 某服务异常 → `action='log'`(`sid=...`)读服务日志;`action='start'/'stop'/'restart'`(`sid=...`)重拉。1303. 缺 celery → `PythonEnv(action='package', python_bin=..., package_action='install', package_name='celery')`。1314. 修正后 `action='list'` 复检 pid 存在。132133## 分支 E —— 依赖问题(环境内包管理)134- `PythonEnv(action='package', python_bin=<虚拟环境>, package_action='list')` 看已装包。135- `package_action='install'`(`package_name` + 可选 `package_version` + 可选 `pip_source`)/ `package_action='uninstall'`(`package_name`)。安装慢,返回 `log_tail`。136- 修完回场景一 Step 5 验证。137138---139140# 日常运维速查(简单操作,直接按工具描述调用)141142| 需求 | 工具 |143|---|---|144| 查看项目列表/状态 | `PythonProjectInfo()`(project_name 留空) |145| 查看单项目详情(prep_status/run/listen/日志路径/服务) | `PythonProjectInfo(project_name=...)` |146| 启动 / 停止 / 重启(含关联进程) | `PythonProjectControl(project_name, action='start'/'stop'/'restart')` |147| 只启动 / 只停止主服务 | `PythonProjectControl(project_name, action='start_main'/'stop_main')` |148| 看应用 / 环境准备 / 服务日志 | `PythonProjectInfo` 返回 `log_files` → filesystem `Read` |149| 改端口/启动方式/入口/用户/环境变量/日志路径 | `PythonProjectModify(action='config', ...)`(重启生效) |150| 加 / 删域名、开 / 关外网映射、path→port 反代 | `PythonProjectModify(action='add_domain'/'remove_domain'/'bind_extranet'/'unbind_extranet'/'add_proxy', ...)` |151| Python 版本检测 / 在线浏览 / 移除 | `PythonVersion(action='list'/'online'/'remove', ...)` |152| **安装 Python 版本(编译慢,后台)** | `PythonVersion` online 取 `install_command` → `Bash(run_in_background=true)` + `BashStatus` 轮询 |153| 虚拟环境列表 / 创建 / 移除 / 设默认 | `PythonEnv(action='list'/'create'/'remove'/'set_default', ...)` |154| 环境内 pip 装 / 卸 / 列表 | `PythonEnv(action='package', python_bin=<env>, package_action='install'/'uninstall'/'list', ...)` |155| 关联进程列表 / 启停 / 日志 / **删除(先停再删)** | `PythonProjectService(project_name, action='list'/'start'/'stop'/'restart'/'log'/'remove', sid=...)` |156| 删除项目(**高风险,先确认**;保留虚拟环境,需删除用 `PythonEnv(action='remove')`) | `PythonProjectDelete(project_name=...)`(保留目录源码) |157158> ⚠️ **remove_domain 注意**:面板移除域名会连带停止项目服务(主服务+协同服务,与是否剩最后一个域名无关,已实证、根因待定位)。工具**不自动恢复**(避免掩盖根因):移除后必须用 `PythonProjectInfo` 复核运行态,被停则手动 `PythonProjectControl(action='start')` 拉起。159> **add_domain 注意**:对已存在的域名面板返回"已存在"=实际已绑定/可访问,工具按逐域结果如实上报(非失败);只有格式错误等才报错。160161---162163# 完成汇报模板(部署成功)164165返回:项目名 / 运行方式(stype)/ 目录 / 虚拟环境 python_bin / 运行用户 / 监听端口;若绑域名:访问地址 + nginx 配置路径;环境准备状态(prep_status=complete)与启动验证结果(进程/端口/日志);关联进程清单;遗留隐患提示(依赖未装、requirements 缺失、env 未注入、端口启发不准等)。