Два запроса в окно выката: почему 5xx на robots.txt дороже, чем на странице
За сутки 157 успешных ответов и два ответа 502 — оба в одну секунду, в момент перезапуска контейнера. Поисковик читает 5xx на robots.txt как «обход запрещён» и ставит краулинг на паузу.
Два внешних аудита в один день сообщили нам, что robots.txt и sitemap.xml
«возвращают internal error», и назвали это первоочередной проблемой. Мы пошли
смотреть логи.
Что показали логи
За сутки по этим двум адресам:
| Ответ | Сколько |
|---|---|
| 200 | 157 |
301 (заход по http://) | 8 |
404 (sitemap.xml.gz и два в окно выката) | 4 |
| 502 | 2 |
Два ответа 502 — оба в одну секунду, 06:03:21. Сайт здоров: пятьсот вторых за сутки получили пять запросов из тысяч. Но попасть в эту секунду можно, и аудит попал.
Откуда берётся окно
Шаг выката делает docker compose up -d: старый контейнер гасится, новый
поднимается, между ними апстрима нет. Второго апстрима в nginx не заведено,
proxy_next_upstream не настроен — всё, что прилетает в этот промежуток,
получает 502.
Выкатов в тот день было три подряд.
Почему именно robots.txt дороже прочих
Обычная страница в этом окне стоит одного неудачного захода: робот придёт позже.
robots.txt со статусом 5xx поисковик читает иначе — как «обход временно
запрещён» — и приостанавливает краулинг сайта целиком до следующего
нормального ответа. Не одной страницы, а всего.
И цена зависит от фазы. У нас домен жил четвёртые сутки, и Googlebot только разгонялся: 41 обращение в первый день, 10 во второй, 67 в третий. Пауза в такой момент обходится дороже, чем будет обходиться через полгода.
Что мы сделали
Оба файла отдаёт nginx статикой, а не приложение. Приложение может лежать, перезапускаться и собираться — на эти два адреса это не влияет.
Но пишет файлы не человек, а сборка: источником остаётся код, потому что оба файла выводятся из данных, а не написаны. Карта сайта строится из списка разделов, правила робота — из списков путей и групп агентов. Ручная копия разошлась бы на первой правке, и мы знаем, как это выглядит: у нас один путь не попал в список закрытых и был открыт роботам, пока это не заметили.
Файл в репозитории сверяется с тем, что породил бы код, — иначе шаг сборки, который однажды не выполнится, оставил бы протухший файл, и никто бы не узнал.
Как проверить у себя
Посмотрите, что отдают эти два адреса в момент выката, а не после него:
# в отдельном окне, пока идёт деплой
while true; do
curl -s -o /dev/null -w "%{http_code} " https://example.com/robots.txt
sleep 1
done
И потом — по логу за сутки:
awk '$7 ~ /^\/(robots\.txt|sitemap\.xml)$/ {print $9}' access.log | sort | uniq -c
Любая пятисотка в этом выводе — минуты паузы в обходе.
Что из этого следует
У выката есть окно недоступности, и обычно с ним живут: пользователь нажмёт ещё раз. Но есть адреса, по которым «нажмёт ещё раз» не работает — их спрашивает робот, и его реакция на отказ не «повторю», а «подожду».
Такие адреса стоит вынести из-под приложения целиком. У нас это два файла; у вас может быть проверка здоровья для балансировщика или вебхук платёжного провайдера, для которого 5xx означает «повторю через сутки».
Мы выкатываем приложения на серверы клиентов, и окно выката там ровно такое же — потому и разбираем его на себе первыми. Как устроен выкат — Деплой из Git.
Читайте также
- Редирект вёл на 0.0.0.0:3000, а локально всё работалоАбсолютный адрес строился от того, что процесс думает о себе. За nginx это дало адрес, которого не существует, — и ни одна проверка до выката этого не видела.
- Зелёный гейт, который ничего не проверил, опаснее красногоЗа один день нашлись три: проверка секретов зеленела на обрезанной истории, проверка зависимостей принимала пустой ответ за «уязвимостей нет», третья не запускала сравнение ни разу.
Автор
Александр ЦапковОснователь Скоупворк
Веду платформу и её боевой контур сам: разработка, выкат, дежурство. Пишу о том, на чём мы обожглись, — с датами, замерами и ссылками на решения в репозитории.