Files
gilfanovrandClaude Opus 5 b56c137b5c Механизм поддержания описаний в актуальном состоянии
Сверка fr1 показала, что дока расходится с фактом по десятку пунктов —
значит нужен не разовый проход, а контракт и инструмент.

  CLAUDE.md — правило «тронул сервер, обнови servers/<хост>.md в том же
  прогоне» плюс стиль: факт + причина + что сломается молча. Лежит именно
  в CLAUDE.md, потому что AGENTS.md автоматически агенту не подгружается.

  .claude/skills/server-audit/ — метод сверки и накопленные грабли: где
  дока врёт чаще всего, почему ufw не отвечает на вопрос об открытых
  портах, почему нужен up -d --dry-run, почему «executed successfully»
  не доказывает работу задания.

  scripts/snapshot.sh — инвентаризация живого состояния за один проход:
  только чтение, без sudo, секретов не печатает, недоступное под root
  помечает и подсказывает команду.

Первый же прогон скрипта нашёл две вещи, обе описаны:

  - IPv6 не «починился», а мигает: за один день FAILED -> REACHABLE ->
    FAILED без единой правки конфига. Описан как мигающий, с выводом
    ничего на него не завязывать.
  - В основном sshd_config стоит PermitRootLogin yes (правка шаблона
    Contabo). Root-вход закрыт только потому, что Include дроп-инов
    стоит выше, а sshd берёт первое значение. Уберёшь дроп-ин —
    включится.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 16:52:22 +03:00

6.7 KiB
Raw Permalink Blame History

name, description
name description
server-audit Сверить фактическое состояние сервера с его описанием в servers/*.md и обновить описание. Использовать после любых работ на сервере (поднял/погасил сервис, поменял конфиг, удалил каталог, завёл ключ), а также когда просят проверить, соответствует ли дока реальности, актуализировать описание хоста или разобраться, что на сервере вообще происходит.

Сверка описания сервера с фактом

Цель — чтобы servers/<хост>.md описывал сервер таким, какой он есть, и чтобы по нему можно было принимать решения. Правила оформления — в CLAUDE.md репозитория, здесь метод и грабли.

Порядок

  1. Собери факт до чтения доки. Сначала ./scripts/snapshot.sh <хост>, потом читай описание. Наоборот — начнёшь подгонять наблюдения под текст.
  2. Сверяй по пунктам, не по впечатлению. Прогоняй утверждения доки через факт по одному: версии, размеры, пути, порты, «включено/выключено». При сверке fr1 2026-09-08 неверными оказались десять утверждений, включая «IPv6 не работает» про работавший IPv6 и версию Gitea на два минора назад.
  3. Добери то, что требует root — snapshot это помечает. Неинтерактивный sudo не проходит: нужен ssh -t <хост> 'sudo ...', то есть попроси пользователя выполнить, а не пытайся обойти.
  4. Правь описание в том же прогоне. Не откладывай на «потом опишу».
  5. Незакрытое — в «Открытые хвосты» файла хоста. Токен, который не удалось отозвать; права, которые не поправил; решение, которое за пользователя не принимаешь.

Где дока врёт чаще всего

  • Версии и размеры — меняются молча при обновлении контейнера. Смотри фактический тег у запущенного контейнера, а не запись в compose: они расходятся, и тогда docker compose up -d откатывает сервис.
  • «Не работает» — могло починиться на стороне провайдера. И наоборот: IPv6 на fr1 за один день был FAILED, потом REACHABLE, потом снова FAILED — такое надо описывать как мигающее, а не как состояние.
  • Открытые порты. ufw status не отвечает на вопрос «что торчит наружу»: docker публикует порты в iptables напрямую, минуя ufw. Только ss -tlnH + docker ps. Непубликуемый порт контейнера всё равно доступен с хоста по адресу контейнера — «внутренняя сеть» не периметр.
  • Процессы вне контейнеров. docker ps их не покажет, а они не переживут перезагрузку. Ищи ps с PPID=1 и чужими пользователями.
  • Кроны других пользователей — в docker ps и в crontab -l их нет. Осиротевшее задание может годами падать молча: MTA не установлен, вывод крона теряется.
  • Планы, записанные как факт. «Планируется перенести DNS» при уже перенесённом DNS. Проверяй раздел «планируется» отдельно.

Грабли, которые стоили времени (не повторяй)

  • Пути в БД абсолютные. Прежде чем контейнеризовать сервис, проверь все префиксы путей в его базе, а не только основной каталог данных: select substr(file_path,1,30), count(*) from images group by 1; Монтируй в тот же путь, что на хосте, иначе часть данных пропадёт молча.
  • up -d --dry-run перед любым compose-действием. Он показывает, что compose собирается сделать, — например поднять забытый контейнер того же проекта и словить конфликт портов.
  • Задание может глушить свои ошибки. У imgbot analyze логирует исключение и возвращается нормально, поэтому планировщик пишет executed successfully после падения. Отсутствие ошибок не доказывает работу — проверяй результат, а не статус.
  • Ретенция. journald был на 500M (11 дней), sysstat на HISTORY=7. Сервер, где разбирают аварии, обязан хранить историю дольше, чем живёт проблема. У sysstat при HISTORY>28 имена переключаются на saYYYYMMDD — иначе поднятие числа бессмысленно.
  • Группа docker = root. Пользователь без sudo, но в группе docker, монтирует / в контейнер и делает что угодно. Учитывай при описании доступа.

Проверка результата

Перед отчётом прогони по получившемуся файлу: каждое ⚠️ подтверждено наблюдением? у каждого изменения указана дата и прежнее значение? не попали ли в текст секреты? если роль хоста изменилась — поправлена ли строка в AGENTS.md?