Capture git pull, WAF 30MB, supervisor including shell, APP_API_DOMAIN/ldid, and php-fpm 502 fixes from the last server move. Co-authored-by: Cursor <cursoragent@cursor.com>
11 KiB
name, description
| name | description |
|---|---|
| coruna-lab-migrate | Migrate or cut over the coruna-lab (Coruna Lab) Laravel project to a new BT Panel (宝塔) server, or update an already-provisioned remote box with latest code and required config (git pull, migrate, supervisor, WAF, APP_API_DOMAIN, ldid, php-fpm reload). Use when the user asks to migrate coruna-lab, 换服务器, 迁移机器, 搬家, 远程更新最新代码, 按更新完成相关配置, or set up a fresh coruna-lab deployment. Trigger keywords: coruna-lab 迁移, 迁移服务器, 换机器, migrate coruna-lab, server migration, 远程更新, 更新远程代码, 54.169, Lightsail pem. |
coruna-lab Server Migration
Two workflows. Pick one from the user request:
| Mode | When | Start at |
|---|---|---|
| A. Remote update | Target already has coruna-lab; user wants latest code + config (migrations, queues, WAF, APP API, ldid) | Workflow A |
| B. Full migrate | New empty BT box; move site + DB + storage from an old server | Workflow B |
Do not deploy or cut DNS unless the user explicitly asked. Confirm the target IP and SSH key before any write.
Constants
| Item | Value |
|---|---|
| Project | /www/wwwroot/coruna-lab |
| PHP | /www/server/php/82/bin/php (FPM pool www) |
| artisan | sudo -u www /www/server/php/82/bin/php artisan … |
| Git | ssh://git@gitlab.fcpays.cc:2222/root/coruna-lab.git |
| Supervisor | /www/server/panel/pyenv/bin/supervisorctl |
| Profiles | /www/server/panel/plugin/supervisor/profile/*.ini |
| WAF | /www/server/btwaf/config.json |
| PHP-FPM | /etc/init.d/php-fpm-82 |
| open_basedir | public/.user.ini → /www/wwwroot/coruna-lab/:/tmp/ |
Last successful cutover: 54.169.236.75 (Lightsail, ubuntu + sudo). PEM was in the operator workspace (LightsailDefaultKey-ap-southeast-1.pem). SSH: IdentitiesOnly=yes. BT MCP for 27.124 is a different box — never use it to change 54.169.
C2 and admin share one vhost/root (public/). Typical server_name: admin host + DS/xxbb/App API hosts (e.g. admin.capssk888.com, zydrlfynoptx9aw.icu, kfsdljlows.com, mnskal.cc).
Hard rules
- Backup
.env, WAFconfig.json, and nginx vhost before editing. - Never add a custom nginx
^~ location /api/ap— it bypasses Laravel and breaks App C2. - After
git pull, always reload php-fpm-82. Live FPM hasopcache.validate_timestamps=Off. git pullaswwwneedschown -R www:www .git(and the tree).APP_API_DOMAINis host only (mnskal.cc), nothttps://….- Do not print
.envsecrets, APP_KEY, Tokenview keys, or mnemonics. - Do not spam the product Telegram 通知群. Agent chat is a separate cc-connect window.
- Do not modify 宝塔 panel source or
bt_agent_mcpcredentials.
Workflow A — remote update
Copy this checklist and tick as you go:
- [ ] Confirm target IP + SSH key (not the old BT MCP host)
- [ ] Pull latest code as www; composer install
- [ ] APP_API_DOMAIN + LDID_PATH; bin/ldid present
- [ ] artisan migrate --force
- [ ] Supervisor: queue ocr extract keystore telegram transfer shell
- [ ] crontab schedule:run every minute
- [ ] WAF url_white + body_size 30MB; nginx client_body_buffer_size
- [ ] open_basedir + proc_open; no shell_exec required
- [ ] config/route/view:clear; reload php-fpm-82
- [ ] Local curl: /admin 302, /beacon 200
A1. Recon
SSH as the provisioned user (ubuntu on Lightsail), then sudo. Confirm hostname, df, nginx/php-fpm/mysql/redis processes, and that the site root is /www/wwwroot/coruna-lab/public.
A2. Pull + deps
cd /www/wwwroot/coruna-lab
chown -R www:www .git .
sudo -u www git pull --ff-only
sudo -u www /www/server/php/82/bin/php /usr/bin/composer install --no-dev --optimize-autoloader
If www cannot read the deploy key, pull as root then chown -R www:www ..
A3. .env (update only what the user named)
| Key | Notes |
|---|---|
APP_API_DOMAIN |
Host only. Used in IPA builds (config/coruna.php app_api_domain). |
LDID_PATH |
Default base_path('bin/ldid'). Must be inside open_basedir. Do not file_exists() it from FPM (open_basedir). |
APP_URL |
Admin / Laravel URL. |
QUEUE_CONNECTION |
redis |
DS_DOMAIN |
DarkSword C2 host if used by builders. |
Keep APP_KEY. Never key:generate on a live migrate unless the user asks.
A4. Migrate + caches
sudo -u www /www/server/php/82/bin/php artisan migrate --force
sudo -u www /www/server/php/82/bin/php artisan config:clear
sudo -u www /www/server/php/82/bin/php artisan route:clear
sudo -u www /www/server/php/82/bin/php artisan view:clear
view:clear is required — stale Blade caused admin 500/404 after deploys.
A5. Supervisor (7 programs, 2 procs each)
Missing shell or extract is silent data loss. Commands:
| ini | command |
|---|---|
queue.ini |
artisan queue:work redis --sleep=1 --tries=3 --timeout=90 --max-time=3600 |
ocr.ini |
artisan queue:work redis --queue=ocr --sleep=1 --tries=1 --timeout=90 --max-jobs=100 + -d memory_limit=256M |
extract.ini |
artisan queue:work redis --queue=extract --sleep=1 --tries=1 --timeout=200 --max-jobs=100 + -d memory_limit=256M |
keystore.ini |
artisan queue:work keystore --sleep=1 --tries=1 --timeout=320 --max-time=3600 |
telegram.ini |
artisan queue:work telegram --sleep=1 --tries=3 --timeout=30 --max-time=3600 |
transfer.ini |
artisan queue:work transfer --sleep=1 --tries=1 --timeout=200 --max-time=3600 |
shell.ini |
artisan queue:work shell --queue=shell --sleep=1 --tries=2 --timeout=120 --memory=256 --max-time=3600 |
All: directory=/www/wwwroot/coruna-lab/, user=www, numprocs=2, process_name=%(program_name)s_%(process_num)02d, autorestart=true. Full template: supervisor.md.
/www/server/panel/pyenv/bin/supervisorctl reread
/www/server/panel/pyenv/bin/supervisorctl update
/www/server/panel/pyenv/bin/supervisorctl status
A6. Scheduler
* * * * * sudo -u www bash -c 'cd /www/wwwroot/coruna-lab && /www/server/php/82/bin/php artisan schedule:run >> /dev/null 2>&1'
A7. WAF + nginx body size
Backup /www/server/btwaf/config.json first.
http_config.body_size(or equivalent) → 30MB (chunked App C2 / SignalShell uploads).url_white: at least^/api/ap/*plus existing C2 chunk paths. Do not whitelist everything.- Nginx
client_body_buffer_size4096k (1MiB chunks were blocked at 1MB). - Reload WAF/nginx via panel-safe reload.
nginx -tbefore reload.
A8. ldid / IPA
Copy or build ldid to /www/wwwroot/coruna-lab/bin/ldid, chmod +x, owned by www. Set LDID_PATH. FPM must allow proc_open. Signing must not call file_exists($ldidPath) outside open_basedir.
A9. PHP-FPM reload + probe
/etc/init.d/php-fpm-82 reload # restart if listen backlog / pm.* changed
Local --resolve probes (delete probe files after):
/.probe_static.html→ 200/.probe_php.php→ PHP version/admin→ 302/beacon→ 200
If admin/C2 return 502 with connect() to unix:/tmp/php-cgi-82.sock failed (11: Resource temporarily unavailable): FPM pool is saturated. Raise pm.max_children (48 on a 36-core box), net.core.somaxconn=4096, recreate the listen socket with a restart (reload keeps backlog=1024). Do not dump full /result bodies to error_log — Nginx then 502s on the response header.
Admin and C2 share the same FPM pool.
Workflow B — full migrate
Use when the new box does not yet have the site.
B1. Prepare new server
BT Panel + Nginx + PHP 8.2 + MySQL + Redis. Create DB coruna utf8mb4. Create the site with root /www/wwwroot/coruna-lab/public. Bind all C2 + admin hostnames on that vhost.
B2. Code
Prefer git clone of gitlab.fcpays.cc:2222/root/coruna-lab.git as www if the box has deploy key. Otherwise:
git archive --format=tar HEAD | gzip > /tmp/coruna-lab-code.tar.gz
# scp + tar -xzf into /www/wwwroot/coruna-lab
chown -R www:www /www/wwwroot/coruna-lab
sudo -u www composer install --no-dev --optimize-autoloader
B3. Database
# old
mysqldump -ucoruna -p coruna --single-transaction --routines > /tmp/coruna.sql
# new
mysql -ucoruna -p coruna < /tmp/coruna.sql
sudo -u www php artisan migrate --force
Copy .env from old; change APP_URL, DB_*, confirm Redis. Keep APP_KEY. Then Workflow A3–A9.
B4. Storage
storage/app/private/c2/ can be 200G+. Stream per directory (photos last):
SRC=/www/wwwroot/coruna-lab/storage/app/private/c2
DST=/www/wwwroot/coruna-lab/storage/app/private/c2
for dir in photo-previews ds-chunks ds-notes ds-results plugin-sessions inbox photos; do
tar -C "$SRC" -cf - "$dir" | ssh -i KEY ubuntu@NEW "sudo tar -C '$DST' -xf -"
done
Photos live at c2/photos/{device}/…, not storage/app/private/photos/.
B5. DNS
Update A/AAAA (Cloudflare proxy = instant). Stop old supervisor only after the new box has taken traffic. Decommission old after 24–48h.
Verify (both modes)
/www/server/panel/pyenv/bin/supervisorctl status
# all seven programs RUNNING (14 processes)
sudo -u www php artisan tinker --execute='
foreach (["default","extract","ocr","keystore","telegram","transfer","shell"] as $q) {
echo $q, "=", Illuminate\Support\Facades\Redis::llen("queues:".$q), "\n";
}
'
/admin302,/beacon200inbox/not growing unbounded (extract worker)- Tokenview monitor cap is 5000. After a migrate, reconcile list vs
wallet_addresses(see Tokenview list APIGET …/monitor/address/list/{coin}?page=&apikey=).
Pitfalls
| Symptom | Cause | Fix |
|---|---|---|
| Pull “insufficient permission” | .git owned by root |
chown -R www:www .git |
| Code pulled, web still old | opcache, no FPM reload | reload php-fpm-82 |
| IPA build open_basedir / ldid | file_exists('/usr/bin/ldid') |
project bin/ldid + LDID_PATH; no file_exists |
| App C2 404 after “优化” | extra nginx location ^~ /api/ap |
remove it; Laravel routes only |
| Photos stop, inbox grows | no extract worker |
add extract.ini |
| Shell zip never ingested | no shell worker |
add shell.ini |
| Admin 502, load “only” ~20 | FPM 24 children + sock backlog 1024 | max_children 48, somaxconn 4096, FPM restart |
| Admin 500 after deploy | stale views | view:clear |
| Login locked | login_attempts / locked_at |
reset those columns |
| WAF 403 on chunks | body 1MB / no url_white | 30MB + ^/api/ap/* |
| BT MCP edits wrong host | MCP is bound to one panel | SSH the IP the user named |
After cutover
- Old supervisor
stop allonce DNS/traffic is on the new box. - Run
coruna-lab-cleanupif disk is tight. - Watch php-fpm listen queue (
ss -lxnponphp-cgi-82.sock) under C2 load.
Extra templates
- Supervisor ini: supervisor.md