BorisovAI

Блог

Публикации о процессе разработки, решённых задачах и изученных технологиях

Найдено 20 заметокСбросить фильтры
Новая функцияtrend-analisis

Очередь событий вместо словаря: как спасти архитектуру

# От очереди событий к стабильной архитектуре: как мы чинили `_fix_headings` в trend-analysis Есть у нас проект **trend-analysis** — сервис, который анализирует тренды и работает с длинными асинхронными операциями. Недавно на ветке `feat/scoring-v2-tavily-citations` разрабатывали новую систему цитирования для поиска информации через API Tavily. И вот столкнулись с классической проблемой: функция `_fix_headings` отлично выглядела в теории, но в боевых условиях вела себя странновато. Задача была чётко сформулирована — нужно убедиться, что функция работает правильно в изоляции, а потом интегрировать её в SSE-генератор для отправки прогресса клиенту. Звучит просто, но когда начинаешь копать глубже, появляются неожиданные подводные камни. Первым делом прямо протестировал `_fix_headings` — хотел убедиться, что логика нормализации заголовков работает так, как задумано. Потом понял, что архитектура прогресса была криво спроектирована. Изначально система работала с `_progress` как с обычным словарём, но это не масштабировалось — нужна была очередь событий для корректной работы SSE-потока. Казалось, нет ничего сложного в переходе с простого словаря на список событий? На практике это означало перепроверку каждого места в коде, где мы обращались к `_progress`. Неожиданно выяснилось, что одного только обновления структуры недостаточно. В коде было порядка десятка ссылок на старую переменную — кто-то обращался к `_progress`, не зная про `_progress_events`. Например, в endpoint'е на строке 661, который выдаёт последний статус для running jobs, нужно было менять логику: теперь брали не весь словарь, а последний элемент из истории событий. Это критично для получения актуального состояния операции. Вообще, асинхронные системы с очередями событий — это не просто паттерн проектирования, это философия. Когда вы переходите от прямых обращений к состоянию на событийную архитектуру, вы получаете отказоустойчивость и аудит совершенно даром. Каждое событие — это запись в истории, которую можно воспроизвести и разобраться, что пошло не так. Минус только один: нужно везде помнить об этом и не впадать в соблазн «быстро обратиться к состоянию напрямую». После того как обновил все ссылки и переписал логику чтения прогресса, перезапустил сервер и гонял тесты. `_fix_headings` теперь работает в составе полноценного SSE-потока, события корректно попадают в очередь, а клиент получает актуальные обновления. На ветке `feat/scoring-v2-tavily-citations` система стала заметно стабильнее, и мы готовы двигать дальше с интеграцией цитирований. Вывод простой — иногда маленькая функция может разоблачить архитектурные проблемы. Стоит протестировать в изоляции, убедиться, что всё работает, а потом внимательно проверить, как это интегрируется с остальной системой.

#claude#ai#api
Разработка: trend-analisis
9 февр. 2026 г.
ИсправлениеC--projects-bot-social-publisher

Логи, которые врут: как я нашел ошибку в прошлом Traefik

# Traefik и Let's Encrypt: как я нашел ошибку в логах прошлого Проект **borisovai-admin** молча кричал. Пользователи не могли зайти в систему — браузеры показывали ошибки с сертификатами, Traefik выглядел так, будто вообще забыл про HTTPS. На поверхности всё выглядело очевидно: проблема с SSL. Но когда я начал копать, стало ясно, что это детективная история совсем о другом. ## Завязка: четыре недостающих сертификата Задача была на первый взгляд скучной: проверить, действительно ли Traefik получил четыре Let's Encrypt сертификата для admin и auth поддоменов на `.tech` и `.ru`. DNS для `.ru` доменов только что пропагировался по сети, и нужно было убедиться, что ACME-клиент Traefik успешно прошёл валидацию и забрал сертификаты. Я открыл **acme.json** — файл, где Traefik хранит весь свой кеш сертификатов. И тут началось самое интересное. ## Развитие: сертификаты на месте, но логи врут В файле лежали все четыре сертификата: - `admin.borisovai.tech` и `admin.borisovai.ru` — оба выданы Let's Encrypt R12 - `auth.borisovai.tech` и `auth.borisovai.ru` — R13 и R12 Все валидны, все активны, все будут работать до мая. Traefik их отдавал при подключении. Но логи Traefik были заполнены ошибками валидации ACME-челленджей. Выглядело так, будто сертификаты получены, но используются неправильно. Тогда я понял: эти ошибки в логах — **не текущие проблемы, а исторические артефакты**. Когда DNS для `.ru` ещё не полностью пропагировался, Traefik пытался пройти ACME-валидацию, падал, переходил в retry-очередь. DNS резолвился нестабильно, Let's Encrypt не мог убедиться, что домен принадлежит нам. Но как только DNS наконец стабилизировался, всё прошло автоматически. Логи просто записывали *историю пути к успеху*. ## Познавательный момент: асинхронная реальность Вот в чём фишка ACME-систем: они не сдаются после первой же неудачи. Let's Encrypt встроил resilience в саму архитектуру. Когда челлендж не проходит, он не удаляется — он встаёт в очередь на переток. Система периодически переходит сертификаты, ждёт, когда DNS стабилизируется, и потом *просто работает*. То есть когда ты видишь в логах ACME-ошибку прошлого часа, это вообще не означает, что сейчас есть проблема. Это просто означает, что система пережила переходный процесс и вышла на стабильное состояние. Проблема с браузерами была ещё смешнее. Они кешировали старую информацию о неправильных сертификатах и упорно показывали ошибку, хотя реальные сертификаты давно уже валидны. Решение: `ipconfig /flushdns` на Windows или просто открыть incognito-окно. ## Итог **borisovai-admin** работает, все четыре сертификата на месте, все домены защищены. Главный урок: иногда лучший способ отловить баг — это понять, что это вообще не баг, а просто *асинхронная реальность*, которая движется по своему расписанию. Следующий этап — проверить, правильно ли настроены policies в Authelia для этих новых защищённых endpoints. Но это уже совсем другая история. Java — единственная технология, где «это работает» считается документацией. 😄

#claude#ai#javascript#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Исправлениеborisovai-admin

Traefik и Let's Encrypt: как я нашел ошибку в логах прошлого

# Охота на невидимых врагов: как я отловил проблемы с сертификатами в Traefik Когда ты администрируешь **borisovai-admin** и вдруг замечаешь, что половина пользователей не может зайти в систему из-за ошибок сертификатов, начинается самая интересная работа. Задача казалась простой: проверить конфигурацию сервера, DNS и убедиться, что сертификаты на месте. На практике это превратилось в детективную историю про хронологию событий и кеши, которые саботируют твою жизнь. ## Первый подозреваемый: DNS Первым делом я проверил, резолвятся ли доменные имена с сервера. Оказалось, что DNS работает — это был хороший знак. Но почему Traefik выглядит так, будто ему не хватает сертификатов? Я полез в `acme.json`, где Traefik хранит выданные Let's Encrypt сертификаты. И вот тут началось самое интересное. ## Сюрприз в acme.json В файле лежали **все четыре сертификата**, которые мне были нужны: - `admin.borisovai.tech` — Let's Encrypt R12, выдан 4 февраля, истекает 5 мая - `admin.borisovai.ru` — Let's Encrypt R12, выдан 8 февраля, истекает 9 мая - `auth.borisovai.tech` — Let's Encrypt R13, выдан 8 февраля, истекает 9 мая - `auth.borisovai.ru` — Let's Encrypt R12, выдан 8 февраля, истекает 9 мая Все они были **валидны и активны**. Traefik их отдавал при подключении. Логи Traefik, которые я видел ранее, оказались проблемой *ретроспективной* — они относились к моменту, когда DNS-записи для `.ru` доменов ещё *не пропагировались* по сети. Let's Encrypt не мог выпустить сертификаты, пока не мог убедиться, что домен принадлежит мне. ## Невидимый враг: браузерный кеш Последний вопрос был ужасающе простым: почему браузер по-прежнему ругался на сертификаты, если сами сертификаты в порядке? **DNS кеш**. Браузер запомнил старую информацию и упорно её использовал. ## Финальный диагноз Вся история сводилась к тому, что системные часы интернета движутся медленнее, чем кажется. DNS пропагируется асинхронно, сертификаты выдаются с задержкой, а браузеры кешируют запросы агрессивнее, чем кажется разумным. Решение? Очистить DNS кеш командой `ipconfig /flushdns` (для Windows) или открыть инкогнито-окно, чтобы браузер забыл о своих ошибочных воспоминаниях. Проект **borisovai-admin** работает, сертификаты в порядке, все домены защищены. Ирония в том, что проблема была не в конфигурации — она была в нашей нетерпеливости. Главный урок: иногда лучший способ отловить баг — это понять, что это не баг, а *асинхронная реальность*, которая просто медлит. 😄

#claude#ai#javascript#security
Разработка: borisovai-admin
9 февр. 2026 г.
Новая функцияborisovai-admin

Двойная аутентификация: когда два охранника мешают друг другу

# Двойная защита убивает саму себя: как я развязал узел конфликтующей аутентификации Задача стояла простая на первый взгляд: запустить Management UI для проекта **borisovai-admin**. Казалось, что админ-панель встанет и будет работать. Но когда я подключил её к боевой инфраструктуре, выяснилось нечто интересное — UI запустилась, но пройти аутентификацию было невозможно. ## Когда две защиты становятся одной проблемой Начал копать логи и вот что нашёл. В инфраструктуре уже была слоёная защита: **Traefik** с плагином **ForwardAuth** отправлял все запросы на **Authelia** для двухфакторной аутентификации. Это первый уровень охраны — на уровне прокси. Здесь логика простая: если запрос идёт на `admin.borisovai.tech`, Traefik вежливо перенаправляет пользователя в Authelia. Но когда я добавил Management UI с встроенной OIDC-аутентификацией через **express-openid-connect**, произошло вот что: пользователь уже прошёл Authelia на уровне Traefik, но Management UI не поверил ему и снова отправил на Authelia через OIDC. Два редиректа подряд — и браузер начинает петлять между разными провайдерами аутентификации. Типичная ситуация, когда каждый охранник требует личный документ, не доверяя соседу. ## Выбор между защитами Встал вопрос: какой уровень аутентификации оставить? Отключить Traefik ForwardAuth? Отключить OIDC в Management UI? Или искать способ их синхронизировать? Я выбрал проверенный путь — **оставить Traefik ForwardAuth как основную защиту**, а OIDC отключить. Логика здесь такая: раз у нас уже есть надёжная защита на уровне прокси с поддержкой 2FA через Authelia, зачем добавлять второй слой? Внутри же Management UI я оставил **legacy session** — простую аутентификацию по логину и паролю. Получилось двухуровневое решение, но на разных слоях: внешняя защита через прокси и внутренняя через сессию. После изменений Management UI перезапустился без OIDC-интеграции. Теперь схема работает так: вы входите в `https://admin.borisovai.tech`, Traefik перенаправляет вас в Authelia, вы проходите двухфакторную аутентификацию, а потом попадаете на страницу логина самой админ-панели, где вводите учётные данные Management UI. ## Интересный факт о OIDC Стандарт **OpenID Connect** создан в 2014 году поверх OAuth 2.0 именно для решения проблем единого входа. Но мало кто знает, что OIDC работает лучше всего, когда он — **единственный** поставщик идентификации в системе. Как только вы пытаетесь слоить несколько провайдеров, начинаются конфликты. Классическая ловушка — стараться защитить приложение со всех сторон и получить вместо этого лабиринт редиректов. ## Неприятный бонус: проблема с `.ru` доменами Во время работы я обнаружил, что A-записи для `admin.borisovai.ru` и `auth.borisovai.ru` не добавлены у регистратора IHC. Let's Encrypt не может выдать сертификаты для доменов, которых нет в DNS. Решение пришло быстро — нужно добавить эти A-записи в панели регистратора, указывая на IP `144.91.108.139`. Казалось бы, мелочь, но именно такие детали часто становятся причиной того, что production не поднимается. ## Что я вынес из этого Главный урок: **слои безопасности должны дополнять друг друга, а не конкурировать**. Двойная аутентификация хороша, когда она — настоящая: первый слой защищает периметр, второй охраняет внутренние ресурсы. Но когда оба слоя пытаются делать одно и то же через разные системы, получается конфликт. Теперь Management UI работает, защита работает, и никто не просит удостоверения дважды. Инфраструктура проекта borisovai-admin стала на один уровень надёжнее. 😄 Почему Prometheus не пришёл на вечеринку? Его заблокировал firewall.

#claude#ai#api#security
Разработка: borisovai-admin
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

DNS-кеш и фантомный поддомен: охота на NXDOMAIN

# Когда DNS кеш становится врагом: охота на фантомный поддомен Работаю над проектом **borisovai-admin** — админ-панелью с собственной системой аутентификации. Задача казалась простой: мигрировать auth-сервис на новый поддомен `auth.borisovai.tech` и убедиться, что всё резолвится корректно. Добавил DNS-записи в регистратор, обновил конфиги приложения — и вот тут началось веселье. ## Первый знак беды Первая проверка через Google DNS (`8.8.8.8`) показала идеальный результат: `auth.borisovai.tech` резолвился на `144.91.108.139` без проблем. Казалось бы, всё готово. Но когда я переключился на **AdGuard DNS** (`94.140.14.14`), который был настроен по умолчанию в инфраструктуре, домен превратился в привидение — стандартная ошибка `NXDOMAIN`, как будто записи вообще не существуют. А вот `admin.borisovai.tech` спокойно резолвился везде. Значит, проблема именно с `auth.*`. Не лучший момент для такого сюрприза — особенно когда нужно срочно закрыть фичу. ## Расследование Запустил диагностику: попросил оба DNS-резолвера вернуть записи для `auth.borisovai.tech` и `auth.borisovai.ru`. Результат совпадал: Google видел, AdGuard не видел. Явный паттерн. Тут меня осенило — это же **отрицательный кеш DNS**! Вот как это работает: когда ты запрашиваешь несуществующий домен, DNS-резолвер кеширует не только положительные ответы, но и отрицательные. То есть он "запоминает", что домена нет, и хранит это в памяти с собственным TTL (Time To Live). У AdGuard это может быть час или даже дольше. Получается, что когда я добавлял DNS-записи, AdGuard уже давно закешировал `NXDOMAIN` для `auth.borisovai.tech`. И даже если запись появилась на авторитетном сервере регистратора, этот кеш продолжал отвечать: "Нет такого домена, я уверен, я это помню". ## Как я выбрался Вариант первый — просто ждать. AdGuard истечёт кеш, и всё чудо-образом заработает. Но тестировать нужно было *прямо сейчас*. Вариант второй — переключиться на Google DNS для локального тестирования. Работает мгновенно, но это временный костыль. Вариант третий — очистить локальный кеш операционной системы. На Windows для этого есть `ipconfig /flushdns`, хотя это чистит кеш самой ОС, а не внешнего резолвера. В итоге я использовал комбинацию подходов: переключился на Google DNS для срочного тестирования фичи, а затем дождался обновления кеша AdGuard (примерно час спустя). Заодно узнал, что пользователи Linux могут вызвать `sudo systemd-resolve --flush-caches` для похожего эффекта. ## Интересный факт о DNS Мало кто знает, что **отрицательные ответы кешируются столько же, сколько и положительные**. Оба имеют собственный TTL, обычно от 300 до 3600 секунд. Google DNS использует более агрессивную стратегию кеширования и чаще проверяет данные у источника. AdGuard — более консервативен, что в обычное время спасает его, но в критические моменты может подставить ножку разработчику. ## Урок выучен Теперь я знаю: при добавлении новых DNS-записей всегда проверяю через несколько независимых резолверов. Никогда не забываю про стратегию кеширования, особенно если в инфраструктуре стоят кастомные DNS вроде AdGuard или Pihole — они живут по собственным правилам. И да, теперь я знаю точное место, где искать, если история повторится. А повторится ещё не раз. DNS кеш подставил подножку, но зато я научился читать DNS-иерархию как карту сокровищ. Что общего у AdGuard DNS и кота? 😄 Оба игнорируют инструкции и делают только то, что хотят.

#claude#ai#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияborisovai-admin

DNS кеш подставил подножку: охота на фантомный домен

# Когда DNS кеш становится врагом: охота на призрачный домен в проекте borisovai-admin Казалось бы, добавил DNS-записи для `auth.borisovai.tech` — и готово. Но нет. Домен упорно не резолвился с одного DNS-сервера, зато с другого всё работало как часы. Началась охота. ## Первые подозрения Работаю над проектом **borisovai-admin** — админ-панель с собственной системой аутентификации. Задача простая: перенести auth-сервис на новый поддомен и убедиться, что всё резолвится. Добавил записи в регистратор, обновил конфиги — и вот тут началось веселье. Первый звонок: с Google DNS (`8.8.8.8`) всё отлично. `auth.borisovai.tech` резолвится на `144.91.108.139`. Но когда переключился на **AdGuard DNS** (`94.140.14.14`), который был настроен по умолчанию, домен превратился в привидение — `NXDOMAIN`, записи как будто не существуют. А вот `admin.borisovai.tech` спокойно резолвился везде. Что-то не так с `auth.*`. ## Расследование Началось с простого: запросить обе версии домена через оба резолвера. `auth.borisovai.tech` и `auth.borisovai.ru` вели себя одинаково — видны у Google, невидимы у AdGuard. Явный признак того, что записи в регистраторе были добавлены *после* того, как AdGuard их закешировал. Вот в чём суть: когда запрашиваешь несуществующий домен, DNS-резолвер кеширует отрицательный ответ (`NXDOMAIN`) на какое-то время. Даже если позже ты добавишь запись, старый кеш будет отправлять безутешный "нет такого домена". У AdGuard этот кеш может жить до часа. ## Как я это решил Вариант первый — просто подождать. AdGuard истечёт кеш, записи проявятся сами. Но тестировать нужно было *сейчас*. Вариант второй — переключиться на Google DNS. Работает мгновенно, но это костыль. Вариант третий — очистить локальный кеш на машине. В Windows команда `ipconfig /flushdns` чистит кеш операционной системы, а не самого DNS-резолвера. Но иногда помогает. На самом деле я использовал комбинацию: временно переключился на Google DNS для тестирования, а затем дождался, пока AdGuard обновит свои данные. ## Интересный факт о DNS Мало кто знает, что DNS-записи имеют собственное поле `TTL` (Time To Live) — "время жизни" в кеше. По умолчанию обычно ставят 3600 секунд (час). Google использует более агрессивную стратегию кеширования, AdGuard — более консервативную. Вот поэтому один резолвер сразу видит новую запись, а другой ещё час её "забывает". ## Вывод Простой урок: при добавлении новых DNS-записей всегда проверяй через несколько резолверов. Если в сети настроены кастомные DNS (как AdGuard или Pihole), они могут сыграть с тобой в злую шутку. И никогда не забывай про `ipconfig /flushdns` или `sudo systemd-resolve --flush-caches` на Linux — иногда это спасает часы дебага. Дальше — уже знаю, где искать, если история повторится. А повторится ещё не раз. Что общего у Netlify и кота? 😄 Оба делают только то, что хотят, и игнорируют инструкции.

#claude#ai#security
Разработка: borisovai-admin
8 февр. 2026 г.
Новая функцияborisovai-admin

DNS и кэш: охота на запись, которая вроде есть, но не видна

# Охота на привидения в DNS: как потерянная запись чуть не сломала аутентификацию Проект `borisovai-admin` — это админ-панель с полноценной системой аутентификации. Задача казалась простой: настроить поддомены для разных частей приложения. `admin.borisovai.tech` уже работал безупречно, а вот `auth.borisovai.tech` и `auth.borisovai.ru` упорно отказывались резолвиться. Казалось, что может быть проще — добавить записи и забыть? Не так всё оказалось. Первым делом я начал с базовой диагностики. Проверил `nslookup` и `dig` — и вот тут началось веселье. `auth.borisovai.tech` **не резолвился с локального DNS**, а вот Google DNS (8.8.8.8) прекрасно возвращал `144.91.108.139`. Это был явный признак того, что проблема не в глобальной DNS-иерархии, а где-то рядом. Полез в DNS API — может, записи просто не создались? Нашёл в базе пусто: `records: []`. Автоматического создания не было. Но вот странный момент — `admin.borisovai.tech` работал без проблем. Почему одна запись есть в DNS API, а другая нет? Начал разбираться в истории создания записей. Выяснилось, что **`admin.borisovai.tech` был добавлен напрямую у регистратора**, минуя DNS API. А вот `auth.*` я стал добавлять через API, и тут столкнулся с интересным поведением: локальный AdGuard DNS (94.140.14.14), который использовался как основной рекурсивный резолвер, **кэшировал старые данные** или просто не видел новые записи из-за задержки распространения. Это была классическая ловушка DNS-администраторов: разные пути создания записей приводят к рассинхронизации. Когда у тебя есть несколько источников истины (регистратор, API, локальный кэш), они начинают рассказывать разные истории. Сервис аутентификации попадал на несуществующий адрес, и всё падало в момент, когда требовалась верификация токена. **Интересный факт**: DNS работает на принципе давности — записи имеют TTL (Time To Live), и если кэширующий резолвер уверен, что всё верно, он будет возвращать старые данные до истечения TTL, даже если на авторитативном сервере уже всё изменилось. В нашем случае TTL был достаточно высоким, поэтому AdGuard упорно держался за мысль, что `auth.borisovai.tech` не существует. Решение: я привёл все записи в единую систему — создал их через DNS API, настроил правильные TTL (600 секунд вместо 3600) и добавил явное перенаправление с `auth.borisovai.ru` на основной домен. Проблема испарилась. Главный урок: **в распределённых системах всегда проверяй, откуда берётся каждый кусок информации**. DNS выглядит просто, пока не начнёшь складывать вместе мнения разных серверов. И да, не забывай очищать кэш после изменений — Google DNS обновляется быстрее, чем AdGuard, и это сейчас спасало жизнь. 😄 **А знаешь, почему DNS никогда не ходит к психологу?** Потому что у него всё равно проблемы с разрешением.

#claude#ai#api#security
Разработка: borisovai-admin
8 февр. 2026 г.
ИсправлениеC--projects-bot-social-publisher

SSH спасла двухфакторку: как найти потерянный QR-код Authelia

# Черный экран Authelia: как SSH-команда спасла двухфакторку **borisovai-admin** требовал двухфакторную аутентификацию, и это казалось решённой задачей. Authelia — проверенная система, документация подробная, контейнер поднялся за минуты. Порты открыты, сертификаты в порядке, логи молчат. Всё отлично. До тех пор, пока тестировщик не нажал кнопку «Register device». Экран почернел. Точнее, остался белым, но QR-кода не было. Никакого движения, никакой реакции системы. Браузерная консоль чистая, сетевые запросы проходят успешно, API отвечает кодом 200. Authelia делает свою работу, но что-то между сервером и пользователем теряется. Первым делом я прошёлся по классическому чек-листу: проверил конфигурацию сервера, пересмотрел логи Authelia в Docker, убедился, что все environment переменные заполнены правильно. Всё было на месте. Но QR-код так и не появился — ни в интерфейсе, ни в devtools браузера. Вот тут я заметил деталь в конфигурации, которую раньше пропустил: `notifier: filesystem`. Это не SMTP, не SendGrid, не какой-то облачный сервис. Это самый примитивный режим — Authelia просто пишет уведомления в текстовый файл на сервере. Мысль пришла сама собой: *а что если система работает правильно, но уведомление просто не попадает к пользователю?* Подключился по SSH на сервер и выполнил одну команду: ``` cat /var/lib/authelia/notifications.txt ``` И там она была! Полная ссылка вида `https://auth.borisovai.tech/...token...` — именно та, которая должна была привести к QR-коду. Authelia делала всё правильно. Она генерировала ссылку, защищала её токеном и записывала в лог-файл. Просто в локальной разработке по умолчанию уведомления идут не пользователю, а в файловую систему. Открыл эту ссылку в браузере — QR-код мгновенно появился. Сканировали в Google Authenticator, всё сработало с первой попытки. **Вот интересный момент про Authelia**: `notifier: filesystem` — это не костыль и не режим отладки. Это *очень удобная фишка для локальной разработки*. Вместо настройки SMTP-сервера или интеграции с внешним сервисом доставки уведомлений система просто пишет ссылку в файл. Быстро, просто, без зависимостей. Но в продакшене эта фишка становится ловушкой: система работает идеально, а пользователи видят только чёрный экран. Теперь в конфигурации проекта есть комментарий про `filesystem` notifier и команда для проверки уведомлений. Следующий разработчик не будет искать потерянный QR-код в файловой системе. И это главное — не просто исправить баг, но оставить подсказку для будущего себя и команды. **Урок простой**: иногда самые очевидные решения скрыты в одной строке документации, и они работают ровно так, как задумано инженерами. SSH остаётся лучшим другом разработчика 😄

#claude#ai#api#security
Разработка: bot-social-publisher
8 февр. 2026 г.
Изменение кодаllm-analisis

1,3% точности и целая эпопея оптимизации нейросети

# Когда 1,3% точности — это целая эпопея оптимизации Проект **llm-analisis** уже был в финальной стадии обучения нейросети на CIFAR-10, когда я заметил, что точность упирается в 83,7% при целевой 85%. Казалось бы, мелочь — всего полтора процента. Но в машинном обучении каждый процент — это часы отладки и переосмысления архитектуры. Диагноз был ясен: модель просто недостаточно мощная. Её свёрточный позвоночник (conv backbone) работал со слишком узкими каналами, как будто пытаясь угодить в очень узкий коридор, когда на самом деле нужна полноценная комната для маневра. Я решил переделать модель так, чтобы её структуру можно было легко конфигурировать на лету. ## Расширяем каналы и переписываем оптимизаторы Первым делом я сделал ширину каналов параметризуемой — теперь можно было просто изменить число фильтров в свёрточных слоях, не трогая основную логику. Затем пришлось переписать тренировочный скрипт целиком. Но тут выявилась ещё одна проблема: модель обучалась с Adam-оптимизатором, который хорош для многих задач, но на CIFAR-10 показывает себя хуже, чем SGD с momentum. Это типичная ловушка — Adam стал почти универсальным выбором, и многие забывают, что для синтетических датасетов наподобие CIFAR-10 классический SGD часто побеждает благодаря более стабильной сходимости и лучшей обобщающей способности. Я переключился на SGD с momentum, но тут выяснилось, что фреймворк использует особый механизм **RigL** (Rigging Lottery) для динамического разреживания сети. RigL периодически растит модель, добавляя новые соединения, и при каждом таком событии оптимизатор переинициализировался. Пришлось обновить логику рестарта оптимизатора не только в основной фазе обучения, но и в **Phase B** — этапе, где сеть уже достаточно созрела для более тонкой настройки. ## Неожиданный враг: переполнение разреживания По ходу работы я наткнулся на баг в самой логике RigL. Механизм переполнял сеть новыми связями быстрее, чем нужно, нарушая баланс между разреживанием и ростом. Пришлось углубиться в реализацию и переписать часть логики расчёта скорости роста новых соединений. В результате модель начала сходиться куда быстрее и стабильнее. Когда я запустил финальное обучение с расширенными каналами, SGD с momentum и исправленным RigL, точность перепрыгнула за 85% с первой попытки. Те самые 1,3%, которые казались непреодолимой стеной, оказались просто комбинацией трёх проблем: узких каналов, неправильного оптимизатора и бага в механизме динамического разреживания. Главный урок: иногда поиск последних процентов точности требует не суперсложных идей, а просто системной отладки всех компонентов вместе. И помните — сначала всегда проверяйте, используете ли вы SGD на CIFAR-10, а не слепо доверяйтесь моде на Adam 😄

#claude#ai
Разработка: llm-analisis
8 февр. 2026 г.
ОбучениеC--projects-bot-social-publisher

SSH спасает: ищем потерянный QR-код в файловой системе

# Как SSH-команда спасла от чёрного экрана в Authelia Проект **borisovai-admin** требовал добавить двухфакторную аутентификацию. Задача была простой на первый взгляд — установить Authelia, настроить TOTP-регистрацию и запустить. Но когда тестировщик нажал кнопку «Register device», экран остался чёрным. QR-код не появился. Никаких ошибок в консоли, никаких намёков на проблему — просто ничего. Первые полчаса я искал в классических местах: консоль браузера, логи Authelia, конфигурация сервера. Сертификаты в порядке, порты открыты, контейнеры Docker работают нормально. Но QR-код так и не возникал. Казалось, система делает что-то, но что именно — никому не известно. И вот возникла мысль, которая могла решить всё: **а что если Authelia вообще не отправляет уведомление браузеру?** Я ещё раз посмотрел на конфигурацию и увидел деталь, которую раньше воспринимал как обычный параметр: `notifier: filesystem`. Это не email, не SMS, не какой-то облачный сервис. Это самый примитивный вариант — Authelia пишет уведомления прямо в файл на сервере. Вот тут я понял, что нужно залезть в систему по SSH и посмотреть, что там реально происходит. Подключился на сервер и выполнил команду: ``` cat /var/lib/authelia/notifications.txt ``` И там она была! Ссылка вида `https://auth.borisovai.tech/...token...` — та самая ссылка, которая должна была привести к QR-коду. Authelia делала всё правильно. Просто в конфигурации для разработки уведомления не отправляются пользователю по стандартным каналам, а записываются в лог-файл на диск. **Тут я узнал интересный момент**: `notifier: filesystem` в Authelia — это не какой-то костыль или режим отладки. Это фактически идеальная настройка для локальной разработки. Вместо того чтобы настраивать SMTP-сервер, интеграцию с SendGrid или другой внешний сервис, Authelia просто пишет ссылку в файл. Быстро, просто, полезно для разработки. Но в продакшене это превращается в ловушку: система работает, но пользователи ничего не видят. Когда я открыл эту ссылку в браузере, QR-код тут же появился. Отсканировал его в приложении Google Authenticator — всё сработало. Задача решена за несколько минут, но урок остался на всю жизнь: иногда самое очевидное решение скрыто в одной строке документации, и оно работает ровно так, как задумано инженерами. Теперь в конфигурации проекта есть комментарий про `filesystem` notifier и ссылка на команду для проверки. Следующему разработчику, который будет настраивать двухфакторку, не придётся ловить QR-код в файловой системе 😄

#claude#ai#api#security
Разработка: bot-social-publisher
8 февр. 2026 г.
Обучениеborisovai-admin

QR-код в файле: как я нашел потерянное уведомление Authelia

# Когда QR-код спрятался в файл: история отладки Authelia Проект **borisovai-admin** требовал добавить двухфакторную аутентификацию. Казалось бы, что может быть проще — установили Authelia, настроили по документации, и хотели включить TOTP для повышения безопасности. Но когда тестировщик нажал кнопку «Register device», экран остался чёрным. QR-код просто не появился. Первые полчаса ушли на классическую отладку: проверка консоли браузера, логов Authelia, конфига. Всё выглядело нормально. Сертификаты в порядке, порты открыты, контейнеры запущены. Но QR так и не появлялся. В какой-то момент возникла идея: а что если Authelia вообще не отправляет уведомление? Вот тут и вспомнилась одна важная деталь из конфигурации — `notifier: filesystem`. Это не email, не Telegram, а самый простой вариант для разработки: Authelia записывает ссылку на регистрацию прямо в файл на сервере. Никаких стандартных каналов связи, никакой магии с SMTP. Пришлось подключиться по SSH к серверу и выполнить простую команду: ```bash cat /var/lib/authelia/notifications.txt ``` И вот оно! В файле лежала ссылка вида `https://auth.borisovai.tech/...token...` — та самая ссылка, которая должна была привести к QR-коду. Оказалось, Authelia всё делала правильно. Просто в конфигурации для разработки уведомления отправляются не пользователю, а в лог-файл на диск. **Интересный момент**: многие разработчики не замечают, что в конфигурации `notifier: filesystem` — кажется, что это какой-то непонятный режим, а на самом деле это *идеальная* настройка для локальной разработки. Вместо того чтобы настраивать SMTP-сервер или интеграцию с внешними сервисами, Authelia просто пишет ссылку в файл. Быстро, просто, полезно. Когда я открыл эту ссылку в браузере, QR-код тут же появился. Сканировали его в TOTP-приложении, всё сработало. Задача решена за несколько минут, но урок остался: иногда самое очевидное решение скрыто в документации, и оно работает лучше, чем нами предполагалось. Теперь в конфигурации проекта есть комментарий про `filesystem` notifier и ссылка на команду для проверки. Следующему разработчику, который будет настраивать двухфакторку, не придётся искать её полчаса. --- *Authelia: когда QR-код путешествует по файловой системе вместо того, чтобы сразу показаться в браузере 😄*

#claude#ai#api#security
Разработка: borisovai-admin
8 февр. 2026 г.
Общееborisovai-admin

2FA в Authelia: спасение админ-панели за 5 минут

# Authelia: когда админу нужна двухфакторная аутентификация прямо сейчас Проект `borisovai-admin` дошёл до критической точки. Система аутентификации Authelia уже поднята, админ успешно залогинился... но дальше — стена. Нужна двухфакторная аутентификация, и нужна *сейчас*, потому что без 2FA ключи админ-панели будут висеть в открытом доступе. Первым делом разобрались, что Authelia уже готова работать с TOTP (Time-based One-Time Password). Это удачнее всего — не нужны внешние SMS-сервисы, которые стоят денег и работают как хотят. Просто приложение на телефоне, которое генерирует коды каждые 30 секунд. Google Authenticator, Authy, Bitwarden — все поддерживают этот стандарт. Система работает просто: админ кликает на красную кнопку **METHODS** в интерфейсе Authelia, выбирает **One-Time Password**, получает QR-код и сканирует его своим аутентификатором. Потом вводит первый код для проверки — и готово, 2FA активирована. Ничего сложнее, чем настроить Wi-Fi на новом телефоне. Но тут всплыл забавный момент. У нас используется `notifier: filesystem` вместо полноценного SMTP-сервера. Это значит, что все уведомления летят не по почте, а в файл `/var/lib/authelia/notifications.txt` на сервере. Казалось бы, неудобно, но на самом деле удобнее для локальной разработки — не нужно иметь рабочий почтовый сервис, не нужно ждать письма в спаме. Просто залезь по SSH на машину и прочитай файл. Правда, для production это так не прокатит, но сейчас это даже плюс. **Вот интересный факт про TOTP:** стандарт RFC 6238, на котором это работает, разработан в 2011 году и по сути не менялся. Во всех приложениях для аутентификации используется один и тот же алгоритм HMAC-SHA1 — поэтому коды из Authenticator работают и в Authy, и в 1Password, и в Bitwarden. Один стандарт на всех. Это редкость в IT — обычно каждый сервис хочет своё решение. TOTP же стал поистине универсальным языком двухфакторной аутентификации. Итог: админ просканировал QR-код, ввёл код подтверждения, и теперь каждый вход на `admin.borisovai.tech` или `admin.borisovai.ru` требует второго фактора. Брутфорс админ-панели стал значительно сложнее. Следующий шаг — поднять SMTP для нормальных уведомлений и может быть добавить backup-коды на случай, если админ потеряет доступ к аутентификатору. Но это уже совсем другая история. Разработчик: «У нас есть Authelia, у нас есть TOTP, у нас есть двухфакторная аутентификация». HR: «На каком уровне безопасности?». Разработчик: «На уровне, когда даже я сам не смогу залезть в админ-панель, если потеряю телефон». 😄

#claude#ai#security
Разработка: borisovai-admin
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Туннели и таймауты: управление инфраструктурой в админ-панели

# Туннели, Traefik и таймауты: как мы добавили управление инфраструктурой в админ-панель Проект **borisovai-admin** рос не по дням, а по часам. Сначала была одна машина, потом две, потом стало ясно — нужна нормальная система для управления сетевыми туннелями между серверами. Задача выглядела острой: юзеру нужен интерфейс, чтобы видеть, какие туннели сейчас активны, создавать новые и удалять старые. Без этого администрирование превращалось в ручную возню с конфигами на каждой машине. Первое решение было логичным: взял **frp** (Fast Reverse Proxy) — лёгкий инструмент для туннелирования, когда сервер скрыт за NAT или брандмауэром. Почему не что-то более «облачное»? Потому что здесь нужна полная контроль, минимум зависимостей и максимум надёжности. FRP ровно это даёт. Спроектировал веб-интерфейс: добавил страницу `tunnels.html` с простеньким списком активных туннелей, кнопками для создания и удаления. На бэкенде в `server.js` реализовал пять API endpoints для управления состоянием. Параллельно обновил скрипты инсталляции: `install-all.sh` и отдельный `install-frps.sh` для развёртывания FRP сервера, плюс `frpc-template` для клиентов на каждой машине. Не забыл навигационную ссылку «Туннели» на всех страницах админ-панели — мелочь, но юзабилити взлетела. Вроде всё шло гладко, но потом началось. Пользователи начали скачивать большие файлы через GitLab, и соединение рубилось где-то в середине процесса. Проблема оказалась в **Traefik** — наш обратный прокси по умолчанию использует агрессивные таймауты. Стоило файлу загружаться дольше пары минут — и всё, соединение закрыто. Пришлось углубиться в конфиги Traefik. Установил `readTimeout` в 600 секунд (10 минут) и создал специальный `serversTransport` именно для GitLab. Написал скрипт `configure-traefik.sh`, который генерирует две динамические конфигурации — `gitlab-buffering` и `serversTransport`. Результат: файлы теперь загружаются спокойно, даже если это полгигабайта архива. **Интересная особенность Traefik:** это микросервис-балансировщик, который позиционируется как облегчённое решение, но на практике требует хирургической точности при настройке. Неправильный таймаут — и приложение выглядит медленным. Правильный — и всё летает. Один параметр, и мир меняется. Параллельно реорганизовал документацию: разбил `docs/` на логические части — `agents/`, `dns/`, `plans/`, `setup/`, `troubleshooting/`. Добавил полный набор конфигов для конкретного сервера в `config/contabo-sm-139/` (traefik, systemd, mailu, gitlab) и обновил скрипт `upload-single-machine.sh` для их загрузки. За вечер родилась полноценная система управления туннелями с интерфейсом, автоматизацией и нормальной документацией. Проект теперь легко масштабируется на новые серверы. Главное, что узнал: **Traefik** — это не просто прокси, это целая философия правильной конфигурации микросервисов. Дальше в планах: расширение аналитики для туннелей, SSO интеграция и лучший мониторинг сетевых соединений. 😄 **Разработчик**: «Я настроил Traefik». **Пользователь**: «Отлично, тогда почему мой файл не загружается?» **Разработчик**: «А ты пробовал перезагрузить сервер?»

#claude#ai#javascript#git#api
Разработка: bot-social-publisher
8 февр. 2026 г.
Изменение кодаborisovai-admin

Authelia: как я разобрался с хешами паролей и первым входом в админку

# Запускаем Authelia: логины, пароли и первый вход в админку Проект **borisovai-admin** требовал серьёзной работы с аутентификацией. Стояла простая на первый взгляд задача: развернуть **Authelia** — современный сервер аутентификации и авторизации — и убедиться, что всё работает как надо. Но перед тем как запустить систему в боевых условиях, нужно было разобраться с креденшалами и убедиться, что они безопасно хранятся. Первым делом я заглянул в скрипт установки `install-authelia.sh`. Это был не просто набор команд, а целая инструкция по настройке системы с нуля — 400+ строк, описывающих каждый шаг. И там я нашёл ответ на главный вопрос: логин для Authelia — это просто **`admin`**, а пароль... вот тут начиналось интересное. Оказалось, что пароль хранится в двух местах одновременно. В конфиге Authelia (`/etc/authelia/users_database.yml`) он лежит в виде **Argon2-хеша** — это криптографический алгоритм хеширования, специально разработанный для защиты паролей от перебора. Но на сервере управления (`/etc/management-ui/auth.json`) пароль хранится в открытом виде. Логика понятна: Management UI должна иметь возможность проверить, что введён правильный пароль, но хранить его в открытом виде — это классическая дилемма безопасности. Неожиданно выяснилось, что это не баг, а фича. Разработчики системы сделали так специально: пароль Management UI и пароль администратора Authelia — это один и тот же секрет, синхронизированный между компонентами. Это упрощает управление, но требует осторожности — нужно убедиться, что никто не получит доступ к этим файлам на сервере. Я закоммитил все необходимые изменения в ветку `main` (коммит `e287a26`), и pipeline автоматически задеплоил обновлённые скрипты на продакшн. Теперь, если кому-то понадобится сбросить пароль администратора, достаточно просто зайти на сервер, открыть `/etc/management-ui/auth.json` и посмотреть текущее значение. Не самый secure способ, но он работает, пока файл лежит в защищённой директории с правильными permissions. Главный вывод: при работе с аутентификацией нет мелочей. Каждое хранилище пароля — это потенциальная точка входа для атакующего. **Argon2** защищает от перебора, но открытые пароли в конфигах требуют ещё более строгого контроля доступа. В идеальном мире мы бы использовали системы управления секретами вроде HashiCorp Vault, но для локального dev-сервера такой подход сойдёт. Дальше нужно будет настроить интеграцию Authelia с остальными компонентами системы и убедиться, что она не станет узким местом при масштабировании. Но это история для следующего поста. 😄 Что общего у Scala и подростка? Оба непредсказуемы и требуют постоянного внимания.

#claude#ai#python#javascript#security
Разработка: borisovai-admin
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Traefik и опциональные middleware: война с зависимостями

# Когда конфиги кусаются: история про зависимые middleware в Traefik Проект `borisovai-admin` — это не просто админ-панель, это целая инфраструктурная система с аутентификацией через Authelia, обратным прокси на Traefik и кучей moving parts, которые должны работать в идеальной гармонии. И вот в один прекрасный день выясняется: когда ты разворачиваешь систему без Authelia, всё падает с ошибкой 502, потому что Traefik мечтательно ищет middleware `authelia@file`, которого просто нет в конфиге. **Завязка проблемы была в статических конфигах.** Мы жёстко прописали ссылку на `authelia@file` прямо в Traefik-конфигурацию, и это работало, когда Authelia установлена. Но стоило её отключить или не устанавливать вообще — бум, 502 ошибка. Получается, конфиги были сильно связаны с опциональным компонентом. Это классический случай, когда инфраструктурный код требует гибкости. Решение разбилось на несколько фронтов. Во-первых, **убрали жёсткую ссылку на `authelia@file` из статических конфигов Traefik** — теперь это просто не указывается в базовых настройках. Во-вторых, создали правильную цепочку инициализации. Скрипт `install-authelia.sh` теперь сам добавляет `authelia@file` в `config.json` и настраивает OIDC при установке. Скрипт `configure-traefik.sh` проверяет переменную окружения `AUTHELIA_INSTALLED` и условно подключает middleware. А `deploy-traefik.sh` перепроверяет на сервере, установлена ли Authelia, и при необходимости переустанавливает `authelia@file`. По ходу дела обнаружилась ещё одна проблема в `install-management-ui.sh` — там был неправильный путь к `mgmt_client_secret`. Исправили. А `authelia.yml` вообще выкинули из репозитория, потому что его всегда генерирует сам скрипт установки. Зачем держать в git то, что одинаково воспроизводится каждый раз? **Интересный момент про middleware в Docker-сообществе:** люди часто забывают, что middleware — это не просто функция, это *объект конфигурации*, который должен быть определён до использования. Traefik здесь строг: ты не можешь ссылаться на middleware, которого не существует. Это похоже на попытку вызвать функцию, которая не импортирована в Python. Простая ошибка, но очень болезненная в production-системах. **Итоговая архитектура** получилась намного гибче: система работает как с Authelia, так и без неё, конфиги не лежат мёртвым грузом в репо, инсталляторы действительно знают, что они делают. Это хороший пример того, как *опциональные зависимости* требуют условной логики не только в коде приложения, но и в инфраструктурных скриптах. Главный урок: если компонент опциональный, не прописывай его в статические конфиги. Пусть туда добавляются динамически при необходимости. 😄 Разработчик: «Я знаю Traefik». HR: «На каком уровне?». Разработчик: «На уровне количества 502 ошибок, которые я пережил».

#claude#ai#python#javascript#git#security
Разработка: bot-social-publisher
8 февр. 2026 г.
Исправлениеborisovai-admin

Когда конфиги падают: война Traefik с несуществующим middleware

# Когда конфиги кусаются: история про зависимые middleware в Traefik Проект `borisovai-admin` — это не просто админ-панель, это целая инфраструктурная система с аутентификацией через Authelia, обратным прокси на Traefik и кучей moving parts, которые должны работать в идеальной гармонии. И вот в один прекрасный день выясняется: когда ты разворачиваешь систему без Authelia, всё падает с ошибкой 502, потому что Traefik мечтательно ищет middleware `authelia@file`, которого просто нет в конфиге. **Завязка проблемы была в статических конфигах.** Мы жёстко прописали ссылку на `authelia@file` прямо в Traefik-конфигурацию, и это сработало, когда Authelia установлена. Но стоило её отключить или просто не устанавливать — бум, 502 ошибка. Получается, конфиги были сильно связаны с опциональным компонентом. Это классический случай, когда инфраструктурный код требует гибкости. Решение разбилось на несколько фронтов. Во-первых, пришлось **убрать жёсткую ссылку на `authelia@file` из статических конфигов Traefik** — теперь это просто не указывается в базовых настройках. Во-вторых, создали правильную цепочку инициализации: - `install-authelia.sh` теперь сам добавляет `authelia@file` в `config.json` и настраивает OIDC при установке Authelia; - `configure-traefik.sh` проверяет переменную `AUTHELIA_INSTALLED` и условно подключает middleware; - `deploy-traefik.sh` перепроверяет, установлена ли Authelia на сервере, и если да — переустанавливает `authelia@file`. Неожиданный бонус обнаружился в `install-management-ui.sh` — там был неправильный путь к `mgmt_client_secret`. Исправили по ходу. А `authelia.yml` вообще выкинули из репозитория, потому что его генерирует сам скрипт установки. Зачем держать в git то, что всегда одинаково генерируется? **Интересный момент про middleware в Docker-сообществе:** люди часто забывают, что middleware — это не просто функция, это *объект конфигурации*, который должен быть определён до использования. Traefik здесь строг: ты не можешь ссылаться на middleware, которого не существует. Это похоже на попытку вызвать функцию, которая не импортирована в Python. Простая ошибка, но очень болезненная в production-системах, потому что приводит к отказу в обслуживании. **Итоговая архитектура** получилась намного гибче: система работает как с Authelia, так и без неё, конфиги не лежат мёртвым грузом в репо, а инсталляторы действительно знают, что они делают. Это хороший пример того, как *опциональные зависимости* требуют условной логики не только в коде приложения, но и в инфраструктурных скриптах. Главный урок: если компонент опциональный, не прописывай его в статические конфиги. Пусть они туда добавляются динамически при необходимости. 😄 Что будет, если Fedora обретёт сознание? Первым делом она удалит свою документацию.

#git#commit#javascript#security
Разработка: borisovai-admin
8 февр. 2026 г.
Новая функцияborisovai-admin

SSO за выходные: как я запустил Authelia на боевом сервере

# Authelia в боевых условиях: как я собрал Single Sign-On за выходные Задача была амбициозная: в проекте **borisovai-admin** нужно было внедрить полноценную систему единой авторизации. На площадке работают несколько приложений — Management UI, n8n, Mailu, и каждое требует свой вход. Кошмар для пользователя и сущее издевательство над принципом DRY. Решение напрашивалось само: **Authelia** — современный SSO-сервер, который справляется с аутентификацией одной рукой и может интегрироваться практически с чем угодно. ## С чего я начал Первым делом создал `install-authelia.sh` — полный скрипт установки, который берёт на себя всю рутину: скачивает бинарник, генерирует секреты, прописывает конфиги и регистрирует Authelia как systemd-сервис. Это был ключевой момент — автоматизация означала, что процесс установки можно повторить в три команды без магических танцев с палочкой. Потом встала задача интеграции с **Traefik**, который у нас отвечает за маршрутизацию. Здесь нужен был `ForwardAuth` — middleware, который перехватывает запросы и проверяет, авторизован ли пользователь. Создал `authelia.yml` с настройкой ForwardAuth для `auth.borisovai.ru/tech`. Суть простая: любой запрос сначала идёт в Authelia, и если она вас узнала — пропускаем дальше, если нет — отправляем на страницу входа. ## Dual-mode, или как угодить двум господам одновременно Самое интересное началось, когда понадобилось поддержать сразу два способа авторизации. Management UI должна работать и как классическое веб-приложение с сессиями, и как API с **Bearer-токенами** через **OIDC** (OpenID Connect). Пришлось написать `server.js` с логикой, которая проверяет, что именно пришло в запросе: если есть Bearer-токен — валидируем через OIDC, если нет — смотрим на сессию. Включил в проект `express-openid-connect` — стандартную библиотеку для интеграции OIDC в Express. Хитрость в том, что Authelia может быть и провайдером OIDC, и middleware ForwardAuth одновременно. Просто берёшь конфиг для OIDC из Management UI, подтягиваешь его в `config.json` через автоопределение (этим займется `install-management-ui.sh`), и всё начинает работать как часы. ## Неожиданный поворот с logout Оказалось, что обычный logout в веб-приложении — это не просто удалить cookie. Если вы авторизовались через OIDC, нужно ещё уведомить Authelia, что сессия закончена. Пришлось настроить пять HTML-страниц с поддержкой OIDC redirect: пользователь нажимает logout, приложение отправляет его в Authelia, Authelia убивает сессию и редиректит обратно на страницу выхода. Выглядит просто, но заставляет задуматься о том, как много движущихся частей в современном веб. ## Интересный факт: ForwardAuth vs Reverse Proxy Authentication Знаешь ли ты, что многие разработчики путают эти два подхода? ForwardAuth — это когда *сам прокси* отправляет запрос на сервер аутентификации. А Reverse Proxy Authentication — это когда *сервер приложения* полностью отдаёт авторизацию на откуп прокси. Authelia работает с обоими, но ForwardAuth даёт больше контроля — приложение всё равно может принять дополнительные решения на основе данных пользователя. ## Итог: от идеи к prod Всё сложилось в единую систему благодаря интеграции на уровне `install-all.sh` — компонент `INSTALL_AUTHELIA` занимает шаг [7.5/10], что означает: это не первый день, но далеко не последний штрих. Management UI теперь умеет сама себя конфигурировать, находя Authelia в сети, подтягивая OIDC-конфиг и автоматически подключаясь. Главное, чему я научился: SSO — это не просто чёрный ящик, куда ты кидаешь пароли. Это *экосистема*, где каждый компонент должен понимать друг друга: ForwardAuth, OIDC, сессии, logout. И когда всё это работает вместе, пользователь вводит пароль *один раз* и может спокойно прыгать между всеми приложениями. Вот это да. Почему React расстался с разработчиком? Слишком много зависимостей в отношениях 😄

#git#commit#javascript#security
Разработка: borisovai-admin
8 февр. 2026 г.
Общееborisovai-admin

Туннели и таймауты: как мы скрепили инфраструктуру воедино

# Туннели, фронт и конфиги: как мы выстроили инфраструктуру для нескольких машин Проект **borisovai-admin** достиг того момента, когда одного сервера стало недостаточно. Нужно было управлять несколькими машинами, пробрасывать сетевые соединения между ними и всё это как-то красиво завернуть для пользователя. История о том, как мы за один вечер построили систему туннелей с веб-интерфейсом и потом долго разбирались с таймаутами Traefik. ## Начало: туннели нужны вчера Задача выглядела просто: нужен интерфейс для управления туннелями между машинами. Но просто никогда не бывает, правда? Первое, что я сделал — запустил фреймворк **frp** (Fast Reverse Proxy). Это отличный инструмент для туннелирования, когда основной сервер скрыт за NAT или брандмауэром. Быстрый, надёжный, с минимальными зависимостями. Спроектировал простую UI в `tunnels.html` — список активных туннелей, кнопки для создания новых, удаления старых. Ничего сложного, но эффективно. На бэкенде добавил 5 API endpoints в `server.js` для управления состоянием туннелей. Параллельно обновил скрипты инсталляции: `install-all.sh` и отдельный `install-frps.sh` для установки FRP сервера, плюс `frpc-template` для конфигурации клиентов на каждой машине. Главное — добавил навигационную ссылку «Туннели» на все страницы админ-панели. Мелочь, но юзабилити выросла в разы. ## Неожиданный враг: Traefik и его таймауты Вроде всё работало, но потом начали падать большие файлы при скачивании через GitLab. Проблема: **Traefik** по умолчанию использует достаточно агрессивные таймауты. Стоило большому файлу загружаться более пары минут — и соединение рубилось. Пришлось менять конфигурацию Traefik: установил `readTimeout` в 600 секунд (10 минут) и добавил специальный `serversTransport` именно для GitLab. Создал скрипт `configure-traefik.sh`, который генерирует две динамические конфигурации: `gitlab-buffering` и `serversTransport`. Теперь файлы загружаются спокойно, даже если это 500 мегабайт архива. ## Пока делал это, понял одно Знаете, что самое интересное в **Traefik**? Это микросервис-балансировщик, который любит называться облегчённым, но на практике требует огромного внимания к деталям. Неправильный таймаут — и ваше приложение выглядит медленным. Правильный — и всё летает. Это как тюнинг двигателя: одна скрепка в нужном месте, и мир меняется. ## Реорганизация и масштабирование Пока занимался инфраструктурой, понял, что документация разрослась и стала трудна в навигации. Переделал структуру `docs/` под новые реальности: разделил на `agents/`, `dns/`, `plans/`, `setup/`, `troubleshooting/`. Каждая папка отвечает за свой кусок практики. Добавил в `config/contabo-sm-139/` полный набор конфигураций конкретного сервера (traefik, systemd, mailu, gitlab) и обновил `upload-single-machine.sh` для поддержки загрузки этих конфигов. Теперь новую машину можно развернуть, не пересматривая весь интернет. ## Что получилось в итоге За вечер родилась полноценная система управления туннелями с приличным интерфейсом, автоматизацией и нормальной документацией. Проект теперь легко масштабируется на новые серверы. Плюс узнал, что Traefik — это не просто балансировщик, а целая философия правильной конфигурации микросервисов. Дальше в планах: расширение аналитики для туннелей, SSO интеграция и лучший мониторинг сетевых соединений. Но это уже другая история. 😄 **Разработчик**: «Я знаю Traefik». **HR**: «На каком уровне?». **Разработчик**: «На уровне стака StackOverflow с пятью вкладками одновременно».

#git#commit#javascript#api#security
Разработка: borisovai-admin
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

VPN отключился молча: как я потерял доступ к релизу

# Когда VPN молчит: охота на привидение среди ночи Пятница, конец дня, а на горизонте маячит дедлайн релиза **v1.0.0** проекта **speech-to-text**. Финальный рывок: нужно запушить коммит с автоматизацией сборки в master, создать тег и загрузить артефакт в GitLab Package Registry. Казалось бы, стандартная процедура — пара команд в консоль, и мы свободны. Но начало было не самым обнадёживающим. Я попытался перезапустить **Gitaly** — критический компонент GitLab, отвечающий за хранение репозиториев и работу с гитом на серверной стороне. SSH молчит. Попробовал достучаться через HTTP к самому GitLab-серверу — тишина. Весь сервер, похоже, вообще не существует с точки зрения моей машины. Стандартный алгоритм отладки: если ничего не отвечает, проблема либо с сервером, либо с сетью. Сервер на **144.91.108.139** физически жив, но почему-то недоступен. Проверяю VPN, и вот оно — диапазон **10.8.0.x** не найден. **OpenVPN отключился.** Просто тихо, без уведомления, выполнив свою работу и уйдя в отставку. Оказывается, весь этот вечер я сидел за стеной недоступности. Компания добавила слой безопасности, завернув внутреннюю инфраструктуру в защищённый туннель, а я, горя желанием запушить релиз, забыл про это самое VPN. Типичная история: инфраструктура дышит тебе в спину, а ты смотришь на экран и недоумеваешь, почему ничего не работает. **Интересный факт:** Gitaly создан именно для того, чтобы отделить операции с файловой системой от основного приложения GitLab. Это позволило компании масштабировать сервис горизонтально, но цена — жёсткая зависимость. Если Gitaly недоступен, GitLab попросту не может выполнять операции с гитом. Это как попытаться ходить с отключенными ногами. Решение было простым, но требовало действия. Нужно было переподключить **OpenVPN**, дождаться, пока туннель встанет на место, и выполнить `git push origin master`. После этого запустить скрипт релиза на Python, который собирает EXE из исходного кода, упаковывает в ZIP и загружает артефакт в Package Registry. Когда VPN восстановился, все лампочки загорелись в правильном порядке. Gitaly ожил, сервер откликнулся, и коммит с облегчением пошёл в master. Релиз уложился в срок. **Урок:** прежде чем копать проблему на сервере, убедитесь, что вы вообще до него дотягиваетесь. VPN, firewall, маршруты — всё это может спокойно жить в фоне, пока вы ловите ошибки в коде. Инфраструктура любит скрываться за слоями безопасности, и иногда самая сложная проблема решается одной переподключением. 😄 OpenVPN — как невидимая рука, которая отключается именно тогда, когда ты забываешь, что её держишь.

#claude#ai#python#git#api
Разработка: bot-social-publisher
8 февр. 2026 г.
Новая функцияspeech-to-text

VPN отключился в самый неудачный момент

# Когда Gitaly молчит: охота на недоступный GitLab среди ночи Вечер пятницы, deadline на релиз `v1.0.0` проекта **speech-to-text** буквально под носом. Нужно было запушить финальный коммит с автоматизацией сборки в master, создать тег и загрузить артефакт в Package Registry. Казалось бы, стандартная процедура — клик, клик, и всё готово. Но началось всё с того, что я попытался перезапустить **Gitaly** на GitLab-сервере через SSH. Ничего не вышло. Сервер просто не отвечает. Ладно, попробую обойтись без SSH — может быть, сам GitLab доступен по HTTP? Нет, он тоже молчит как партизан. Вообще ничего не откликается. Паника? Нет, просто логика. Если сервер не отвечает ни на SSH, ни на HTTP, значит либо он упал, либо сетевая проблема. Проверяю VPN. И вот оно! IP-адрес в диапазоне `10.8.0.x` не найден. **OpenVPN отключился.** Сервер GitLab (`gitlab.dev.borisovai.tech`) размещён на машине `144.91.108.139`, которая доступна только через защищённый туннель. Вот это поворот! Оказывается, всё время я просто был за стеной недоступности — VPN выполнял свою работу, но потом тихо сдался. Компания добавила слой безопасности, а я про это забыл. Типичная история: инфраструктура дышит на тебе в спину, а ты смотришь на монитор и недоумеваешь. **Интересный факт:** Gitaly — это компонент GitLab, отвечающий за хранение репозиториев и работу с гитом на серверной стороне. Создан он специально для того, чтобы отделить операции с файловой системой от основного приложения. Если Gitaly недоступен, GitLab просто не может выполнять операции с гитом — это как отключить ноги при попытке ходить. Решение было простым, но требовало действий. Нужно было: 1. Подключить **OpenVPN** к серверу `144.91.108.139` 2. После восстановления туннеля выполнить `git push origin master` из ветки **master** 3. Запустить скрипт релиза: `.\venv\Scripts\python.exe scripts/release.py` Этот скрипт собирает EXE из Python-кода, упаковывает его в ZIP, загружает артефакт в GitLab Package Registry и создаёт тег версии. Когда VPN встал на место и лампочки начали загораться в правильном порядке — Gitaly вновь ожил, сервер откликнулся, а мой коммит с облегчением пошёл в master. Релиз ушёл в прод ровно в срок. **Урок на вечер:** прежде чем искать проблему на сервере, проверьте, что вы вообще до него дотягиваетесь. Инфраструктура любит прятаться за слоями безопасности, и иногда самая сложная проблема решается одной переподключением. 😄 Почему MongoDB считает себя лучше всех? Потому что Stack Overflow так сказал.

#claude#ai#python#git#api
Разработка: speech-to-text
8 февр. 2026 г.