Atlorium

Сайт падает молча: как сертификат и DNS убивают выручку, пока никто не смотрит

Сертификат истекает в 3 часа ночи в субботу. Мониторинг доступности зелёный: сервер отвечает, просто браузер клиента показывает страшный экран. Собираем проверку, которая ловит это заранее.

10 минут чтения DevOps · технический директор · системный администратор · малый бизнес

Сертификат истёк в субботу, в 03:12. Автопродление сломалось ещё в мае — тогда поменяли веб-сервер, и хук перезапуска перестал находить конфиг. Никто не заметил: сертификат был выписан на 90 дней, и до субботы всё работало.

Мониторинг в это время показывал зелёное. Он ходил на /health и получал честный HTTP 200 — сервер-то жив, приложение отвечает, база на месте. Просто у каждого, кто в эти часы открывал сайт, браузер рисовал красный экран с надписью про небезопасное соединение. Ни один из них не написал в поддержку — люди в такой ситуации просто уходят.

Разбор в понедельник занял четыре минуты: открыли сайт в браузере — и всё стало ясно. Обиднее всего было не то, что чинили долго, а то, что о поломке узнали от коммерческого директора, который в воскресенье вечером посмотрел на выручку выходных.

Вторая история из того же класса — тише и дороже. Домен переносили к новому регистратору, аккуратно перенесли A и AAAA, проверили, что сайт открывается, и закрыли задачу. Через три недели выяснилось, что вместе со старой зоной остались MX и TXT: почта с домена уходила, но никуда не приходила, а письма от сервиса рассылки провайдеры складывали в спам, потому что SPF в новой зоне не завезли.

Где мониторинг слепнет

Типовая проверка доступности — это запрос по HTTP и ожидание кода 200. Её пишут один раз и потом годами не трогают. У неё есть два слепых пятна, и именно в них живут самые дорогие отказы: те, при которых с точки зрения сервера всё в порядке.

Сертификат истёк, а сервер отвечает

Что происходит
Проверка ходит на внутренний адрес или по HTTP, а если по HTTPS — то с выключенной валидацией сертификата, иначе «мониторинг ложно срабатывает». Ответ 200 приходит и в тот момент, когда браузер клиента уже показывает предупреждение на весь экран.
Во что обходится
Конверсия на публичной странице падает почти до нуля, а платные клики продолжают откручиваться: рекламная система про ваш сертификат ничего не знает.
Чем закрывается
Проверка SSL-сертификата возвращает daysRemaining и список ошибок. За 30 дней до истечения это задача в бэклоге, за 3 дня — срочная задача, после истечения — инцидент.

Зона переехала, половина записей осталась

Что происходит
При переносе зоны копируют то, что видно глазами: A, AAAA, иногда CNAME. MX, TXT со SPF и запись _dmarc остаются у старого провайдера — и молчат, потому что сайт-то открывается.
Во что обходится
Письма домена перестают доходить, а узнаёте вы об этом от клиента, который «не получил счёт». Репутация домена у почтовых провайдеров восстанавливается неделями.
Чем закрывается
Проверка DNS-записей одним ответом отдаёт A, AAAA, MX, TXT, CNAME и NS. Эталон записей держите в репозитории и сравнивайте с тем, что реально отвечает резолвер.

Проверка есть, но она не запускалась

Что происходит
Cron-строку взяли из чужого гайда. «0 0 */5 * *» выглядит как «каждые пять дней», а на деле срабатывает 1, 6, 11, 16, 21, 26 числа — и в конце месяца между запусками проходит семь дней, а не пять.
Во что обходится
Сторож, который срабатывает не тогда, когда вы думаете, хуже отсутствия сторожа: на него полагаются. Проверить это в бою можно только пропустив событие.
Чем закрывается
Разбор Cron-выражений возвращает нормализованное выражение и список ближайших запусков в нужном часовом поясе. Ошибка в расписании видна за секунду и до выкатки.

Про выключенную валидацию TLS в проверках стоит сказать отдельно, потому что это не разгильдяйство, а логичный шаг. Мониторинг обычно ходит на внутренний адрес или прямо в контейнер, где сертификата нет вовсе или он самоподписанный. Включённая валидация там начинает орать постоянно, её выключают — и вместе с ложными срабатываниями теряют настоящее. Правильный ответ не «включить обратно», а «завести вторую проверку, которая смотрит на публичный адрес глазами клиента».

Отдельный сорт этой же беды — несовпадение имени. Завели поддомен api.example.com, направили его на тот же сервер и забыли перевыпустить сертификат: в нём есть example.com и www.example.com, а нового имени нет. Сервер отвечает, приложение отдаёт JSON, мобильное приложение падает с ошибкой TLS. В ответе проверки это видно сразу: список subjectAlternativeNames и строка про name mismatch в errors.

Сколько стоит тишина

Считать будем на магазине с выручкой 1,2 млн ₽ в месяц. Это примерно 40 000 ₽ в сутки. Допущение назову вслух: выручка по часам распределена неравномерно, ночью заказов почти нет, и растягивать сутки в ровные 1 700 ₽ в час было бы враньём в свою пользу. Возьмём консервативно: 70% выручки приходится на десять дневных часов, то есть один дневной час стоит около 2 800 ₽.

Сертификат истёк ночью в субботу. Первый клиент упёрся в красный экран около десяти утра, а починили в 16:40 — потому что дежурный сначала полчаса искал, что не так с приложением. Шесть дневных часов простоя — это около 17 000 ₽ невыкупленных корзин. Плюс контекстная реклама, которая эти шесть часов исправно вела людей на страницу с предупреждением.

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

А теперь вторая колонка: сколько стоило бы узнать заранее. Проверка сертификата по трём хостам раз в сутки — это 90 проверок в месяц. Сверка DNS — ещё 30. Цены считайте на странице тарифов, но порядок такой, что сумма за месяц не дотягивает до стоимости одного потерянного заказа. Отдельного договора и абонентской платы тут нет: платите за сделанные запросы, а один ключ работает и для сертификата, и для DNS, и для остальных сервисов.

Событие Что видит проверка доступности Что видит проверка сертификата и DNS Запас времени
Сертификат истекает через 2 недели HTTP 200, всё в порядке daysRemaining: 14 14 дней
Сертификат истёк HTTP 200 (валидация TLS обычно выключена) isValid: false, в errors — «Certificate has expired» 0, но узнаёте за минуты, а не за часы
Сертификат выписан на другое имя HTTP 200 errors: «Certificate name mismatch for host …» сразу
A-запись подменили или потеряли 200 — резолвер мониторинга ещё держит старый ответ в кэше значение A не совпадает с эталоном минуты
SPF пропал при переносе зоны ничего: сайт открывается в группе TXT нет записи v=spf1 … до первой рассылки

Как собрать проверку за вечер

Порядок ровно такой, и первый шаг — не про код.

Шаг первый: заведите эталон. Файл в репозитории рядом с инфраструктурным кодом: список хостов с сертификатами, ожидаемый издатель для каждого и ожидаемые DNS-записи — A, AAAA, MX, TXT со SPF, отдельно запись _dmarc. Без эталона сравнивать не с чем: скрипт сможет сказать «MX-записи такие-то», но не сможет сказать, что они не те. Эталон меняется через тот же pull request, что и всё остальное, — значит, у любого расхождения есть автор и дата.

Шаг второй: раз в сутки проверяйте сертификаты. Эндпоинт /api/certificate/batch принимает до 10 хостов за запрос и отдаёт по каждому карточку: isValid, daysRemaining, expirationDate, issuer, subject, subjectAlternativeNames, версию TLS, размер ключа, цепочку и список ошибок. Одиночный хост — /api/certificate?host=…, а если у вас на руках полный URL из браузера, подойдёт /api/certificate/url?url=…: хост и порт он разберёт сам.

Шаг третий: сверяйте DNS. /api/dns/lookup?domain=… возвращает записи, сгруппированные по типам — A, AAAA, MX, TXT, CNAME, NS, — с TTL и приоритетом для MX. DMARC живёт не на самом домене, а на поддомене _dmarc.example.com, поэтому для него нужен отдельный запрос: смотреть надо в его TXT. Резолвер по умолчанию — Cloudflare; параметр resolver принимает публичный IP любого другого, а значение system заставит сервис спросить системный DNS.

Когда домен переезжает, полезен /api/dns/propagation: он опрашивает несколько резолверов сразу и показывает, кто из них уже видит новые записи, а кто ещё отдаёт старые. По умолчанию их четыре — Cloudflare, Google, OpenDNS, Quad9; своих можно передать до восьми.

Шаг четвёртый: пороги. Одно «сертификат истекает» бесполезно: если писать в чат каждый день начиная с 60 дней, к 30-му дню на это перестанут смотреть. Пороги должны повышать голос по мере приближения даты.

Осталось дней Что делает скрипт Почему так
30 Заводит задачу в бэклог, молча Автоматика продления обычно обновляет сертификат, когда остаётся меньше 30 дней. Если порог перешагнули — просто ждём, это нормальный день из жизни домена.
20 Первое сообщение в рабочий чат Автопродление должно было отработать и не отработало. Это уже сигнал, что сломан хук или права на файлы, а не что «время пока есть».
14 Напоминание в чат ежедневно, задача с исполнителем Двух недель хватает на ручное продление даже с платным УЦ, где нужна проверка организации.
7 Эскалация: чат плюс письмо владельцу сервиса Неделя — это последний срок, когда отпуск дежурного ещё не превращается в аварию.
3 Пейджер, звонок дежурному Три дня — это выходные плюс понедельник. Дальше сертификат истечёт в тот момент, когда никто не смотрит.
0 или isValid: false Инцидент Клиенты уже видят предупреждение браузера.

Шаг пятый: расписание. Проверка сертификатов раз в сутки — этого достаточно: сертификат не истекает внезапно. DNS лучше сверять чаще, раз в час: подмена или потеря записи происходит мгновенно. Строку для планировщика прогоните через /api/cron/evaluate до того, как она попадёт в прод: сервис вернёт нормализованное выражение, разбор по полям и список ближайших запусков в вашем часовом поясе. Если написали не то, что имели в виду, — увидите это по датам.

Жить этот сторож должен не на том сервере, за которым он следит. Иначе он утонет вместе с ним и в самый нужный момент промолчит. Подойдёт что угодно: соседняя виртуалка, рабочая машина админа с включённым питанием, задача в CI по расписанию. Тридцать строк скрипта, переменная окружения с ключом и одна строка в crontab.

Код: сторож на два запроса

Все примеры работают с публичным демо-ключом ak_sandbox_demo_mockdata_v1: скопируйте команду и получите ответ, не заводя аккаунт. С этим ключом API отдаёт моки — правдоподобные, но сгенерированные данные, одинаковые от запроса к запросу. На них удобно отладить разбор ответа и написать тесты; настоящий сертификат вашего домена приходит только с личным ключом.

Проверка сертификатов по списку хостов

curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     "https://atlorium.com/api/certificate/batch?hosts=example.com,shop.example.com,api.example.com"
        

import os
import requests

API = "https://atlorium.com/api"
HEADERS = {"Authorization": "Bearer " + os.environ["ATLORIUM_KEY"]}

HOSTS = ["example.com", "shop.example.com", "api.example.com"]
EXPECTED_ISSUER = "Let's Encrypt"

# Пороги из таблицы выше: от самого срочного к самому спокойному.
THRESHOLDS = [(3, "PAGE"), (7, "ESCALATE"), (14, "DAILY"), (20, "CHAT"), (30, "BACKLOG")]

def level(days_remaining):
    for limit, name in THRESHOLDS:
        if days_remaining <= limit:
            return name
    return None

response = requests.get(
    API + "/certificate/batch",
    params={"hosts": ",".join(HOSTS)},
    headers=HEADERS,
    timeout=30,
)
response.raise_for_status()

for cert in response.json():
    host = cert["host"]

    # isValid = false — это уже инцидент: имя не то, цепочка не строится или срок вышел.
    if not cert["isValid"]:
        print("CRITICAL " + host + ": " + "; ".join(cert["errors"]))
        continue

    # Издатель сменился сам собой — повод посмотреть руками, а не радоваться.
    if EXPECTED_ISSUER not in cert["issuer"]:
        print("WARN " + host + ": издатель " + cert["issuer"] + ", ожидали " + EXPECTED_ISSUER)

    alert = level(cert["daysRemaining"])
    if alert:
        print(alert + " " + host + ": осталось " + str(cert["daysRemaining"]) + " дн.")
        

using System.Net.Http.Json;

var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
    new("Bearer", Environment.GetEnvironmentVariable("ATLORIUM_KEY"));

var hosts = "example.com,shop.example.com,api.example.com";
var certs = await http.GetFromJsonAsync<List<CertificateData>>(
    $"https://atlorium.com/api/certificate/batch?hosts={hosts}");

foreach (var cert in certs!)
{
    if (!cert.IsValid)
        Console.WriteLine($"CRITICAL {cert.Host}: {string.Join("; ", cert.Errors)}");
    else if (cert.DaysRemaining <= 14)
        Console.WriteLine($"WARN {cert.Host}: осталось {cert.DaysRemaining} дн.");
}

// Поля берём ровно те, что отдаёт API.
record CertificateData(
    string Host, bool IsValid, int DaysRemaining,
    string Issuer, string Subject, List<string> Errors);
        

[
  {
    "host": "example.com",
    "port": 443,
    "isValid": true,
    "daysRemaining": 47,
    "validFrom": "2026-05-28T09:14:00",
    "expirationDate": "2026-08-30T09:14:00",
    "issuer": "CN=R3, O=Let's Encrypt, C=US",
    "subject": "CN=example.com",
    "subjectAlternativeNames": ["example.com", "www.example.com"],
    "tlsVersion": "Tls13",
    "signatureAlgorithm": "sha256RSA",
    "keySize": 2048,
    "isSelfSigned": false,
    "certificateChain": [
      {
        "subject": "CN=example.com",
        "issuer": "CN=R3, O=Let's Encrypt",
        "validTo": "2026-08-30T09:14:00",
        "isValid": true,
        "errors": []
      }
    ],
    "errors": [],
    "checkedAt": "2026-07-14T03:00:12Z"
  }
]
        

Тот же вызов на шести языках (Python, TypeScript, Go, Java, C#, PHP) — в репозитории ssl-certificate-check-api-client. Примеры запускаются сразу: ключ в них уже стоит демонстрационный.

Разбирать ответ целиком не нужно — для сторожа хватает четырёх полей. Вот что с ними делать.

Что в ответе Что это значит Решение
isValid: true, daysRemaining больше порога Всё в порядке Молчать. Сторож, который говорит каждый день, перестаёт быть сторожем.
errors: «Certificate has expired» Срок вышел, клиенты видят предупреждение Инцидент. Продлевать немедленно.
errors: «Certificate name mismatch for host …» Сертификат выписан на другое имя: обычно завели поддомен и забыли добавить его в SAN Смотреть subjectAlternativeNames: нужного имени там нет. Перевыпустить.
errors: «SSL handshake failed: …» Рукопожатие не состоялось: сервер не отдал TLS на этом порту или не сошлись протоколы Проверить, что на порту действительно HTTPS, и заглянуть в tlsVersion.
isSelfSigned: true на публичном хосте Самоподписанный сертификат — в проде такого быть не должно Скорее всего, приложение отдаёт дефолтный сертификат сервера: конфиг не подхватился.
issuer не тот, что в эталоне Сертификат выписан другим удостоверяющим центром Разбираться руками. Чаще всего это откат конфига, но проверить стоит внимательно.

Сверка издателя в этом скрипте — не паранойя. Сертификат, который вдруг выписан другим удостоверяющим центром, чаще всего означает, что при перезапуске сервер подхватил не тот файл: старый, тестовый или дефолтный. Браузер такое иногда проглатывает, а мобильное приложение с закреплённым сертификатом — нет. Заодно загляните в certificateChain: там каждое звено цепочки со своими датами, издателем и флагом isValid. Про промежуточные сертификаты вспоминают редко, а даты у них тоже есть — и проблемы с цепочкой попадают в errors вместе со всем остальным.

Вторая половина сторожа — сверка DNS. Логика та же: получить записи, сравнить множества значений с эталоном, сказать вслух только про расхождение.

Сверка DNS-записей с эталоном

curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     "https://atlorium.com/api/dns/lookup?domain=example.com"

# DMARC лежит на отдельном поддомене — это отдельный запрос:
curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     "https://atlorium.com/api/dns/lookup?domain=_dmarc.example.com"
        

import os
import requests

API = "https://atlorium.com/api"
HEADERS = {"Authorization": "Bearer " + os.environ["ATLORIUM_KEY"]}

# Эталон. Лежит в репозитории и меняется через pull request — как и любой другой конфиг.
EXPECTED = {
    "example.com": {
        "A": {"93.184.216.34"},
        "MX": {"mail1.example.com", "mail2.example.com"},
        "TXT": {"v=spf1 include:_spf.example.com ~all"},
    },
    "_dmarc.example.com": {
        "TXT": {"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"},
    },
}

def lookup(domain):
    r = requests.get(API + "/dns/lookup", params={"domain": domain}, headers=HEADERS, timeout=15)
    r.raise_for_status()
    data = r.json()

    # Пустые records при непустых errors — резолвер не ответил. Это не «записей нет»,
    # а «мы не знаем»: поднимать тревогу по такому ответу нельзя.
    if not data["records"] and data["errors"]:
        raise RuntimeError(domain + ": " + "; ".join(data["errors"]))

    # Ответ сгруппирован по типам: records = [{"type": "A", "records": [...]}, ...]
    return {g["type"]: {rec["value"] for rec in g["records"]} for g in data["records"]}

for domain, expected_groups in EXPECTED.items():
    actual = lookup(domain)
    for record_type, expected in expected_groups.items():
        got = actual.get(record_type, set())
        if got != expected:
            print("DNS DRIFT " + domain + " " + record_type)
            print("  ожидали: " + str(sorted(expected)))
            print("  получили: " + str(sorted(got)))
        

{
  "domain": "example.com",
  "resolver": "Cloudflare",
  "requestedAtUtc": "2026-07-14T03:00:14Z",
  "records": [
    {
      "type": "A",
      "records": [
        { "name": "example.com", "value": "93.184.216.34", "ttl": 300 }
      ]
    },
    {
      "type": "MX",
      "records": [
        { "name": "example.com", "value": "mail1.example.com", "preference": 10, "ttl": 3600 },
        { "name": "example.com", "value": "mail2.example.com", "preference": 20, "ttl": 3600 }
      ]
    },
    {
      "type": "TXT",
      "records": [
        { "name": "example.com", "value": "v=spf1 include:_spf.example.com ~all", "ttl": 3600 }
      ]
    }
  ],
  "errors": []
}
        

Тот же вызов на шести языках (Python, TypeScript, Go, Java, C#, PHP) — в репозитории dns-lookup-api-client. Примеры запускаются сразу: ключ в них уже стоит демонстрационный.

Осталось запустить это по расписанию. Строку планировщика стоит проверить до того, как она уедет в прод: /api/cron/evaluate принимает выражение и часовой пояс, а возвращает нормализованное выражение, разбор по полям и ближайшие запуски.

Проверяем расписание до выкатки

curl -X POST "https://atlorium.com/api/cron/evaluate" \
     -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     -H "Content-Type: application/json" \
     -d '{"expression":"0 6 * * *","timeZoneId":"Europe/Moscow","take":3}'
        

import requests

resp = requests.post(
    "https://atlorium.com/api/cron/evaluate",
    json={"expression": "0 6 * * *", "timeZoneId": "Europe/Moscow", "take": 3},
    headers={"Authorization": "Bearer ak_sandbox_demo_mockdata_v1"},
    timeout=10,
)
result = resp.json()

if not result["isValid"]:
    raise SystemExit("Расписание не разобралось: " + result["error"])

# Смотрим глазами на даты — именно здесь ловятся «каждые пять дней», которые не каждые пять.
for moment in result["occurrences"]:
    print(moment)
        

{
  "isValid": true,
  "rawExpression": "0 6 * * *",
  "normalizedExpression": "0 6 * * *",
  "segments": ["0", "6", "*", "*", "*"],
  "warnings": [],
  "error": "",
  "occurrences": [
    "2026-07-15T06:00:00+03:00",
    "2026-07-16T06:00:00+03:00",
    "2026-07-17T06:00:00+03:00"
  ]
}
        

Тот же вызов на шести языках (Python, TypeScript, Go, Java, C#, PHP) — в репозитории cron-expression-parser-api-client. Примеры запускаются сразу: ключ в них уже стоит демонстрационный.

Сервис принимает 5 и 6 полей (второй вариант — с секундами). Выражения из Quartz он приводит к своему виду и говорит об этом вслух: символ ? заменяется на *, седьмое поле с годом отбрасывается — и то и другое попадает в warnings. Если разобрать выражение не получилось, придёт isValid: false и текст ошибки в error: ответ 200, а не 400, потому что «невалидное выражение» — это результат разбора, а не сбой запроса.

Чего это не умеет

Раздел, ради которого стоит читать любую статью про инструмент.

Отзыв сертификата не проверяется. Ни по CRL, ни по OCSP. Сервис устанавливает TLS-соединение и разбирает то, что сервер показал в рукопожатии: срок, цепочку, издателя, соответствие имени хосту. Если сертификат отозван удостоверяющим центром, но по датам ещё действует, в ответе будет isValid: true. Это осознанное ограничение, а не забытая задача, и полагаться на нас в вопросе отзыва нельзя.

Ответ может быть не сиюминутным. Успешная проверка сертификата сохраняется и в течение суток отдаётся из локального хранилища, не порождая нового соединения с вашим сервером. Поле checkedAt показывает, когда рукопожатие было на самом деле. Для сторожа, который смотрит на daysRemaining, разница в несколько часов не значит ничего.

Это взгляд снаружи и с одного адреса. Мы видим то, что ваш сервер показал нашему серверу. Split-horizon DNS, гео-балансировку и региональные различия так не поймать: propagation по четырём-восьми публичным резолверам даёт срез, а не карту мира.

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

Демо-ключ отдаёт моки. Сертификат из песочницы всегда валиден, а даты в нём сгенерированы. На нём отлаживают разбор ответа — мониторить боевой домен с ним нельзя.

И привычная оговорка: если внешний источник не ответил, приходит 503 и деньги за такой запрос не списываются.

Частые вопросы

Частые вопросы

Почему мониторинг доступности не видит истёкший сертификат?

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

За сколько дней предупреждать об истечении SSL-сертификата?

Порогов должно быть несколько. Первое молчаливое напоминание — за 30 дней, первое сообщение в чат — за 20 (к этому моменту автопродление уже должно было отработать), ежедневные напоминания — за 14, эскалация владельцу сервиса — за 7, звонок дежурному — за 3 дня. Один порог не работает: либо на него перестают смотреть, либо он срабатывает слишком поздно.

Проверяет ли сервис отзыв сертификата по CRL или OCSP?

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

Как проверить SPF и DMARC через DNS API?

SPF — это TXT-запись самого домена: запросите /api/dns/lookup?domain=example.com и найдите в группе TXT значение, начинающееся с v=spf1. DMARC живёт на отдельном поддомене, поэтому нужен второй запрос — domain=_dmarc.example.com, и смотреть снова в TXT. Обе записи возвращаются вместе с TTL.

Чем propagation отличается от обычного lookup?

Lookup спрашивает один резолвер и отдаёт записи по шести типам. Propagation опрашивает несколько резолверов сразу и показывает ответ каждого отдельно — это нужно после изменения зоны, когда одни резолверы уже видят новые записи, а другие ещё отдают старые. По умолчанию опрашиваются четыре публичных резолвера, всего можно указать до восьми, и тарифицируется такая проверка по числу резолверов.

Можно попробовать без регистрации?

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

Сервисы из этой статьи

Проверка SSL-сертификата

Срок действия, цепочка доверия и параметры TLS-сертификата домена

Проверка DNS-записей

Резолв A/AAAA/MX/TXT и других типов, в т.ч. через DoH

Разбор Cron-выражений

Ближайшие даты запусков по cron-расписанию

Попробовать прямо сейчас — без регистрации

Демо-ключ ak_sandbox_demo_mockdata_v1 — публичный и общий для всех. С ним API отвечает моками: данные правдоподобные, но сгенерированные, и они не меняются от запроса к запросу — на них удобно писать тесты. Настоящие данные приходят с личным ключом.

curl -H "Authorization: Bearer ak_sandbox_demo_mockdata_v1" \
     https://atlorium.com/openapi/certificate_ru.json
Полезно? Перешлите коллеге: Telegram VK

Восстанавливаем соединение…

Похоже, связь с сервером ненадолго прервалась. Переподключаемся автоматически — пожалуйста, подождите несколько секунд.

Не удалось переподключиться

Проверьте интернет-соединение. Можно повторить попытку или обновить страницу.

Сессия устарела

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