Appearance
Server Security Operations Runbook
Scope
Runbook для эксплуатации serveradmin (prod/dev), security мониторинга и безопасных ручных действий.
Контур
- Repo:
/home/admin/workspace/serveradmin - Prod URL:
https://serveradmin.designcorp.eu - Dev URL:
https://dev.serveradmin.designcorp.eu - Service units:
serveradmin-ui.serviceserveradmin-agent.service
Быстрый healthcheck
bash
curl -skI https://serveradmin.designcorp.eu
curl -skI https://dev.serveradmin.designcorp.eu
sudo -n systemctl status serveradmin-ui --no-pager
sudo -n systemctl status serveradmin-agent --no-pagerКритичные файлы
- Env:
/home/admin/.config/serveradmin/serveradmin.env - Events:
/home/admin/logs/serveradmin/events.jsonl - Audit snapshots:
/home/admin/logs/serveradmin/audit.jsonl - Operator audit:
/home/admin/logs/serveradmin/operator_audit.jsonl - Jobs queue:
/home/admin/logs/serveradmin/jobs.json - Approvals queue:
/home/admin/logs/serveradmin/approvals.json - Runtime web dist:
/opt/designcorp/serveradmin/prod/web-dist - Daily Telegram report script:
/home/admin/bin/nightly-security-report.sh - Security guard script:
/home/admin/bin/sec-guard.sh
Scheduled Monitoring
serveradmin uses systemd timers for host-level scheduled monitoring that must not depend on the mutable user crontab:
bash
systemctl list-timers --all --no-pager | rg 'serveradmin-(daily-report|sec-guard)'
systemctl status serveradmin-daily-report.timer --no-pager
systemctl status serveradmin-sec-guard.timer --no-pagerserveradmin-daily-report.timerruns/home/admin/bin/nightly-security-report.shevery day at08:00 UTCand sends the 24h Telegram security report.serveradmin-sec-guard.timerruns/home/admin/bin/sec-guard.shevery minute and checks host/container IOC markers.- If Telegram reports stop, first verify
serveradmin-daily-report.timer, then runsudo -n systemctl start serveradmin-daily-report.serviceand checksystemctl show serveradmin-daily-report.service -p Result -p ExecMainStatus.
Telegram alert scope:
- Daily report includes public TLS expiry checks for active
prodsites from/home/admin/logs/serveradmin/sites.json. - TLS thresholds are controlled by
SERVERADMIN_SSL_WARN_DAYS(default21) andSERVERADMIN_SSL_CRITICAL_DAYS(default7). - TLS scope is controlled by
SERVERADMIN_SSL_ALERT_ENVS(defaultprod; useallonly if dev certificates must be reported too). serveradmin-agentsite-down Telegram alerts are scoped bySERVERADMIN_SITE_ALERT_ENVS(defaultprod). This prevents intentionally paused dev services from paging Telegram while still protecting prod.
Deploy frontend
bash
cd /home/admin/workspace/serveradmin
npm run web:deploy
sudo -n systemctl restart serveradmin-uiПроверка:
bash
curl -s -I http://127.0.0.1:3099/Безопасные ручные действия
Предпочтительно выполнять из UI (Эксперт -> Действия), т.к. там есть audit trail.
High-risk операции (restart_nginx, nginx_apply, backup_restore) выполняются через:
- Создание заявки (
/api/v2/jobsбезrisk_ack) ->requires_approval=true. - Решение админа (
/api/v2/approvals/:id/decision). - Запуск approved заявки (
/api/v2/approvals/:id/execute).
Для прод-контура включен scheduler эскалаций:
- pending approvals получают Telegram reminders;
- заявка auto-expire после
SERVERADMIN_APPROVAL_PENDING_TTL_MIN.
CLI fallback:
bash
sudo -n nginx -t
sudo -n systemctl reload nginx
sudo -n systemctl restart serveradmin-ui
sudo -n systemctl restart serveradmin-agentИнцидент: P0
- Зафиксировать тип инцидента (
P0) и время. - При необходимости включить
global lockdownилиhost lockdown. - Проверить:
- активность подозрительных процессов,
- последние записи
events.jsonl/audit.jsonl, - статус nginx/fail2ban.
- После стабилизации:
- откатить временные ограничения,
- оформить post-incident запись,
- обновить docs (runbook + baseline + backlog).
Incident Room V1 (UI triage)
Во вкладке Incidents в serveradmin используется единый triage поток:
- Фильтры потока:
- severity (
p0|p1|lockdown|all) - project/host
- time window (
1h|6h|24h|7d) - status (
open|acked|resolved|all)
- severity (
- Для каждого инцидента доступны quick actions:
Ack / Resolve / ReopenLock host / Unlock hostNginx test / Nginx reload / Restart nginxOpen Cockpit-> project-specific diagnosis panel без CLI
- Для каждого инцидента есть прямая ссылка в релевантный runbook.
Incident Cockpit V1 показывает:
- live health probe по
healthUrl; - linked runtime targets и их state;
- runtime logs preview;
nginx -tsnapshot и путь vhost;- SSL snapshot;
- recent related jobs/actions;
- probable cause для
502/downпо rule-based heuristics.
One-click Workflows V1 в Actions:
- сценарии:
publish_project,ssl_issue,rollback_release,grant_access; - сначала запускать
Run preflight, затемStart workflow; - если apply-stage создал approval, дальше действие продолжается через linked approval прямо из того же run;
- история workflow хранит correlation id и step status, но не сохраняет секреты из apply результата.
Recovery Center V1:
- открывается из
Incidents -> Recoveryили изActions -> Recovery Center; - собирает runtime, health, releases, backups и workflows в один recovery context;
Rollback last healthyтеперь целится в последний успешныйdeploy, а не в прошлый rollback-event;Restore dry-runиспользовать первым, если нужно проверить целостность backup без live restore;- для
serveradmin.designcorp.euself-deploy теперь может быть завершён новой копией UI после собственного restart, поэтому после restart нужно проверять не только service status, но и release state в/api/deploy/releases.
Recovery Center
Использовать как primary path для 502/down, если проблема уже customer-visible:
Verify nowRestart runtimeесли binding настроенRollback last healthyесли restart не помогRestore dry-run, затем live restore только при подтверждённой необходимости- Повторный health verify и
Resolveинцидента
Approval Inbox V2:
- approvals теперь triage'ятся через lanes
Needs decision,Ready to execute,Recent outcomes; Needs decision— зона админа,Ready to execute— зона оператора;- detail pane показывает justification, site context, payload summary, decision notes и linked job;
- raw JSON оставлен как secondary debug view, а не как основной интерфейс.
Approval Inbox
Порядок работы:
- Проверить justification и scope.
ApproveилиReject.- Если request уже approved, выполнить его через
Execute approved. - Проверить linked job и follow-up screen (
Recovery,Projects/Sites,Monitoring).
Health Policy / Onboarding:
- в
Projects/Sitesprobe теперь читается не только как код, а как policy + explanation; - если сайт discovery-managed и root не подходит как health endpoint, agent сам переводит его на canonical
/healthилиauth-expected, не перетирая explicit настройку оператора; - колонка
Managedпоказывает missing/warning metadata для частично подключённых проектов; - новый сайт нужно считать завершённым только после заполнения
runtime,nginxPath, canonicalhealthUrl/healthPolicy, owner, criticality и backup mode.
Требование по трассировке:
- действия из Incident Room должны идти с reason-префиксом
incident_room:<incident_key>; - все такие действия фиксируются в
operator_audit.jsonl.
Инцидент: UI недоступен
- Проверить local backend:
bash
curl -s -I http://127.0.0.1:3099/- Проверить nginx конфиг/статус:
bash
sudo -n nginx -t
sudo -n systemctl status nginx --no-pager- Проверить
serveradmin-ui:
bash
sudo -n systemctl status serveradmin-ui --no-pager
sudo -n systemctl restart serveradmin-uiCredentials / Rotation
Минимум для ротации:
- Basic Auth (
/etc/nginx/.htpasswd-serveradmin) SERVERADMIN_API_TOKENSERVERADMIN_TELEGRAM_TOKEN(по необходимости)
После ротации:
sudo -n nginx -t && sudo -n systemctl reload nginxsudo -n systemctl restart serveradmin-ui serveradmin-agent- Проверка prod/dev URL + API доступа.
SSL Operations
Если ssl_issue блокируется:
- Не запускать ручной
certbotнаугад. - В
Actions -> One-click workflowsсначала смотретьRun preflight. - Исправить DNS или HTTP challenge path blockers.
- Только после этого запускать
Start workflow. - Затем проверить
SSL statusиMonitoring Workspace.
API smoke для jobs/approvals
bash
curl -sS -H "x-serveradmin-token: $SERVERADMIN_TOKEN" http://127.0.0.1:3099/api/v2/ops/summary | jq
curl -sS -H "x-serveradmin-token: $SERVERADMIN_TOKEN" http://127.0.0.1:3099/api/v2/jobs?limit=20 | jq
curl -sS -H "x-serveradmin-token: $SERVERADMIN_TOKEN" http://127.0.0.1:3099/api/v2/approvals?limit=20 | jqAPI smoke для Hosting Modules (V2)
Использовать встроенный smoke-скрипт:
bash
SERVERADMIN_TOKEN="$SERVERADMIN_TOKEN" \
/home/admin/workspace/serveradmin/scripts/smoke-api-v2.sh http://127.0.0.1:3099Проверяет:
- core/rbac (
/api/config,/api/me); - jobs/approvals (
/api/v2/*); - files/ftp, db, mail, cron, resources, access;
- incidents feed и managed files list.
Примечание по backend/frontend decomposition phase 2:
- V3 route-level handlers теперь живут в
src/ui-api/*.js, аsrc/ui.jsсобирает их черезmodularApiHandlers. - Hosting/system surfaces вынесены в
src/ui-api/hosting-modules.jsиsrc/ui-api/system.js. - Legacy inline admin HTML вынесен в
src/ui-html.js. web/src/App.jsxтеперь тонкий shell; state/effects вынесены вweb/src/hooks/useServerAdminApp.js, а секции UI живут вweb/src/sections/*.jsx.- После route-level refactor достаточно повторить smoke по доменам, которые были вынесены:
/api/workflows/catalog/api/v2/jobs?limit=1/api/sites/<site-id>/runtime/api/incidents/feed?limit=1/api/backup/status/api/ssl/status?site_id=<site-id>/api/resources/sites?limit=1/api/admin/actions
noVNC desktop for code-server
Browser VNC URL:
bash
https://vscode.designcorp.eu/proxy/6080/vnc.html?path=proxy/6080Runtime units:
bash
sudo -n systemctl status vscode-vnc-xvfb.service --no-pager
sudo -n systemctl status vscode-vnc-fluxbox.service --no-pager
sudo -n systemctl status vscode-vnc-x11vnc.service --no-pager
sudo -n systemctl status vscode-novnc.service --no-pagerExpected process chain:
Xvfb :100owns the virtual display.x11vncbridges:100to127.0.0.1:5901.websockifyexposes local noVNC on127.0.0.1:6080.vscode-vnc-fluxbox.servicemust start/usr/bin/startfluxbox, not/usr/bin/fluxboxdirectly.startfluxboxreads/home/admin/.fluxbox/startup, which startspcmanfm --desktop --profile LXDEfor desktop icons and file manager integration.
If desktop icons or File Explorer disappear but VNC still connects, first check:
bash
ps -eo pid,ppid,user,stat,cmd | grep -Ei 'pcmanfm|fluxbox|x11vnc|websockify' | grep -v grep
DISPLAY=:100 xlsclients -lRoot cause seen on 2026-05-31: Xvfb had restarted on 2026-05-30, killing the old pcmanfm --desktop; the Fluxbox unit restarted only /usr/bin/fluxbox, bypassing /home/admin/.fluxbox/startup, so pcmanfm did not come back. Fix was to point vscode-vnc-fluxbox.service at /usr/bin/startfluxbox, run sudo -n systemctl daemon-reload, then restart only vscode-vnc-fluxbox.service.
Примечание по V3 registry:
GET /api/sitesтеперь возвращает не только legacy top-level поля проекта, но и нормализованные блокиruntime,backupPolicyиcapabilities.- При диагностике нового проекта сначала смотреть именно эту модель, а не пытаться вручную угадать runtime/health/ownership из nginx.
- Новый guided onboarding идёт через
Projects/Siteswizard, а не через ручное заполнение всех полей одним экраном. - Перед созданием/обновлением wizard вызывает
POST /api/sites/preview; именно этот preview является источником правды дляmanagedStatusи remaining blockers. - Runtime controls читаются через:
GET /api/sites/:id/runtimeGET /api/sites/:id/runtime/logs?target=<unit|container>&lines=80
- Safe restart runtime выполняется через jobs:
POST /api/v2/jobs- body:
{"operation":"service_control","reason":"...","payload":{"site_id":"...","action":"restart"}}
- Важно: restart не принимает unit/container names из запроса. Backend берёт targets только из
runtime.units/runtime.containersproject registry или из controlled bootstrap map для core-проектов.
Операционные правила V2
- High-risk direct execution только для
admin+risk_ack=true. - По умолчанию high-risk действия идут через approvals queue.
- Для всех mutating API обязателен
reason(audit trail). - Новые managed token значения возвращаются только в момент создания и далее в API не отображаются.