SSL, домени і крони: три фічі, кожна з яких виявилась не тим, чим здавалась

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Мене звати Валентин, я розробник, і останні пів року у вільний час ми вдвох з напарником робимо uptime-моніторинг. Це стаття про три фічі, кожна з яких на папері виглядала як дрібниця, а на практиці виявилась не тим, чим здавалась, і про граблі, які ми на цьому зібрали. Має бути корисно тим, хто робить власний продукт у вільний час, і тим, кому просто цікаво, як моніторинг влаштований зсередини.

Перші два місяці я був упевнений, що знаю, як влаштована ця робота: пінгуєш URL, дивишся що прийшло, алертиш якщо не те.

Потім ми додали три речі поспіль. Перевірку SSL-сертифікатів, перевірку строку реєстрації домену і heartbeat для кронів. На папері кожна виглядала як варіація того самого пінгу.

Жодна нею не виявилась. SSL взагалі не робиться через fetch(). З доменами проблема виявилась не в протоколі, а в тому, як часто їх смикати. А heartbeat узагалі працює у зворотний бік: там стукаємо не ми.

Що це і хто ми

Uptime-моніторинг, називається Dumza. Посилання не даю, стаття не про це. Щоб був зрозумілий масштаб: зараз 13 зареєстрованих, 12 моніторів під перевіркою, 0 платних. Інфра: Hetzner під воркер, Supabase під базу, Vercel під фронт, Resend під пошту, разом 45$ на місяць. Прод з червня, до цього приблизно стільки ж розробки у вільний час.

Нас двоє. Я роблю код та інфраструктуру, напарник — конкурентів, ринок, аналітику. Щоб це не звучало як «а він займається стратегією»: список типів моніторів, які ми додали після HTTP, зібраний з його розбору трьох найближчих конкурентів, а не з моєї інтуїції. Я б робив в іншому порядку і майже напевно зробив би не те.

Ринок при цьому не порожній, і я не вдаватиму, що ми побачили в ньому дірку. UptimeRobot, Better Stack, Pingdom, StatusCake, Healthchecks.io, і це тільки перша сторінка гугла.

Стек, якщо цікаво: монорепо на Turborepo поверх yarn workspaces, Next.js на фронті й API-роутах, окремий Bun-процес під воркер з BullMQ, Postgres через Prisma, спільний для обох. Ping-движок винесений в окремий пакет, щоб той самий код перевірки викликався і воркером по розкладу, і кнопкою Check Now з дашборду.

SSL, або навіщо вимикати валідацію

Найбільше часу з’їв саме він, і причина досить безглузда: через звичайний fetch() сертифікат не подивишся взагалі. Він не віддасть ані дату закінчення, ані видавця, ані ланцюг. Тільки факт, що з’єднання або вдалось, або ні.

Тобто йдеш у сирий tls.connect(), піднімаєш сокет руками і читаєш сертифікат прямо з нього. Це нормально, це десяток рядків. Неочевидне починається далі: валідацію ланцюга треба свідомо вимкнути, rejectUnauthorized: false. Виглядає як діра в безпеці рівно до того моменту, поки не подумаєш, для чого взагалі існує моніторинг сертифікатів.

А існує він саме для тих сертифікатів, які невалідні. Протермінований, самопідписаний, виданий на інший хостнейм. Якщо валідація увімкнена, хендшейк обривається саме на них, і ти дізнаєшся рівно нічого, крім того, що з’єднання не вдалось. Жодної деталі, яку треба показати користувачу. Для цієї конкретної задачі валідація не просто зайва, вона робить фічу неможливою.

Окремо довелось повозитись з порогом попередження. Фіксовані 14 днів, як роблять майже всі, не працюють: у Let’s Encrypt сертифікат живе 90 днів, у корпоративного клієнта рік. Для першого 14 днів це вже пізно, для другого параноя. Зараз рахуємо третину від строку життя конкретного сертифіката, з мінімумом у три дні.

І ще одна дрібниця, яка коштувала окремого багу. Позначку «коли ми востаннє дивились на цей сертифікат» треба ставити і тоді, коли хендшейк не вдався. Інакше хост, який зараз лежить, потрапляє під перевірку кожного проходу замість раз на добу — тобто рівно той, кому і так погано, отримує від нас найбільше навантаження. Самі дати при невдачі при цьому не чіпаємо, щоб одна мережева помилка не стерла останнє відоме вікно валідності.

Домени і частота перевірок

Історія та сама, тільки нудніша. RDAP замість WHOIS, бо WHOIS це вільний текст без схеми, і парсити його між сотнями реєстраторів я не збирався. Пробував півдня, кинув. RDAP віддає нормальний JSON, а мапа «TLD → сервер» тягнеться з бутстрап-файлу IANA і кешується.

Єдине, що там реально цікаво, це частота. Сертифікат живе місяцями, домен роками. Перевіряти домен щодня так само, як сертифікат, означає спалювати запити ні на що, до того ж у зовнішній протокол з рейт-лімітами і без жодних гарантій аптайму.

Зараз так: якщо до кінця реєстрації більше пів року, ми домен не чіпаємо взагалі, поки він не увійде у вікно. Виняток один. Домен, про який ми ще нічого не знаємо, перевіряється завжди, інакше він ніколи не зійдеться до відомої дати. На це я витратив зайвий вечір, бо перша версія логіки чесно пропускала всі нові домени і мовчала.

Heartbeat

Тут механіка взагалі інша. Не ми стукаємо в клієнтський URL, а клієнтський крон стукає в наш після кожного успішного запуску. Не прийшов у вікно, значить джоб або впав, або не стартував. Класичний dead man’s switch, той самий підхід, що в Healthchecks.io, нічого нового ми тут не вигадали.

Але саме воно закриває кейс, який звичайний uptime не бачить у принципі. Бекап, який тихо перестав робитись три тижні тому. Жоден ендпоінт не впав, дашборд зелений, бекапів немає.

Технічно найважливіше рішення там таке: ендпоінт, у який стукає клієнт, не робить нічого, крім одного UPDATE. Він не рахує дедлайни, не вирішує «спізнився чи ні», не чіпає чергу алертів. Обидва переходи, і «пропустив», і «повернувся», вирішує окремий фоновий прохід раз на хвилину. Спокуса зробити все прямо в ендпоінті велика, бо так на вигляд простіше. Але це найгарячіша ручка сервісу, в неї стукають тисячі кронів, і вона має лишатись однією операцією.

Другий момент там менш очевидний. setInterval не чекає, поки завершиться попередній прохід. Якщо прохід із якоїсь причини затягнувся довше за хвилину, наступний стартує поверх нього і побачить рівно ті самі прострочені чеки. Фільтра у вибірці для цього недостатньо — він робить обробку унікальною всередині одного проходу, але не між двома. Тому кожен перехід спочатку «забирається» умовним апдейтом, і алерт ставиться в чергу тільки якщо цей апдейт зачепив рядок. Виглядає як зайва обережність рівно до першого разу, коли клієнту прилетить два однакові листи про один пропущений крон.

Граблі

Один клієнтський монітор почав сипати 403. Спершу думав, що в нас щось з редіректами. Виявилось, Cloudflare Bot Fight Mode чесно записав наш User-Agent у підозрілі, бо він не браузерний, і це загалом правильна поведінка з їхнього боку.

Зробили евристику: якщо перевірка падає саме з 403 або 429, а не з таймауту чи 5xx, власнику монітора йде окремий лист з поясненням, що це схоже на бот-захист, а не на падіння сервісу, і як додати нас у whitelist. Таймаут і 5xx під це свідомо не підпадають, там справді швидше за все ліг сервер, і збивати людину з пантелику не треба.

Смішне сталось за тиждень після викочування. Я збирав дані для сторінки порівняння з Pingdom, зайшов до них на прайсинг і отримав 403. Їхній WAF вирішив, що я бот. Рівно той кейс, під який ми щойно зробили фічу, тільки з іншого боку барикади.

Була ще історія з egress на Supabase, яка виявилась ніякою. Побачив ріст трафіку за два тижні і півдня шукав запит у циклі. Розібрав графік по днях, знайшов два сплески, обидва день у день збігаються з нашим же ручним тестуванням на проді. Витоку не було.

А от що не «ніяка», це стеля бази. Сирі пінги ми зараз тримаємо 30 днів для всіх, включно з безкоштовним тарифом. Тридцять активних безкоштовних юзерів по 10 моніторів з інтервалом 5 хвилин — і ми в стелю впираємось. Питання не «чи», а «коли». Правильна відповідь очевидна: менший ретеншен на free, агрегати замість сирих рядків глибше. Не викочено, висить.

Про ШІ, чесно

Не вдаватиму, що пишу все руками. Більшість продуктивного коду за останній рік з агентом.

Писати я тепер майже не встигаю, час пішов у рев’ю і тестування. Точну пропорцію не рахував, але за відчуттям вона перевернулась десь за рік. Відповідаю за результат усе одно я, тож це не «ШІ пише мій продукт», це просто інша частина тієї самої роботи.

Що реально дратує: агент пише правдоподібно. Код компілюється, тести зелені, змінні названі як треба. І я ловлю себе на тому, що такий код читаю по діагоналі, бо він виглядає нормально. Криво написаний перевіряю уважніше, хоча мало б бути навпаки.

Три фічі вище, до речі, непогана ілюстрація. Агент без питань згенерував би SSL-перевірку з увімкненою валідацією і фіксованим порогом у 14 днів. Воно б скомпілювалось і пройшло тести, і мовчки не працювало саме на тих сертифікатах, заради яких ця перевірка існує.

Де ми програємо

Безкоштовний тариф у нас менший, ніж у UptimeRobot, 10 моніторів проти їхніх 50, і я поки не бачу, як ми цю цифру наздоженемо. Мультирегіональних перевірок немає: фундамент закладений, у проді немає, тож якщо треба підтвердження падіння з трьох континентів, ми не той інструмент. Мобільного застосунку теж немає. Продукту пів року, у конкурентів роки і значно довший список інтеграцій.

SMS не робимо і не плануємо. Кредит-паки і ціна за повідомлення, яка залежить від країни, це рівно та модель, через яку я взагалі почав дивитись на цей ринок. Замість цього Telegram, на телефоні виглядає так само, а коштує нуль.

Що є натомість. Фіксована ціна без per-seat і без пакетів. Імпорт з Uptime Kuma безкоштовний на всіх тарифах, включно з нульовим, бо брати гроші за міграцію мені здається дивним. Kuma при цьому чудова, я не буду вдавати інше, у неї просто є одна структурна проблема: вона живе на тому ж сервері, який моніторить, і вмирає разом з ним. І підтримка українською, від мене особисто, не через тікет-систему і не через бота. Наскільки все це разом взагалі перевага, питання відкрите, ми теж поки не знаємо.

Не проситиму реєструватись. Мені цікавіше інше: чим ви моніторите свої сервіси і що там реально бісить?

Особливо цікаві кейси, які звичайний uptime не покриває. Heartbeat у нас з’явився рівно з такої історії, і я підозрюю, що там є ще.

👍ПодобаєтьсяСподобалось5
До обраногоВ обраному1
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Я юзав статускейк 6 років, бо там було до 100 безкоштовних моніторів. Смс зробив через email to sms поки Київстар це підтримував. Виходило повінстю безкоштовно (крім ціни за смс, яка була пару копійок) Потім цю фічу кільнули і я купив підписку на статускейк за 30 баксів в міс. Але виявилось що смс в Україну не праюють. Тому ми за півдня склєпали свій монітор який вже служить 3 роки без проблем. Хоститься на віртуалці за 4$.

Сьогодні з АІ, такий сервіс просто ваншотиться. Не кажучи вже про опен-сорс і селф-хост.

Так, в цілому з AI багато що переповнюється, якщо брати наприклад мобільні завстосунки, там взагалі бум
В цілому придумати щось нове і потрібне стає досить складно

Мені цікавіше інше: чим ви моніторите свої сервіси і що там реально бісить?

Зараз Sentry. Раніше це був UptimeRobot. Перейшов, тому що вже користуюсь аналізом помилок з Sentry, щоб усе було з однієї коробки.

Може має сенс вам піти далі моніторінга — наприклад, зробити root-cause аналіз падінь сайтів?

Я розробляю testinel.dev — і вирішив не робити yet another test case management system з репортами, а робити фокус саме на root-cause analysis чому ці тести впали. Іншою мовою робити логічне продовження існуючих інструментів: якщо людина дивиться в логи тестів, то їй буде цікаво й одразу почати виправляти.