Files
Nexus/docs/project/nexus-1panel-operations-knowledge.md
T
Nexus Agent b62f1039db feat(ops): add production probe with dual-path health checks.
SSH origin checks cover auth contracts and once-schedule create/delete
when external HTTPS is blocked; includes install script for probe credentials.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 03:28:17 +08:00

476 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nexus 6.0 — 1Panel + Docker 运维知识文档
| 项 | 内容 |
|----|------|
| 版本 | 2026-06-06round9 同步 god-menu 巡检 round48 |
| 读者 | 运维、接续开发、AI Agent |
| 定位 | **1Panel 生产部署 SSOT**(安装向导、网络、MySQL/Redis、日常 nx update |
| 关联 | [deploy/README-1panel.md](../../deploy/README-1panel.md) · [nexus-god-menu-audit-summary.md](nexus-god-menu-audit-summary.md) · [nexus-functional-development-guide.md](nexus-functional-development-guide.md) · [2026-06-04-1panel-docker-production.md](../design/plans/2026-06-04-1panel-docker-production.md) |
---
## 1. 架构总览
### 1.1 生产拓扑(1Panel
```mermaid
flowchart LR
Internet --> OpenResty["OpenResty (host)"]
OpenResty -->|"127.0.0.1:8600"| Nexus["Nexus 容器"]
Nexus -->|"1Panel-mysql-xxxx:3306"| MySQL["1Panel MySQL"]
Nexus -->|"1Panel-redis-xxxx:6379"| Redis["1Panel Redis"]
Nexus --- VolState["卷 nexus-state (.env)"]
Nexus --- VolData["卷 nexus-web-data"]
MySQL --- Net["1panel-network"]
Redis --- Net
Nexus --- Net
```
**铁律**[1Panel 官方说明](https://github.com/1Panel-dev/1Panel/issues/11676)):
- 应用商店 MySQL/Redis 在 **`1panel-network`** 上,容器间用 **容器名** 通信。
- **禁止**在 Nexus 容器内用 `127.0.0.1``localhost``host.docker.internal` 连 1Panel MySQL/Redis。
- OpenResty 在宿主机网络,反代目标为 **`http://127.0.0.1:8600`**。
### 1.2 仓库关键目录
| 路径 | 职责 |
|------|------|
| `server/` | FastAPI 后端;`api/install.py` = 安装向导 API |
| `frontend/` | Vue 3 SPA 源码(14 页) |
| `web/app/` | 构建产物;**`install.html` 为独立静态页**Alpine.js,不经 Vite 路由) |
| `web/data/` | 运行时:`config.json``1panel-hosts.json` |
| `deploy/` | 1Panel 安装/升级、`nx`、验收与修复脚本 |
| `docker/` | `docker-compose.prod.yml``entrypoint.sh``.env.prod` |
| `Dockerfile.prod` | 多阶段:npm build + Python 镜像 |
### 1.3 两套 Compose
| 文件 | 服务 |
|------|------|
| `docker-compose.yml` | 本地 devnexus + mysql + redis |
| `docker-compose.prod.yml` | **生产:仅 nexus** |
| `docker-compose.1panel.yml` | 叠加:nexus 加入 `1panel-network` |
---
## 2. 启动模式与 `.env` 生命周期
### 2.1 安装模式 vs 正常模式
`server/main.py``is_install_mode()`**运行时**检测 `/app/.env` 是否存在。
| 模式 | 条件 | 可用能力 |
|------|------|----------|
| 安装模式 | 无 `/app/.env` | `/api/install/*``/app/install.html`、静态、`/health` |
| 正常模式 | 有完整 `.env` | 全 API、WebSocket、后台任务 |
### 2.2 配置存储四层
| 层级 | 位置 | 写入方 |
|------|------|--------|
| Compose 环境 | 宿主机 `docker/.env.prod` | `nexus-1panel.sh install` / `generate_nexus_secrets.py` |
| 应用根 | 容器 `/app/.env` | 安装向导步骤 3 `init-db` |
| 持久卷 | `nexus-state``/var/lib/nexus/.env` | `entrypoint.sh` 退出时同步 |
| Web 数据 | `nexus-web-data``/app/web/data/` | `config.json``1panel-hosts.json` |
**不可从 DB settings 覆盖**`SECRET_KEY``API_KEY``ENCRYPTION_KEY``DATABASE_URL`
### 2.3 Docker 安装状态机
```
install --fresh
→ docker/.env.prod: NEXUS_INSTALL_WIZARD_PENDING=1 + 预生成三密钥
→ entrypoint 不写 /app/.env,不阻塞等待 MySQL/Redis
浏览器步骤 3 init-db
→ 写 /app/.env、config.json、settings、.install_state.json
步骤 4 create-admin
→ 写 admins,自动 lock.install_locked
步骤 5 lock / entrypoint
→ install.html 重命名为 install.html.bak(外网 /app/install.html → 404
→ 安装锁双写:/app/.install_locked + /var/lib/nexus/.install_locked
entrypoint EXIT trap
→ /app/.env 复制到 nexus-state
```
**重要**:仅删除 1Panel 里的 MySQL 库 **不会** 清除 `/app/.env`;向导会提示「系统已初始化,无法重复执行数据库安装」。重装需删卷内 `.env` 并设 `NEXUS_INSTALL_WIZARD_PENDING=1`(见 §7.6)。
---
## 3. 安装向导(5 步)
### 3.1 流程与 API
| 步 | UI | API | 说明 |
|----|-----|-----|------|
| 1 | 欢迎 | — | 准备项 |
| 2 | 环境检测 | `GET /api/install/env-check` | TCP 探测 MySQL/Redis;返回 `docker_defaults` |
| 3 | 数据库配置 | `POST /api/install/test-credentials` | **必须先检测账号密码** |
| 3 | 初始化 | `POST /api/install/init-db` | 建表、三写、发 `install_token`**.env 已存在则 403** |
| 4 | 管理员 | `GET /api/install/connection-check` | 读 `.env` 验 MySQL+Redis |
| 4 | 创建 admin | `POST /api/install/create-admin` | 需 `install_token` |
| 5 | 完成 | `POST /api/install/lock`(兜底) | 写 `.install_locked`**Docker 模式展示 1Panel 守护清单** |
辅助:`GET /status``GET /state`(断点续装;**白名单脱敏**,不含 `install_token`/`redis_pass`,有 token 时仅 `has_token: true`)。
实现文件:`server/api/install.py``web/app/install.html`
### 3.2 步骤 3 表单(1Panel 正确填法)
| 字段 | MySQL | Redis |
|------|-------|-------|
| 主机 | `1Panel-mysql-xxxx` | `1Panel-redis-xxxx` |
| 端口 | `3306` | `6379` |
| 库名 | `nexus` | 库号 `0` |
| 用户名 | `nexus` | **无**1Panel Redis 无账号;向导仅填密码) |
| 密码 | 1Panel「数据库」里建的 nexus 密码 | 1Panel Redis **应用参数**中的口令 |
### 3.3 进程守护(1Panel Docker
| 层级 | 机制 | 说明 |
|------|------|------|
| Layer 1 | Compose `restart: unless-stopped` + `healthcheck` | 容器崩溃自动拉起 |
| Layer 2 | Python `self_monitor`(30s) | 向导完成后正常模式自动运行 |
| Layer 3 | 宿主机 OpenResty + 可选 `health_monitor.sh` | 反代 `127.0.0.1:8600`;见 `deploy/1panel/openresty-nexus.conf.example` |
`init-db``NEXUS_DOCKER_WRITE_ENV=1` 时调用 `_configure_docker_guardian`**不**在容器内写 Supervisor)。
### 3.4 Docker 预填来源
优先级(`_onepanel_service_host`):
1. 环境变量 `NEXUS_1PANEL_DB_HOST` / `NEXUS_1PANEL_REDIS_HOST`
2. `/app/web/data/1panel-hosts.json``nx update` 写入卷)
3. 回退 `host.docker.internal`**1Panel 场景错误**
`env-check``NEXUS_DOCKER_WRITE_ENV=1` 时返回 `docker_defaults`(主机/端口/库名,**不含** Redis 用户名)。前端会覆盖 stale 的 `127.0.0.1` / `host.docker.internal`,并隐藏 Redis 用户名字段。
### 3.5 连接 URL 格式(必读)
**MySQL**(写入 `NEXUS_DATABASE_URL`):
```
mysql+aiomysql://nexus:密码@1Panel-mysql-xxxx:3306/nexus
```
**Redis**(写入 `NEXUS_REDIS_URL`)— `server/api/install.py` `_build_redis_url`
| 场景 | URL 格式 |
|------|----------|
| 1Panel(常见,推荐) | `redis://:密码@1Panel-redis-xxxx:6379/0`(向导用户名留空) |
| 1Panel ACL default | `redis://default:密码@1Panel-redis-xxxx:6379/0` |
| 无密码 | `redis://1Panel-redis-xxxx:6379/0` |
**历史 bug807f4c2 前)**:生成 `redis://密码@host` 会把密码当成**用户名**,导致 `invalid username-password pair or user is disabled`。升级后须 `git pull` + `sync-install-wizard-to-container.sh`
---
## 4. 1Panel 部署流程
### 4.1 前置
1. 安装 1Panel + Docker
2. 应用商店安装 **MySQL**、**Redis**(自动创建 `1panel-network`
3. 1Panel「数据库」:库 `nexus`、用户 `nexus`(仅授权 `nexus` 库)
4. 记录 Redis 应用参数中的 **连接口令**(不是 MySQL 式账号)
### 4.2 安装 Nexus
```bash
# 新机(curl
curl -fsSL "http://66.154.115.8:3000/admin/Nexus/raw/branch/main/deploy/quick-install.sh" | bash
# 或已有仓库
cd /opt/nexus && bash deploy/install-nexus-fresh.sh --skip-clone
```
完成后:`https://<域名>/app/install.html`
### 4.3 `nx update` 自动 sync2026-06-06 根治版)
`deploy/nexus-1panel.sh` 在 install/upgrade 时:
1. `detect-1panel-services.sh` 探测容器名
2. 写入 `docker/.env.prod``NEXUS_1PANEL_*_HOST``NEXUS_REDIS_URL` 优先保留卷/向导中的 `redis://:pass@host`**不经 Compose 注入容器**
3. `write_1panel_hosts_volume``1panel-hosts.json`
4. 若存在 `1panel-network`,叠加 `docker-compose.1panel.yml`(仅 networks,无重复 environment
5. **已锁定**`sync_env_prod_to_volume``docker/.env.prod` 三密钥 + `NEXUS_REDIS_URL`/`NEXUS_DATABASE_URL` 双写至 `nexus-state`
6. **已锁定**`set_install_complete``NEXUS_INSTALL_WIZARD_PENDING=0` 回写 `docker/.env.prod`
### 4.4 OpenResty
- 1Panel → 网站 → 反代 `http://127.0.0.1:8600`
- HTTPS Let's Encrypt
- 参考:`deploy/1panel/openresty-nexus.conf.example``/ws/` 超时 ≥ 3600s
- **禁止**脚本修改 `/opt/1panel/apps/openresty/`
### 4.5 资源档位
| Profile | 说明 |
|---------|------|
| `1c4g` | 小机 |
| `2c8g` | 默认 |
| `4c16g` | `--profile 4c16g` |
持久化:`docker/.host-profile`
---
## 5. 日常运维:`nx` 与 `update`
| 命令 | 等价 |
|------|------|
| `nx` | 交互菜单 |
| `nx update` | `deploy/update.sh``nexus-1panel.sh upgrade` |
| `nexus-update` | 同上 |
**upgrade 顺序**2026-06-06 god-menu round48+):
```
git fetch → MySQL 备份(mysql_dump_to_file.shdocker exec 1Panel MySQL)→ git reset --hard
→ sync_1panel_service_hosts → sync_env_prod_to_volume → NEXUS_HOST_ROOT 写入 .env.prod
→ tag 当前镜像为 nexus-prod-nexus:rollback
→ compose build → 镜像门控 (import server.main)
→ compose up -d --no-build → verify_nexus_1panel_network
→ 已锁定:跳过 install.html 热同步;未锁定且非 200 才 sync-install-wizard
→ set_install_complete → verify_health
→ TTYprompt_ops_cron_if_missing;已锁定:verify-1panel-install-wizard.sh
→ 健康失败:自动 tag rollback + up -d 回滚
```
`deploy/upgrade.sh``deploy-production.sh` 等会自动识别 **Docker vs Supervisor**Docker 路径委托 `nexus-1panel.sh upgrade`
| 参数 | 含义 |
|------|------|
| `--check` | 仅查 Git |
| `--no-cache` | 无缓存重建镜像 |
| `--no-backup` | 跳过 mysqldump |
| `--require-backup` | mysqldump 失败则中止升级 |
| `--prune` | 清理悬空镜像 |
**推荐更新方式**`cd /opt/nexus && bash deploy/update.sh``curl \| bash` 会回退 `/opt/nexus` 并打印警告)。
### 5.1 密钥 / Redis URL 轮换(双写)
已锁定生产环境运行时以 **卷内** `/var/lib/nexus/.env` 为准。轮换步骤:
1. 修改宿主机 `docker/.env.prod``NEXUS_SECRET_KEY` / `NEXUS_API_KEY` / `NEXUS_ENCRYPTION_KEY``NEXUS_REDIS_URL`
2. 执行 `sudo nx update` — 脚本 `sync_env_prod_to_volume` 会同步至卷
3. 验收:`docker exec <nexus> redis-cli -u "$URL" ping``PONG``/health``ok`
Redis 容器改名时,`resolve_nexus_redis_url` 会尝试将旧 URL 中的密码迁移到新 host。
### 5.2 三层守护与宿主机 cron
| 层 | Docker 1Panel | 裸机 Supervisor |
|----|---------------|-----------------|
| L1 | Compose `restart` + healthcheck | Supervisor `autorestart` |
| L2 | `self_monitor`30s | 同左 |
| L3 | **宿主机** `health_monitor.sh`cron | 同左 |
安装向导步骤 5(Docker)会提示在宿主机执行 `sudo nx cron``nx update` 结束时 TTY 下可交互安装。
| 脚本 | 用途 |
|------|------|
| `install_ops_cron.sh` | 幂等写入 health_monitor(每分钟)+ db_backup03:00 |
| `health_monitor.sh` | Layer 33 次 `/health` 失败 → `docker restart` + Telegram |
| `db_backup.sh` | 调用 `mysql_dump_to_file.sh`,保留 30 天 |
| `mysql_dump_to_file.sh` | `docker exec` MySQL 容器 → 宿主机 mysqldump → 临时 mysql:8 客户端 |
备份目录默认 `/var/backups/nexus/`。菜单 `nx``[9]` 手动备份;`[e]` / `nx cron` 安装定时任务。
---
## 6. 脚本速查
| 脚本 | 用途 |
|------|------|
| [deploy/README-1panel.md](../../deploy/README-1panel.md) | 速查表 |
| `verify-1panel-install-wizard.sh` | 服务器一键验收(含 cron、镜像特性) |
| `detect-1panel-services.sh` | 输出 `NEXUS_1PANEL_*_HOST` |
| `detect_deploy_runtime.sh` | Docker / Supervisor 运行时检测 |
| `fix-1panel-mysql-grant.sh` | 修复 MySQL 1045`nexus@'%'` |
| `test-1panel-redis.sh` | **Redis 多格式认证诊断** |
| `sync-install-wizard-to-container.sh` | 热同步(**已归档时早退**) |
| `uninstall-mysql-compose.sh` | 清理旧内置 MySQL 栈 |
`nx` 子命令:`update` · `verify` · `cron` · `health` · `install-fresh`
---
## 7. 故障排查决策树
### 7.1 Redis 认证失败
**症状**`invalid username-password pair` / `NOAUTH` / `wrongpass`
```
1. 主机是否为 1Panel-redis-xxxx?(不是 127.0.0.1
2. 是否误把口令当成「root 用户名」?(1Panel Redis **无账号**,只填密码)
3. 密码是否与 1Panel → Redis → 参数 一致?
4. 运行 `bash deploy/test-1panel-redis.sh` 看哪种 URL 可用
5. 运行诊断:
cd /opt/nexus && bash deploy/test-1panel-redis.sh
```
**在 Redis 容器内验证**
```bash
REDIS=$(docker ps --format '{{.Names}}' | grep -i '1Panel-redis' | head -1)
docker exec -it "$REDIS" redis-cli -u "redis://:你的密码@127.0.0.1:6379" ping
# 期望 PONG
```
**查真实配置**(密码与 ACL):
```bash
ls /opt/1panel/apps/redis/
grep -E 'requirepass|user ' /opt/1panel/apps/redis/*/conf/redis.conf 2>/dev/null
```
**修正已有 `.env`(步骤 3 已执行过)**
```bash
NEXUS=$(docker ps --format '{{.Names}}' | grep nexus-prod-nexus | head -1)
REDIS=$(grep '^NEXUS_1PANEL_REDIS_HOST=' /opt/nexus/docker/.env.prod | cut -d= -f2)
docker exec "$NEXUS" sed -i "s|^NEXUS_REDIS_URL=.*|NEXUS_REDIS_URL=\"redis://:你的密码@${REDIS}:6379/0\"|" /app/.env
docker restart "$NEXUS"
# 向导步骤 4 → 重新检测连接
```
### 7.2 MySQL 1045
**症状**`Access denied for user 'nexus'@'172.18.x.x'`
- TCP 已通,但用户仅 `nexus@localhost`
- 修复:`bash deploy/fix-1panel-mysql-grant.sh`(需 1Panel MySQL **root** 密码,非 nexus 用户)
### 7.3 host.docker.internal
**症状**`Can't connect to MySQL/Redis on 'host.docker.internal'`
```bash
cd /opt/nexus
bash deploy/detect-1panel-services.sh
nx update --no-cache
bash deploy/verify-1panel-install-wizard.sh
```
### 7.4 系统已初始化,无法重复执行数据库安装
- `/app/.env` 已存在,**不要**再点步骤 3 初始化
- 若 Redis 错:改 `.env``NEXUS_REDIS_URL`(§7.1)→ 步骤 4 重检
- 若需完全重装:
```bash
NEXUS=$(docker ps --format '{{.Names}}' | grep nexus-prod-nexus | head -1)
docker exec "$NEXUS" rm -f /app/.env /app/.install_state.json /app/.install_locked
docker run --rm -v nexus-prod_nexus-state:/data alpine:3.19 rm -f /data/.env
# 确认 docker/.env.prod 中 NEXUS_INSTALL_WIZARD_PENDING=1
nx update --no-cache
```
### 7.5 外网 HTTPS 失败、本机 8600 正常
- 配置 OpenResty 反代 + SSL
- `curl -s http://127.0.0.1:8600/health``ok`
- `curl -sk https://域名/health` → 应 `ok`
### 7.6 install.html 非 200 / 已归档 404
| 状态 | 期望 | 处理 |
|------|------|------|
| 安装中 | HTTP 200 | `sync-install-wizard-to-container.sh``nx update` |
| **已锁定** | HTTP **404** | 正常;容器内仅 `install.html.bak` |
```bash
sudo nx verify # 已安装时应 PASS「install.html 已归档 → HTTP 404」
```
### 7.7 升级前 MySQL 备份被跳过
旧版因宿主机无 `mysqldump` 且 URL host 为容器名而跳过。现用 `mysql_dump_to_file.sh``docker exec` 1Panel MySQL)。手动:`sudo bash /opt/nexus/deploy/db_backup.sh`
---
## 8. 生产探针(post-deploy
部署后从开发机巡检(外网 HTTPS 可能被运营商重置时,**源站 SSH 探针仍可通过**):
```bash
bash scripts/prod_health_check.sh # auto:外网尽力 + SSH 源站必检
NEXUS_PROBE_MODE=origin bash scripts/prod_health_check.sh # 仅源站
```
一次性在宿主机写入探针口令(**须与 admin 登录密码一致**,不入 git):
```bash
NEXUS_TEST_ADMIN_PASSWORD='你的admin密码' bash scripts/prod_probe_install.sh
```
写入路径:`/opt/nexus/docker/.env.prod`root 600)。鉴权段覆盖:`/health/detail`、告警 `per_page=50`、once 调度 201 创建并删除。
---
## 9. 验收清单
```bash
cd /opt/nexus && sudo nx verify
```
关键 `[PASS]`
- Git ≥ `b25d079`1Panel sync
- `NEXUS_1PANEL_DB_HOST` / `NEXUS_1PANEL_REDIS_HOST`
- Nexus 在 `1panel-network`
- **已安装**`install.html` → 404Crontab 含 health_monitor + db_backup
- **已安装**:容器 `install.py``host_deploy_root``NEXUS_HOST_ROOT=/opt/nexus`
- **安装中**`/app/.env` 不存在;`env-check``docker_defaults.db_host``1Panel-mysql-*`
浏览器:步骤 3 **先检测** → 初始化 → 步骤 4 创建 admin → `/app/` 登录。
---
## 10. 提交修复索引
| 提交 | 主题 |
|------|------|
| `b25d079` | `nx update` sync 1Panel 容器名;upgrade 补 `sync_1panel_service_hosts` |
| `d0544c9` | `fix-1panel-mysql-grant.sh`MySQL 1045 友好错误 |
| `da061d3` | 步骤 3 `test-credentials` 门禁 |
| `807f4c2` | Redis URL `redis://:pass@` 修复(曾误加 root,已废弃) |
| `3b2856f+` | 自动解析 `:pass@` / `default`;步骤 4 connection-check 可自愈 `.env` |
| `4e1347b``ba69bc3` | Docker MySQL 备份、`install_ops_cron.sh``nx cron` |
| `89865ec` | `upgrade.sh` / `deploy-production.sh` Docker·Supervisor 分流 |
| `c9e0879``e5d4822` | 守护配置 `host_deploy_root`、向导 Layer 3 cron UI |
| `72e46ce` | 升级后自动验收、`nx verify`、镜像特性检查 |
---
## 11. 与功能开发 SSOT 的差异
| 点 | `nexus-functional-development-guide.md` §16 | 1Panel 实装 |
|----|---------------------------------------------|-------------|
| 步骤 2/3 | 与 init-db 合并描述 | 步骤 2 仅 env-check;步骤 3 含 test-credentials |
| 配置三写 | 提及 `config.php` | 现为 `config.json` |
| 生产部署 §18 | Supervisor + 宝塔 | 以 `nexus-1panel.sh` / `nx` 为主 |
| Redis 主机 | 泛化为 localhost | **1Panel 必须容器名 + 仅密码(`:pass@`** |
---
## 11. 相关文档
- [nexus-functional-development-guide.md](nexus-functional-development-guide.md) — 全栈功能 SSOT
- [nexus-functional-development-guide-appendix.md](nexus-functional-development-guide-appendix.md) — API 附录
- [production-verification-checklist.md](production-verification-checklist.md) — L5
- [linux-dev-paths.md](linux-dev-paths.md) — 本地路径
- [../changelog/](../changelog/) — 按日变更记录
---
*本文档随 1Panel 部署实践更新;代码行为以 `server/api/install.py` 与 `deploy/nexus-1panel.sh` 为准。*