Сервер редко отказывает внезапно. Сначала несколько месяцев тихо растёт занятое место на разделе, потом задание резервного копирования второй раз подряд завершается с ошибкой, потом накопитель начинает выдавать переназначенные сектора, и только когда сдвиги складываются в одну кучу, приходит отказ. Месячный цикл обслуживания закрывает именно медленную деградацию: она незаметна день ото дня, но хорошо видна на дистанции в четыре недели.

Смысл цикла в том, чтобы раз в месяц возвращать сервер в известное состояние, а каждое отклонение фиксировать в протоколе. Проверять всё подряд не нужно, у мониторинга своя работа и свой темп. Ниже разобран набор действий, закрывающий медленные процессы: обновления, копии, место, накопители, учётные записи, сертификаты, службы и сеть. Каркас месячного прогона умещается в один список:

  1. проверить и установить обновления безопасности, при смене ядра согласовать перезагрузку в плановое окно;
  2. убедиться, что задания резервного копирования за месяц прошли успешно, и выполнить выборочное восстановление;
  3. проверить свободное место по разделам, почистить старые журналы и временные файлы, убедиться в работе ротации;
  4. снять показания самодиагностики накопителей, сверить температуры и просмотреть ошибки ядра за месяц;
  5. провести ревизию учётных записей, возраста паролей и административных доступов;
  6. проверить сроки действия сертификатов и ключей, внести даты перевыпуска в календарь;
  7. просмотреть незапланированные перезапуски и ошибки служб, сверить слушающие порты и правила фильтрации;
  8. записать результаты и изменения месяца в протокол обслуживания.

Дальше каждый пункт раскрыт с командами и рабочими деталями.

Обновления безопасности и плановая перезагрузка после смены ядра

Обновления безопасности стоят в списке первыми не случайно: незакрытая уязвимость сетевой службы доступна извне круглосуточно, остальные пункты спокойно подождут час. На Debian и Ubuntu базовая последовательность знакома каждому:

apt update
apt list --upgradable
apt upgrade

На сервере под действующей нагрузкой ставят чаще только исправления безопасности. Пакет unattended-upgrades делает это автоматически по расписанию, его настраивают один раз:

apt-get install unattended-upgrades

В файле /etc/apt/apt.conf.d/50unattended-upgrades задаётся, какие репозитории использовать: только security-источник или всё сразу. В семействе RHEL та же логика через dnf:

dnf check-update
dnf upgrade --security

С ядром история отдельная. После его обновления в памяти продолжает работать старая версия, и уязвимость остаётся открытой, хотя обновление уже установлено. На Ubuntu после обновлений, требующих рестарта, появляется файл /var/run/reboot-required, проверить его достаточно командой cat. На RHEL ответ даёт команда needs-restarting с ключом -r из пакета dnf-plugins-core. Полезна и утилита needrestart: она перечисляет службы, которые после обновления библиотек продолжают работать со старыми версиями, и подсказывает, что перезапускать первым делом.

Перезагрузку не делают "когда-нибудь": под неё выделяют плановое окно, согласованное с командой и пользователями. Разница между "перезагрузим в среду ночью" и "перезагрузим, когда будет минутка" превращается в разницу между плановым обслуживанием и внеплановым простоем. Команда shutdown -r 22:30 ставит рестарт на точное время, а подключённым пользователям уходит сообщение с причиной. У Canonical есть сервис Livepatch по подписке Ubuntu Pro: он накладывает критические исправления ядра на работающую систему и откладывает перезагрузку, но полного обновления без рестарта не отменяет.

После перезагрузки проверяют три вещи: uptime -s покажет фактическое время старта системы, uname -r подтвердит новое ядро, systemctl --failed выявит службы, не поднявшиеся обратно. Всё, что не сошлось, уходит в протокол в тот же день, пока детали свежи.

Контроль резервных копий за месяц и выборочный тест восстановления

Резервная копия, которую ни разу не восстанавливали, остаётся предположением. До первого восстановления это набор файлов, про который кто-то когда-то сказал, что он годится для возврата данных. Месячный контроль копий состоит из трёх частей: история заданий, место в хранилище и выборочный тест.

Начинают с истории заданий. Если копирование запущено через systemd-таймер, всё просто:

systemctl list-timers --all
journalctl -u restic-backup.service --since "30 days ago"

В журнале ищут ошибки и ночные сводки. Инструменты помогают сами: restic печатает сводку добавленных и изменённых файлов, borg хранит список архивов с датами, rsnapshot пишет отчёт в /var/log/rsnapshot.log. Смотреть нужно не только факт успеха, но и объём: если ночная копия внезапно похудела в десять раз, значит, изменилось поведение задания, и чаще всего причина в забытом смонтированном разделе или расширившемся исключении в маске файлов.

Дальше смотрят хранилище копий. На хосте с резервами выполняют df -h /srv/backup и сравнивают цифры с прошлым месяцем. Рост должен быть предсказуемым: база прибавляет известный объём, логи известный, скачок на треть раздела за месяц требует разбирательства. У restic есть собственная проверка целостности:

restic check --read-data-subset=5%

Команда проверяет структуру репозитория и читает случайные 5% содержимого, сверяя контрольные суммы. Полное чтение оставляют на квартал, для месяца достаточно выборки.

Третья часть - тест восстановления. Из свежего архива возвращают один небольшой файл в отдельный каталог и сверяют результат:

restic restore latest --target /tmp/restore-test --include /etc/nginx/nginx.conf
diff /tmp/restore-test/etc/nginx/nginx.conf /etc/nginx/nginx.conf

С дампами баз схема та же: архив разворачивают во временную базу и выполняют пару выборочных запросов. Для файловых архивов достаточно сверки контрольных сумм. Дата теста, имя архивной копии и результат попадают в протокол. Пять минут работы в месяц закрывают вопрос, на который иначе отвечают только во время аварии, и тогда цену ответа назначает сама авария.

Место на разделах, чистка старых журналов и работа ротации

Место на диске кончается по-разному: иногда честно заполняется раздел, иногда исчерпываются inodes при полупустом выводе df. Поэтому смотрят обе картины:

df -h
df -i

Крупных потребителей ищут сверху вниз:

du -h --max-depth=1 /var 2>/dev/null | sort -h | tail -20

В интерактивном режиме удобен ncdu: он показывает те же цифры и позволяет сразу просмотреть подозрительный каталог. Стабильный набор пожирателей места известен каждому: журналы, временные файлы, кэш пакетного менеджера, старые ядра, образы контейнеров.

Журнал systemd растёт незаметно, его объём проверяют одной командой:

journalctl --disk-usage

Лимит задаётся в /etc/systemd/journald.conf:

[Journal]
SystemMaxUse=500M
Compress=yes

После правки конфигурации службу журнала перезапускают, а немедленную уборку выполняют через journalctl --vacuum-size=500M либо journalctl --vacuum-time=30d. Ротация классических лог-файлов живёт в logrotate. Проверить конфигурацию без выполнения изменений можно в режиме отладки:

logrotate -d /etc/logrotate.conf

Состояние ротации хранится в файле /var/lib/logrotate/status: по нему видно, когда обработчик заходил в последний раз и что крутил. Если в /var/log/nginx лежат только свежие файлы без суффиксов .1 и .gz, ротация для сайта не настроена, и место съедается медленно, без единого оповещения от мониторинга. Для собственного приложения с журналом в /var/log/app настройка занимает один блок:

/var/log/app/app.log {
    weekly
    rotate 8
    compress
    delaycompress
    missingok
    notifempty
    postrotate
        systemctl reload app.service
    endscript
}

Здесь еженедельный поворот, хранение восьми копий, сжатие со сдвигом на один шаг и мягкая перезагрузка службы после ротации.

Временные файлы чистит механизм tmpfiles: настройка лежит в /etc/tmpfiles.d, уборку по расписанию выполняет systemd-tmpfiles --clean. Забытые файлы старше месяца в /var/tmp ищут так:

find /var/tmp -type f -mtime +30

Кэш пакетов убирают через apt-get clean или dnf clean all, старые ядра на Debian и Ubuntu снимает apt-get autoremove --purge, в семействе RHEL количество хранимых ядер ограничивает параметр installonly_limit в /etc/dnf/dnf.conf. Отдельная строка бюджета - контейнеры:

docker system df
docker system prune --filter "until=168h"

Вторая команда убирает остановленные контейнеры, потерянные образы и кэш сборки старше недели; тома она по умолчанию не трогает, и это правильно: решения об удалении томов человек принимает сам.

Состояние накопителей, температуры и ошибки ядра за месяц

Накопители изнашиваются предсказуемо, и месячная сверка ловит тренд задолго до отказа. Базовая проверка занимает секунды:

smartctl -H /dev/sda

Ответ PASSED значит, что встроенная самодиагностика не видит проблем, но итоговое здоровье смотрят по атрибутам:

smartctl -A /dev/sda | egrep "Reallocated_Sector_Ct|Current_Pending_Sector|Temperature_Celsius|Power_On_Hours"

Reallocated_Sector_Ct и Current_Pending_Sector должны оставаться нулями. Ноль, ставший единицей, не причина для тревоги, а причина для наблюдения; рост от прогона к прогону - уже основание планировать замену диска. Раз в месяц полезно запускать короткий тест самодиагностики:

smartctl -t short /dev/sda
smartctl -l selftest /dev/sda

Первая команда запускает тест, вторая показывает историю результатов. Для NVMe те же вопросы задаёт smartctl -a /dev/nvme0: в выводе есть строки Percentage Used и Media and Data Integrity Errors, по которым видно износ и ошибки целостности.

Температуры снимают пакетом lm-sensors командой sensors, накопители отдают свою температуру в атрибутах SMART. Значение само по себе мало что говорит, смысл появляется в сравнении с прошлым месяцем: стабильные цифры при той же нагрузке - норма, заметный прирост при неизменной нагрузке - сигнал о проблемах охлаждения.

Журнал ядра за месяц просматривают на ошибки ввода-вывода и сбои памяти:

journalctl -k -p err --since "30 days ago"
dmesg -T --level=err,warn

Ищут сообщения с "I/O error", ошибки файловой системы EXT4-fs, записи о сбросах nvme-устройств. Исправляемые ошибки памяти собирает служба rasdaemon, а сводку по ним выводит ras-mc-ctl --summary. Единичный сбой и устойчивый поток сбоев - разные ситуации: первый наблюдают, второй требует немедленной реакции.

Ревизия учётных записей и сроки сертификатов с ключами

Учётные записи обрастают лишним медленно: тестовый доступ "до конца недели", подрядчик с закрытым проектом, стажёр прошлого лета. Месячная ревизия отвечает на три вопроса: кто входил, у кого какие права, у кого пароль не менялся год. Начинают с тех, кто не входил давно:

lastlog -b 60

Команда выводит пользователей, чей последний вход старше шестидесяти дней. Дальше список сверяют с кадровой реальностью: уволенных блокируют, а не удаляют сразу. Сначала архивируют домашний каталог и проверяют, что архив читается, и только потом убирают учётную запись. Блокировка на время разбора:

usermod -L username

Возраст пароля смотрят через chage:

chage -l username
chage -M 90 -W 7 username

Первая команда показывает возраст и политику пароля, вторая задаёт максимум девяносто дней и предупреждение за неделю до истечения. Административные доступы проверяют шире. Список UID 0 обязан содержать только root:

awk -F: '$3 == 0 {print $1}' /etc/passwd

Файлы в /etc/sudoers.d просматривают на предмет правил с NOPASSWD и правами на всё подряд, синтаксис проверяет visudo -c. Эту проверку прогоняют после каждого изменения sudoers, а не только раз в месяц. Ключи SSH из authorized_keys ушедших коллег удаляют в тот же день, а не в конце квартала.

С сертификатами главная беда не в самом сертификате, а в дате. Сроки смотрят так:

openssl x509 -in cert.pem -noout -dates
openssl x509 -checkend 2592000 -noout -in cert.pem

Первая команда печатает начало и конец срока, вторая завершается успешно, пока сертификат проживёт больше тридцати дней. Если перевыпуск ручной, дата попадает в календарь с запасом. Автоматическое обновление через certbot тоже проверяют: certbot certificates покажет все известные ему сертификаты, certbot renew --dry-run прогонит обновление без изменения файлов, а перезагрузку службы после реального перевыпуска выполняет deploy-hook с командой вида systemctl reload nginx. Вдобавок смотрят права на секреты приложений: файлы .env не должны быть читаемы всеми:

find /srv -name ".env" -perm /077

Пустой вывод - то, что хочется увидеть.

Поведение служб, слушающие порты и синхронизация времени

Службы оставляют следы за месяц, и следы читаются быстрее инцидентов. Отправная точка:

systemctl --failed

Для каждого упавшего юнита смотрят журнал за месяц и решают, было ли падение разовым сбоем или закономерностью. Число автоматических перезапусков systemd считает сам:

systemctl show nginx.service -p NRestarts

Свойство NRestarts растёт у служб с параметром Restart=on-failure: служба падает ночью, поднимается за секунду, мониторинг молчит, потому что проверка прошла уже после подъёма. Ненулевое значение за месяц - причина открыть журнал и найти корень. Ошибки по всей системе собирает journalctl -p err --since "30 days ago".

Лишние службы убирают из автозапуска:

systemctl disable --now имя-службы
systemctl mask имя-службы

Первая команда останавливает службу и исключает её из автозапуска, вторая запрещает запуск даже при зависимости от других юнитов. Каждое такое решение записывают в протокол: через полгода обязательно спросят, почему службы нет.

Сеть проверяют с двух концов: что слушает сервер и что разрешено фильтром. Слушающие сокеты:

ss -tulpn

Вывод сверяют с известным списком: лишний порт означает либо новую службу, о которой никто не сообщил, либо чужой процесс. Удобно держать снимок и сравнивать:

ss -tulpn > /root/ports.txt
diff /root/ports.old.txt /root/ports.txt

Правила фильтрации смотрят по инструменту: nft list ruleset показывает полный набор nftables, firewall-cmd --list-all выводит зоны firewalld, ufw status verbose перечисляет правила ufw. В правилах ищут забытые временные разрешения: порт, открытый "на вечер" для теста, живёт годами.

Время проверяют через timedatectl: в выводе должны стоять NTP service: active и System clock synchronized: yes. Подробности для chrony дают chronyc tracking и chronyc sources: первая команда показывает смещение часов, вторая список серверов времени с их качеством. Смысл не в церемонии: рассинхронизация ломает TLS-соединения, смешивает журналы разных серверов при разборе инцидента и сдвигает задания cron. Пять минут проверки экономят часы разбора.

Протокол изменений и границы чек-листа рядом с мониторингом

Последний пункт цикла держит всё вместе. Прогон ставят в календарь фиксированным блоком, один рабочий день в месяц, без варианта "когда появится время": чек-лист, который выполняется по остаточному принципу, через квартал превращается в формальность. Протокол выполнения - обычный текстовый файл или задача в системе учёта, по одной записи на прогон: дата, исполнитель, версия чек-листа, результат по каждому пункту, найденные отклонения, задачи-последствия. Выглядит скромно:

дата | исполнитель | версия | пункт | результат | что сделано | задача

Ценность проявляется позже. Через квартал записи отвечают на вопросы, которые иначе повисают в воздухе: когда начался рост занятости места, после какого обновления служба стала падать по ночам, кто и почему открыл порт. Протокол превращает обслуживание из последовательности галочек в историю сервера, у которой можно перечитать предыдущие главы.

Чек-лист при этом остаётся живым документом. Раз в квартал его пересматривают: новые сервисы добавляют пунктами, исчезнувшие убирают вместе с их проверками. Когда по метрике настроено автоматическое оповещение, ручная проверка уходит из списка: следить за свободным местом каждую минуту должен мониторинг, а не человек раз в месяц. Пара Prometheus с Alertmanager, Zabbix или Netdata закрывает события: место кончилось, служба остановилась, сертификат истекает. Чек-лист отвечает за другое: за то, что осмотрено глазами и руками. Тест восстановления оповещение не сделает, тренд переназначенных секторов не покажет, забытый временный доступ в sudoers не найдёт. Разделение простое: мониторинг ловит события, месячный цикл ловит дрейф.

Пункты цикла делят по уровню ответственности. Инвентаризацию портов и просмотр журналов можно доверить начинающему администратору, тест восстановления и ревизию правил фильтрации оставляют за старшим. Протокол делает передачу безопасной: новый человек читает последние записи и понимает состояние сервера без устных пересказов.

Плата за месячную дисциплину небольшая, несколько часов работы. Взамен сервер большую часть года живёт в известном состоянии, деградация замечается на стадии, когда её исправляют планово, а перед разбором любого сбоя есть протокол, из которого видно, что менялось в последний месяц. Чек-лист работает как страховка: не та, что предотвращает событие, а та, что превращает неизвестное в известное. А известное чинить всегда дешевле.