cleanup-existing-server
Skill1 starsChanged 3 months agoMITView on GitHub
Поэтапное приведение унаследованного хаоса на сервере к управляемому состоянию без простоя: переименование контейнеров через aliases (two-stage паттерн), правка прав на .env (0644→0600), drift'ы между sites-available/sites-enabled, мёртвые nginx-конфиги, mem_limit по замерам. Yellow Zone, каждая категория с подтверждением. Триггеры: «бардак на сервере», «навести порядок», «контейнеры с дикими именами», «cleanup server», «приведи в порядок без простоя». НЕ для свежих VPS (для них — bootstrap-new-server); НЕ для удаления volumes/БД (это Red Zone).
- Reads credentials
- Deletes or force-pushes
In this repository25 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- audit-securitySkill
- bootstrap-new-serverSkill
- configure-vpn-routingSkill
- deploy-serviceSkill
- devSkill
- extract-subscription-serversSkill
- finalize-vpn-routingSkill
- generate-client-configSkill
- health-checkSkill
- install-monitoring-stackSkill
- inventory-scanSkill
- migrate-server-to-serverSkill
- refresh-vpn-knowledgeSkill
- restore-from-backupSkill
- retroSkill
- rotate-secretsSkill
- second-opinionSkill
- setup-backupsSkill
- setup-happ-subscriptionSkill
- setup-secrets-vaultSkill
- setup-server-proxySkill
- setup-vpn-panelSkill
- sysadmin-initSkill
- sysadmin-meetSkill
The file
Files
<role>
Я расчищаю унаследованный хаос на сервере поэтапно, без простоя. Каждая категория
правок — отдельный брифинг 6 пунктов и подтверждение оператора (Yellow Zone).
Деструктивные операции (удаление volumes, БД, file-system rm -rf) я не делаю в этом
скилле — для них есть отдельная Red Zone-процедура.
</role><context>
Что предполагается:
- inventory-scan уже запускался — есть свежий snapshot (≤24 часов) и обновлённые
inventory-документы
- drift-report свежего snapshot показывает, что чистить нужно
- Бэкапы свежие (≤24 часов) — обязательно перед любой правкойЧто НЕ предполагается:
- Свежий сервер (для него — bootstrap-new-server)
- Деструктивные операции (для них — отдельная процедура Red Zone)
- Автоматическое выполнение всех категорий разом — каждую утверждаем отдельно
</context>
<goals>
После выполнения:
- Категории чистки идентифицированы и предложены оператору как план
- По каждой утверждённой категории — изменения применены поэтапно, с верификацией
после каждой
- Re-inventory или specific check после каждой категории — drift'ы по этой
категории закрыты
- Журнал чистки в `incidents/YYYY-MM-DD-cleanup-<scope>.md` — что чистили,
какие команды, что получилось, lessons learned
</goals>Параметры
| Параметр | Default | Описание |
CATEGORIES | all | names,permissions,drift,dead-configs,memory-limits или комбинация |
DRY_RUN | false | Только показать план, не выполнять |
INCIDENT_DIR | incidents | Куда журналировать |
SSH_HOST | (обязательный) | SSH-target — user@<your-server-ip> или SSH-алиас из ~/.ssh/config |
Процедура
Шаг 1. Pre-check
Перед любой работой проверяю две страховки:
# Свежесть snapshot (≤24 ч)
LATEST_SNAP=$(ls -t inventory/hosts/*/snapshots/ | head -1)
SNAP_AGE_H=$(( ($(date +%s) - $(date -r "$LATEST_SNAP" +%s)) / 3600 ))
[ "$SNAP_AGE_H" -le 24 ] || {
echo "ОШИБКА: snapshot старше 24 часов. Запусти сначала inventory-scan."
exit 1
}
# Свежесть бэкапа (≤24 ч)
restic snapshots --latest 1 --json 2>/dev/null \
| jq -r '.[0].time' \
| xargs -I{} bash -c 'echo $(( ($(date +%s) - $(date -d {} +%s)) / 3600 ))' \
| { read -r AGE; [ "$AGE" -le 24 ] || {
echo "БЛОКЕР: бэкап старше 24 часов. Без свежего бэкапа НЕ ПРОДОЛЖАЮ."
exit 1; }; }Если бэкапа нет вообще — это блокер, не предупреждение. Без страховки чистка запрещена.
Шаг 2. Анализ snapshot → план чистки
Для каждой категории — запускаю scripts/cleanup-categories.sh, который читает
свежий snapshot и формирует список кандидатов на чистку:
Имена контейнеров (names) — кандидаты с автогенерируемыми именами
<project>-<service>-<index> (например, <project>-postgres-1,
<project>-app-1). Решение через two-stage rename + aliases
(ADR 0011 или эквивалент в проекте-носителе).
Права на .env (permissions) — find /opt -name '.env' -exec stat -c '%a %n' {},
ищем mode 0644 (должно быть 0600). Типичный паттерн в зрелой инфре —
несколько таких файлов накапливаются за полгода-год работы.
Drift sites-available vs sites-enabled (drift) — diff имён файлов в двух
папках, плюс [ -L /etc/nginx/sites-enabled/$name ] — регулярный файл вместо
симлинка = drift.
Мёртвые nginx server-блоки (dead-configs) — nginx -T | grep server_name,
сверяем с inventory/hosts/<host>/domains.md. Server-блок без живого DNS-target =
кандидат на удаление.
Лимиты памяти (memory-limits) — docker inspect | jq '.[].HostConfig.Memory',
ищем нули. Замеры — через docker stats --no-stream за разное время суток (или из
Beszel, если стек установлен).
Шаг 3. Презентация плана оператору — брифинг 6 пунктов на каждую категорию
Для каждой категории отдельно (не «делай всё разом»):
- ЧТО — список конкретных изменений с конкретными именами (не абстракции)
- ЗАЧЕМ — какая боль решается, какой риск без правки
- РИСКИ — что может сломаться, ожидаемый downtime
- ОТКАТ — конкретные команды, которыми можно вернуть как было
- СТРАХОВКА — что бэкапим перед, как проверим
- ПРОВЕРКА — как убедиться, что всё ок после применения
Брифинг печатается в чат, оператор отвечает «давай» / «не сейчас» / «измени план». Категория начинается только после явного «давай».
Шаг 4. Поэтапное выполнение
После «давай» оператора по категории:
- Выполняю ровно эту категорию, не «попутно ещё одну»
- После каждой — re-verify (либо
inventory-scanповторно, либо specific check) - Если что-то сломалось — пауза, новый брифинг, не «продолжаю на свой страх»
Категория names — scripts/rename-container-aliases.sh (two-stage паттерн
ADR 0011 проекта-носителя):
Stage 1 (~2 сек простоя): добавить новый alias к контейнеру
Stage 2 (~10 сек простоя): переименовать container_name + service key,
старый alias оставить временно
Stage 3 (когда клиенты переключатся): убрать старый aliasКатегория permissions:
# Backup .env, потом chmod
for f in $(find /opt -name '.env' -perm 644); do
cp -p "$f" "$f.bak.$(date +%s)"
chmod 600 "$f"
doneКатегория drift (sites-available vs sites-enabled):
# Если sites-enabled — регулярный файл, не симлинк:
mv /etc/nginx/sites-enabled/$NAME /tmp/$NAME.bak
ln -s /etc/nginx/sites-available/$NAME /etc/nginx/sites-enabled/$NAME
nginx -t && nginx -s reloadКатегория dead-configs:
# bak-копия мёртвого блока, удаление, проверка nginx, reload
mv /etc/nginx/sites-available/$NAME /tmp/$NAME.dead-$(date +%s)
nginx -t || { echo "ОТКАТ"; mv /tmp/$NAME.dead-* /etc/nginx/sites-available/$NAME; exit 1; }
nginx -s reloadКатегория memory-limits (по ADR 0009 проекта-носителя или эквивалентному
правилу — например, суммарный лимит ≤80% RAM хоста; для 4 ГБ это ≤3.2 ГБ
с запасом 800 МБ):
# Обновить compose: добавить mem_limit на основе замеров (peak * 1.5)
# Применить узким scope, без -d --no-deps, чтобы не пересоздавать соседей
docker compose up -d --no-deps <service>Шаг 5. Журналирование
Скопировать templates/cleanup-incident.md → incidents/YYYY-MM-DD-cleanup-<scope>.md,
заполнить:
- Что чистили (категории)
- Какие конкретные имена / файлы / контейнеры
- Конкретные команды (для воспроизводимости)
- Результат: что починилось, что сломалось
- Lessons learned (если есть новые грабли)
Failed Attempts
- «Переименование без aliases — разом ломаются клиенты» — ADR 0011 проекта-носителя (или эквивалент) фиксирует two-stage как обязательный. Реальный замер: один прогон одностадийной правки клал 5 БД-клиентов одновременно на ~30 секунд; two-stage сокращает простой до ~12 сек.
- «chmod 600 без backup .env» — если что-то сломается (например, сервис
работал из-под другого user), нужен откат через
cp -p .env.bak. Backup обязателен перед chmod. - «Удаление мёртвого nginx-блока без
nginx -t» — сломанный конфиг блокирует reload всего nginx. Один забытый;положит все домены сразу. Всегдаnginx -tдоnginx -s reload. - «mem_limit без замеров» — слишком жёсткий лимит → OOM kill. ADR 0009 проекта-носителя (или эквивалентное правило) про это: лимит = peak_observed × 1.5, не «возьму поменьше для надёжности». Замеры должны быть >24 ч на разное время суток.
- «find -mtime +N округляет вниз» — для retention в этом скилле не нужен,
но регулярно всплывает при чистке
/tmp. Использовать сортировку по имени. - «Compose без явного
image:при смене service key триггерит пересборку» — типичный кейс с длительным простоем (наблюдалось до 8 минут на средних образах). Если compose толькоbuild:, до переименования добавитьimage: <project>-<service>:latestна существующий image, чтобы Docker Compose не запускал full rebuild.
Граничные случаи
- Контейнер в restart loop — не переименовывать, сначала разобраться с loop'ом (это диагностика, не cleanup)
- БД-контейнер в категории
names— особо аккуратно, риск длительного простоя для ВСЕХ клиентов (если БД-контейнер shared, переименование роняет сразу несколько приложений). Окно простоя оговаривается отдельно - Суммарный лимит памяти превышает порог хоста (например, > 3.2 ГБ при 4 ГБ хоста) — отказать, требовать решения оператора. Это нарушение ADR 0009 проекта-носителя или эквивалентного правила «суммарный лимит ≤80% RAM»
- Исторические compose-файлы с устаревшими сервисами — не трогать.
История архивации — особый случай, шапка
# АРХИВИРОВАНОесть в compose-файлах, скилл их пропускает - Compose без
image:(толькоbuild:) — добавитьimage:на существующий локальный сборочный образ ДО переименования, иначе Docker Compose инициирует full rebuild (см. Failed Attempts) - Несколько категорий разом — скилл откажет: «делаю по одной, утвердим первую, потом следующую»
Bundled resources
scripts/cleanup-categories.sh— анализатор snapshot → список кандидатов по 5 категориямscripts/rename-container-aliases.sh— two-stage переименование (ADR 0011 проекта-носителя или эквивалент)templates/cleanup-incident.md— шаблон записи вincidents/references/typical-grabli.md— каталог типичных граблей с короткими описаниями (симптом → причина → лечение)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

