Хроника обслуживания сервера: диагностика, очистка, безопасность и публикационная платформа
Ниже — сжатое резюме работ на сервере с момента начала обслуживания. Изложение обезличено: без токенов, идентификаторов аккаунтов, ключей и адресов секретов.
1. Диагностика и очистка диска🔗
Исходная проблема: системный диск заполнен на 79% (свободно ~17 ГБ) — риск остановки сервисов и отказа записи.
Что сделано:
- инвентаризация крупных потребителей: контейнерные образы, кэши сборщиков, старые архивы артефактов, временные каталоги;
- удаление неиспользуемых образов — с проверкой реальных зависимостей работающих контейнеров (по привязке к образам, а не по имени тега);
- очистка резервных копий дистрибутов и временных файлов сборок;
- хранилище runtime-образов контейнеров не тронуто — это рабочая инфраструктура, а не мусор.
Результат: 59% занято, свободно 32 ГБ (было 17), освобождено ~12 ГБ. Все удалённое зафиксировано в манифестах; копии удалённых компонентов сохранены в изолированном каталоге.
2. Санация служб: удаление мёртвых процессов🔗
- Приёмник Telegram-сообщений. Токен недействителен (API возвращает 404), служба выключена и не выполняла задач. Удалена с сохранением копии.
- Внешний ping-мониторинг (Healthchecks.io). Пинги блокировались на уровне сети провайдера (HTTP 403) — мониторинг существовал формально, сигналов не давал. Удалён вместе с cron-записями и ключом.
Замены не потребовалось: на сервере уже работал собственный стек — Uptime-Kuma и скрипт мониторинга критичных служб, полностью под контролем и без внешней зависимости.
3. Безопасность: исправление опасной cron-задачи🔗
В планировщике обнаружена еженедельная очистка Docker в формулировке, удалявшей все неиспользуемые образы и тома принудительно. Для сервера с рабочими базами в контейнерах — это прямой риск безвозвратной потери данных (и он был близок: 25 из 27 образов реально используются).
Заменено на безопасный вариант: срезка только «висячих» образов и остановленных контейнеров, логирование сохранено. Остальные задачи планировщика (бэкапы в объектное хранилище, мониторинг памяти, обновления пакетов) проверены и не изменены. Перед правкой снята полная копия crontab.
4. Почтовый сервис: миграция на новую мажорную версию🔗
Почтовый сервер Stalwart переведён с 0.15.5 на 0.16.24 — апгрейд с ломкой обратной совместимости (формат конфига toml → json, REST-API → JMAP, имена аккаунтов → email).
- миграция офлайн и по официальному руководству: дамп всех настроек и principals (3787 параметров, 9 сущностей) → конвертер → новый
config.json+ файл экспорта; применение через recovery-режим и CLI, 10 объектов, 0 ошибок; - полная точка отката: копия конфигурации, старого бинарника, базы и каталога данных плюс systemd-unit до миграции;
- вручную воссоздано то, что не мигрируется: четыре сетевых листенера (SMTP, submission, submissions с implicit TLS, админ-HTTP), сертификат и ссылка на дефолтный;
- найдена первоисточник давней TLS-проблемы: сертификат в хранилище сервера был просрочен — из-за этого порты 465/587 отдавали не боевой сертификат. Пересоздан из свежего выпускного; проверка доставки письма на внешний ящик прошла с TLS 1.3;
- подписи писем стали лучше: включено автоматическое управление DKIM с ротацией ключей; сервер сам выпустив второй ключ (Ed25519) рядом с рабочим RSA — исходящие письма подписываются двумя подписями, для второй требуется публикация новой DNS-записи;
- доступ администратора восстановлен после миграции (в recovery-режиме роли не создаются сами): выдана реальная роль плюс отдельный fallback-админ через файл секретов с правами root-only;
- мёртвый хвост убран: сервис postfix падал, не смог занять порт 25 (его держал Stalwart) — служба своей почты не использовалась; отключена и замаскирована, итог — ноль упавших systemd-юнитов;
- логи переведены в файл с ротацией, IMAP по указанию владельца не включался.
5. База знаний (Outline): доступ, ключи и интеграции🔗
Корпоративная wiki на Outline (контейнеры с PostgreSQL, Redis, own nginx-прокси):
- программный доступ настроен без штатного UI: ключ создан прямым внесением в базу, проверен живыми запросами (аутентификация, список коллекций); права — административные;
- секрет убран из временного каталога в защищённое хранилище с правами
600только для root, временный файл уничтожен; закреплён принцип «секреты не попадают в git-память и в переписку»; - описана и учтена изоляция общего объектного хранилища: один bucket используется почтой, базой знаний и резервными копиями — зафиксировано, кто пишет по какому префиксу, чтобы обслуживание не затронуло чужие данные;
- плашка cookie на базе знаний и webmail переделана со встроенной вёрстки на внешний скрипт, отдаваемый с того же origin: проходит строгую политику CSP без её ослабления и без nonce, с видимой кнопкой согласия и ссылкой на политику; проверка синтаксиса и доступности выполнена;
- экспорт базы знаний в Markdown не делался — решение принял владелец (признано нецелесообразным), поисковый индекс отложен.
6. Сетевая безопасность: закрытие случайно опубликованных Docker-портов🔗
Критичная находка: Docker публиковал внутренние сервисы наружу в обход межсетевого экрана — UFW его правила не покрывают. Проверено извне независимым сканером: доступны 5 портов — две СУБД (PostgreSQL), кэш (Redis) и два бэкенда.
- закрытие через цепочку
DOCKER-USER(единственное место, где правила Docker не перебиваются): DROP по каждому порту, отдельно для IPv4 и IPv6; - техническая тонкость, без которой фикс не сработал: обычный фильтр порта не матчится из-за DNAT (внешний порт 3004 транслируется во внутренний 80), поэтому правило строится по исходному порту назначения из сокет-трекинга;
- правила вынесены в скрипт с systemd-службой, которая стартует после и вместе с Docker и остаётся активной — защита не теряется при перезапуске или обновлении контейнеров;
- итог: все пять портов снаружи закрыты, почта (25/587/465) и веб (80/443) работают без изменений; служебный порт provisioner дополнительно ограничен только docker-подсетями;
- вывод на будущее зафиксирован: каждый новый порт в контейнерах требует проверки наружу и, при необходимости, правила в этом скрипте;
- попутно выполнена антивирусная проверка сервера (rkhunter, chkrootkit, проверка SUID/preload/майнеров) — чисто.
7. Обзор готовых решений под задачи🔗
По запросу владельца разобраны открытые проекты: мультиагентные оркестраторы, векторная память ассистентов, инструменты автоматизации. Вывод: из десяти рассмотренных под текущую инфраструктуру прямо применимы три–четыре. Основной кандидат — YAML-оркестратор мультиагентных цепочек поверх tmux (сам мультиплексор уже используется). Остальные — из другой предметной области. Решение принято за владельцем, ничего не устанавливалось.
8. Публикационная платформа: n.syntog.ru🔗
Сайт на генераторе Zola (Rust) в режиме dev-сервера за nginx с TLS от Let's Encrypt.
Издательский цикл🔗
- Источник — документ из облачного редактора выгружен, очищен от артефактов разметки, преобразован в Markdown.
- Раздел «Omarchy» — создана секция с описанием, сортировкой по датам и карточками материалов.
- Статья — «Архитектура, экосистема и прикладной потенциал операционной системы Omarchy» (≈4 700 слов): идеология проекта, архитектура (Hyprland + Quickshell), модульная система плагинов, IPC и безопасность маркетплейса, интеграция ИИ-агентов как сущностей первого класса, сетевая безопасность и автономная установка, сравнительная матрица с системами оркестрации агентов.
Обновление движка: Zola 0.19.2 → 0.23.6🔗
Установленная версия была почти на два года старше актуальной. Обновление прошло по шагам и выявило несколько скрытых проблем:
- резервная копия бинарного файла, загрузка и проверка новой сборки, миграция через systemd-сервис;
- формат конфигурации переработан: настройки подсветки кода стали вложенной таблицей с другими именами полей — потребовалась правка
config.toml; - битый контент: на старых документационных страницах примеры шаблонов содержали неразэкранированные конструкции вида двойные фигурные скобки и percent-теги. Прежняя версия парсила их «по случайности», новая — отказала. Исправлено экранированием; устаревшая документация перенесена в отдельный раздел, корневая страница переписана как живое оглавление сайта;
- переписаны шаблоны: единая база для всех страниц, корректный вывод разделов и списков статей;
- проверено, что при сборке не осталось ошибок и все страницы отдают 200.
Оформление: читабельность🔗
Прежний вид сайта был фактически без стилей — CSS подключался по пути несуществующего файла. Спроектирован заново:
- serif-вёрстка, оптимальная ширина строки, межстрочный интервал 1.75, типографская шкала заголовков;
- автоматическая тёмная тема (
prefers-color-scheme) и адаптивная мобильская версия; - стилизованные таблицы, код-блоки, цитаты, карточки статей;
- якорные ссылки у заголовков;
- строка метаданных под заголовком: дата, число слов и время чтения;
- липкая навигация: Главная · Omarchy · Статьи · Глоссарий · Документация — с подсветкой активного раздела. Исправлены битые ссылки (в частности, создан раздел «Статьи», куда ранее вел пункт меню).
Превью для мессенджеров🔗
Для публикации ссылок в Telegram:
- Open Graph и Twitter Card метатеги: заголовок, описание, картинка;
- сгенерирована обложка 1200×630 в стиле раздела;
- ссылки в метатежах зафиксированы как публичные (домен вместо адреса локальной сборки) — иначе бот мессенджера не смог бы загрузить превью;
- значения подставляются автоматически из данных страницы, работают для любого будущего материала.
9. Собственная аналитика прочтений🔗
Статистика без внешних счётчиков и без передачи данных третьим лицам:
- обработчик логов nginx (включая ротированные архивы) считает просмотры конкретной статьи;
- уникальные читатели — по IP с нормализацией мобильных подсетей, с исключением поисковых, проверяющих и инфраструктурных ботов;
- отдельно учитываются заходы Telegram при генерации превью — видно, что ссылкой делились в чате, но эти обращения не попадают в «читатели»;
- разбивка по дням и топ рефереров (откуда приходят);
- накопительная история «за всё время» в отдельном снимке — устойчива к ротации логов;
- результат: человекочитаемая HTML-страница с карточками плюс JSON-выгрузка, доступны под паролем на служебном поддомене статистики;
- обновление встроено в уже существующий системный таймер генерации трафик-отчёта (каждые полчаса), отдельный планировщик не создавался.
Отдельно: основной домен статистики занимает сторонний проект (RailSync) — он не затронут, аналитика размещена на служебном поддомене.
10. Настройка связи с облачным хранилищем🔗
Налажено соединение сервера с облачным дисktорidji (Google Drive) для обмена рабочими материалами:
- подключение через rclone (remote настроен, объём хранилища 5 ТБ, работающие папки проверены списыванием);
- продление токена выполнено на сервере самостоятельно через refresh-механизм rclone — доступ восстановлен без ручной вставки кодов из чата; прямой доступ к API облака мимо rclone заблокирован провайдером OAuth-клиента, поэтому все операции ведутся только штатным инструментом;
- налажен обмен документами с внешней ИИ-системой через согласованную папку: файлы передаются с SHA-256 сверкой побайтово в обе стороны;
- при архивировании дублей выявлены и задокументированы ограничения инструмента (перепись одинаковых имён при переносе, адресация только по путям, не по ID) — выработаны правила безопасной обработки, потери ограничены промежуточными копиями, все актуальные артефакты целы.
11. Аудит проекта «ГРАНИ»🔗
Выстроен и проведён цикл машинного аудита инженерного проекта ГРАНИ (железнодорожные аналитические расчёты, Rust + веб-интерфейс):
- проверка артефактов релиза: сверка SHA-256 заявленных и фактических файлов кодовой базы и архивов — расхождений нет;
- инвентаризационный аудит: независимый ИИ-аудитор собирал состав релиза (размеры, количество файлов, дайджест кода) и выдавал протокол с дефектами по классам P0/P1/P2, с жёсткой установкой «искать дефекты, не подтверждать корректность»;
- найдены реальные проблемы: отсутствующий файл контрольных сумм дистрибутива (на него ссылались 11 артефактов), ложная статистика в описании (заявленные 80 подклассов против ~17 в коде), расхождение числа XML-документов, десятки дублей архивов и самопротиворечия релизной нотации;
- инцидент P0: при проверке веб-интерфейса обнаружен критический дефект; составлены протокол инцидента и hotfix-уведомление, опубликованы в папке обмена, хеши сверены с Диском;
- UI E2E-прогон: автоматическая проверка интерфейса с базовыми и исправленными скриншотными артефактами, XLSX-сводкой и манифестом;
- рекомендации разработчику: обоснован отказ от «правки живого релиза» (ломает верифицированные хеши), предложен корректный путь — spec-as-code, матрица трассируемости, SBOM (SPDX), неизменяемые релизы; составлено ТЗ из 9 пунктов;
- каскад пересборки измерен на практике: одна пропущенная скобка в источнике влекла пересборку 12 релизных артефактов — отсюда требование автоматизированного build-скрипта;
- все протоколы закреплены тегами в git и дублируются в облаке; рабочая копия разработки изолирована от прода и аудита.
12. Dev-среда ИИ-агента (omp) — проблемы решены🔗
Построена серверная среда разработки с TUI-агентом omp (oh-my-pi), чтобы работать удалённо:
- проблема 1 — агент не запускался: пакет требовал рантайм
bun, которого не было (env: 'bun': No such file). Установлен bun, агент живой; - проблема 2 — агент уходил не на того провайдера: механизм нечётко сопоставлял имена моделей и подставлял чужого облачного провайдера («No API key»). Решение — прозрачная привязка моделей в конфигурации (
providers:с явным base-URL ретранслятора) и правило: всегда указывать модель с префиксом провайдера; - проблема 3 — переменные окружения не доходили до агентов: GUI-агенты, запущенные из «холодного» терминала, не видели ключ ретранслятора. Причина: systemd читает
environment.dпри логине, а.bashrcдействует только в интерактивном bash. Фикс — новый терминал либо явный source конфига; - развёрнуты также opencode и codex-cli; создан лаунчер проекта с обёрткой PATH и tmux-сессиями; живой прогон подтвердил работу (чтение файла, проверка синтаксиса — успешно).
13. Соблюдаемые принципы🔗
- Резервная копия перед каждым удалением — файлы, конфигурации, crontab, шаблоны; каталог
.backupрядом с контентом, манифесты в изолированном хранилище. - Ничего работающего не трогается без отмашки владельца — производственные каталоги и контейнеры ключевых сервисов не изменены.
- Проверка зависимостей вместо имён — образы удалялись только после подтверждения, что на них ничего не запущено.
- Автоматическая проверка результата — после каждой правки: тест конфигурации веб-сервера, сборка сайта, прогон всех URL через HTTP-проверку.
Итог🔗
| Направление | Было | Стало |
|---|---|---|
| Диск | 79% занято, 17 ГБ свободно | 59%, 32 ГБ |
| Мёртвые службы | 2 (битый приёмник, заблокированный пинг) | 0, работает собственный мониторинг |
| Опасная cron-задача | принудительная очистка образов и томов | безопасная срезка неиспользуемого |
| Движок сайта | Zola 0.19.2, стили отсутствовали | Zola 0.23.6, полноценный дизайн с тёмной темой |
| Публикации | структура не оформлена | раздел Omarchy, 2 статьи, рабочая навигация, превью для мессенджеров |
| Облачное хранилище | доступ требовал ручных кодов, дубли в архивах | rclone-токен продлён на сервере, обмен папкой с SHA-сверкой |
| Аудит проекта | артефакты не верифицированы | полный цикл: сверка хешей, P0/P1/P2 протоколы, инцидент P0, ТЗ разработчику, git-теги |
| omp (агент) | не запускался, уходил на чужого провайдера | рабочая dev-среда: bun, конфиг провайдера, environment.d, лаунчер |
| Почтовый сервер | старая версия с просроченным TLS-сертификатом | новая мажорная версия, двойной DKIM, TLS исправлен, мёртвый postfix убран |
| База знаний | не было программного доступа | API-ключ с проверкой, секрет в защищённом хранилище, CSP-совместимая плашка |
| Сетевая безопасность | 5 внутренних сервисов торчали наружу | закрыты правилами по исходным портам + постоянная служба |
| Статистика | только общий отчёт по трафику | собственная аналитика прочтений под паролем |