Короткий ответ
Если после переноса site.example «то новый, то старый», смотрите DNS, не PHP. Записи A/AAAA должны указывать на новый origin 10.0.20.40 (или на CDN, который уже смотрит на него). Снизьте TTL заранее, смените записи, ждите максимальный старый TTL. Проверку контента делайте curl --resolve / файл hosts, не надеясь, что «у меня уже открылось». Пока DNS старый, Let's Encrypt HTTP-01 тоже ходит на старый IP.
План cutover: перенос. 404 на новом при правильном DNS — document root.
Симптомы и как отличить
- Соседи видят новый сайт, вы — старый (или наоборот).
dig A site.example≠10.0.20.40.- HTTPS ошибка имени: попали на чужой default vhost старого сервера.
- NPM/панель открывается, публичный сайт нет.
| Инструмент | Что проверяет |
|---|---|
dig у авторитетного NS | что выписали |
dig @8.8.8.8 | публичный резолвер, не ваша политика если запрещён — используйте свой рекурсор |
curl --resolve | origin напрямую |
| браузер | кэш + DoH |
Возможные причины
- A не сменили, сменили только www или наоборот.
- AAAA всё ещё на старый IPv6, клиенты предпочитают v6.
- TTL 86400, сменили запись час назад.
- Cloudflare/прокси: серые/оранжевые облака, origin IP в панели не тот.
- Несколько A round-robin, один старый.
- Локальный
hostsу админа на старый IP. - Кэш рекурсора офиса.
Диагностика
1. Что видит мир и что вы хотите
dig +noall +answer A site.example www.site.example
dig +noall +answer AAAA site.example
dig +noall +answer NS site.example
dig +ttlunits +noall +answer A site.exampleСверьте с панелью регистратора. IP нового стенда: 10.0.20.40.
2. Авторитетные NS
dig +short NS site.example
dig A site.example @ns1.example-registrar # подставьте реальный NS из предыдущей командыНе выдумывайте имя NS. Берите из ответа.
3. Origin напрямую
curl -sI --resolve site.example:443:10.0.20.40 https://site.example/ | head
curl -sI --resolve site.example:443:<OLD_IP> https://site.example/ | headПодставьте фактический старый IP из dig, не из памяти.
4. Hosts на рабочей станции
# Linux/macOS
grep site.example /etc/hosts
# Windows PowerShell
Get-Content $env:SystemRoot\System32\drivers\etc\hosts | Select-String 'site.example'5. LE
Если renew падает connection refused на чужом IP — это этот кейс + certbot.
Решение
Сценарий A. Плановая смена
- За 24–48 ч до cutover поставьте TTL 300 на A/AAAA/www.
- Дождитесь истечения старого TTL.
- Поднимите сайт на
10.0.20.40, проверьте--resolve. - Смените A/AAAA (и www) на новый адрес.
- Наблюдайте
digс нескольких рекурсоров. - Старый сервер не гасите, пока TTL не выдохся (редирект/статика «мы переехали» опционально).
Не уменьшайте TTL в момент смены — поздно для тех, кто уже закэшировал час назад.
Сценарий B. Забыли AAAA
Удалите устаревший AAAA или поставьте корректный IPv6 нового сервера. Битый AAAA = часть клиентов на старом/мёртвом узле при живом A.
Сценарий C. Несколько A
Оставьте один канонический origin (или два осознанных в балансировке). Лишний старый A — лотерея.
Сценарий D. CDN
Смените origin IP в панели CDN. Публичный A может остаться anycast CDN — это нормально, тогда «старый сервер» в A вы не увидите. Проверяйте настройки origin, не только dig site.example.
Сценарий E. Локальный hosts после теста
Удалите тестовые строки после cutover, иначе будете чинить «не тот сервер».
Сценарий F. Раздвоенная зона и старый NS
dig NS site.example должен совпадать с NS у регистратора. Если сменили DNS-хостинг, но регистратор всё ещё делегирует старые NS, вы правите «красивую» панель, а мир читает старую зону со старым A. Сверьте glue и whois/RDAP NS. Не путайте записи в Cloudflare с записями на registrar DNS — активен один набор NS.
После cutover обновите SPF/A для сайта, если SPF содержал старый IP как ip4: для веб-форм. MX не меняйте «за компанию». CAA, если есть, должен разрешать Let's Encrypt на новом origin.
Проверка с нескольких резолверов:
for s in 1.1.1.1 8.8.8.8 9.9.9.9; do echo $s; dig +short A site.example @$s; doneЕсли политика запрещает публичные резолверы — используйте внутренние рекурсоры филиалов. Расхождение = кэш TTL или split-horizon.
Как проверить, что проблема устранена
dig +short A site.example
dig +short A www.site.example
dig +short AAAA site.example
curl -sI https://site.example/ | headA = 10.0.20.40 (если без CDN). HTTPS — новый контент (метку в футере/заголовок X-Served-By если добавите временно). С телефона через LTE — не офисный кэш. Certbot dry-run с нового IP.
Если не помогло
- SERVFAIL: сломали DNSSEC, DS на старой ZSK. Это уже зона DNSSEC, не nginx.
- NXDOMAIN: удалили apex, остался только www.
- GeoDNS отдаёт разные IP — сверьте view.
- Почта: MX не обязан совпадать с A сайта; не трогайте MX «заодно».
Профилактика
- Чеклист миграции с TTL.
- Инвентаризация A, AAAA, www, dev, mail.
- Мониторинг
digс внешнего зонда. - Не держать TTL 86400, если миграции частые; 3600 разумный компромисс.
- Перед cutover запишите
dig A/AAAA/NSв заявку: иначе не докажете, что «у клиента старый IP» — это кэш, а не ваша зона.
FAQ
Сколько ждать TTL 3600?
До часа после смены плюс кэш промежуточных. Для страховки — 2×TTL.
CNAME www на apex
Apex обычно A/AAAA (или ALIAS у регистратора). Не ставьте CNAME на apex, если DNS провайдер это запрещает.
Можно ли /etc/hosts у всех сотрудников вместо смены DNS?
Только для теста админов. Пользователей так не переключить.
Старый сервер как 301 на новый IP?
HTTP-редирект по IP чужой Host сломает TLS. Лучше DNS. Временно — страница «обновите кэш» на HTTP.
Glue записи?
Только если NS на том же домене. Для сайта на 10.0.20.40 обычно не ваш случай.