// Engineering Log
HTTP, HTTPS и TLS: Часть 9 — Отладка HTTP с curl: подмена DNS, редиректы, тайминги и трассировка
Опубликовано 14.10.2026
// Быстрый маршрут
Эта статья относится к теме Деплой и стабильная работа.
curl — консольный HTTP-клиент, который есть в Linux, macOS и Windows 10 и новее. Для отладки он удобнее браузера: показывает запрос и ответ целиком, позволяет задать любой заголовок и метод, отправить запрос на конкретный IP в обход DNS и замерить, на каком этапе уходит время. Ниже — приёмы отладки: от просмотра заголовков до диагностики медленного сайта за балансировщиком. Если вы только начинаете работать с curl, начните со статьи «curl для начинающих»: там разобраны основные ключи, запросы к API и загрузка файлов.
Версия curl в системе может быть старой; часть ключей появилась недавно (у каждого указана версия). Свою версию и возможности сборки покажет curl --version.
Посмотреть ответ и заголовки
curl https://example.ru/ # только тело ответа
curl -i https://example.ru/ # заголовки ответа + тело
curl -I https://example.ru/ # только заголовки (метод HEAD)
curl -v https://example.ru/ # всё: DNS, TCP, TLS, запрос, ответ
curl -sv -o /dev/null https://example.ru/ 2>&1 # всё, кроме тела
curl -s -D - -o /dev/null https://example.ru/ # только заголовки, но методом GETЧто означают ключи:
-v(verbose) — подробный вывод в stderr: строки*— служебные сообщения (адрес, TLS, сертификат),>— отправленный запрос,<— полученные заголовки;-s— без индикатора загрузки; вместе с-Sошибки всё равно выводятся;-o /dev/null— тело выбросить;-o file— сохранить в файл,-O— сохранить под именем из адреса;-D -— записать заголовки ответа в stdout.
Осторожно с -I. Он отправляет HEAD, а не GET. Часть приложений отвечает на HEAD иначе — 405, 404 или без нужных заголовков. Если ответ на -I выглядит странно, проверьте тот же адрес через -s -D - -o /dev/null.
Передать заголовки
Заголовок задаётся ключом -H, ключ можно повторять:
curl -H 'Accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOi...' \
-H 'X-Request-ID: debug-42' \
https://api.example.ru/v1/ordersОсобые формы:
curl -H 'User-Agent:' https://example.ru/ # удалить заголовок, который curl добавляет сам
curl -H 'X-Empty;' https://example.ru/ # отправить заголовок с пустым значением
curl -H @headers.txt https://example.ru/ # взять заголовки из файла, по одному на строку (7.55+)Для частых заголовков есть отдельные ключи:
curl -A 'Mozilla/5.0 ...' https://example.ru/ # User-Agent
curl -e https://example.ru/ https://example.ru/x # Referer
curl -u admin:secret https://example.ru/admin/ # Basic-авторизация
curl --oauth2-bearer TOKEN https://api.example.ru/ # Authorization: Bearer
curl --compressed https://example.ru/ # Accept-Encoding + распаковка ответаУказывать -H 'Accept-Encoding: gzip' вручную не стоит: curl получит сжатый ответ и выведет его в терминал как есть. --compressed и запрашивает сжатие, и распаковывает.
Пароли и токены в командной строке видны в ps и остаются в истории оболочки. В скриптах передавайте их из файла: -H @auth-header.txt, или используйте ~/.netrc с ключом --netrc.
Cookie
curl -b 'session=abc123; lang=ru' https://example.ru/account # отправить cookie
curl -c cookies.txt https://example.ru/login # сохранить полученные
curl -b cookies.txt -c cookies.txt https://example.ru/account # читать и обновлять файлТипичный сценарий — войти через форму и дальше ходить с полученной сессией:
curl -c jar.txt -d 'login=ivanov&password=secret' https://example.ru/login
curl -b jar.txt https://example.ru/accountМетоды и тело запроса
Метод curl выбирает сам: без тела — GET, с -d — POST, с -I — HEAD. Явно метод задаётся ключом -X:
curl -X DELETE https://api.example.ru/v1/orders/42
curl -X PUT -H 'Content-Type: application/json' -d '{"status":"paid"}' https://api.example.ru/v1/orders/42-X POST вместе с -d не нужен — POST и так будет. А -X вместе с -L опасен: curl применит заданный метод ко всем запросам после редиректов, даже там, где по стандарту должен был быть GET.
Форма (application/x-www-form-urlencoded):
curl -d 'name=Иван&city=Москва' https://example.ru/form
curl --data-urlencode 'comment=Цена 100% & доставка' https://example.ru/form # с кодированием-d отправляет данные как есть и удаляет переводы строк из файла (-d @file). Для файлов без изменений — --data-binary @file, для строк с символом @ в начале — --data-raw.
JSON:
curl --json '{"name":"Иван","qty":2}' https://api.example.ru/v1/orders # curl 7.82+
curl --json @order.json https://api.example.ru/v1/orders--json сам ставит Content-Type: application/json и Accept: application/json. В старых версиях то же самое:
curl -H 'Content-Type: application/json' -d '{"name":"Иван"}' https://api.example.ru/v1/ordersЗагрузка файла (multipart/form-data, как форма с полем «файл»):
curl -F 'title=Отчёт' -F 'file=@report.pdf;type=application/pdf' https://example.ru/uploadПараметры GET из данных: -G превращает -d в строку запроса:
curl -G -d 'q=nginx' -d 'page=2' https://example.ru/search # GET /search?q=nginx&page=2Редиректы
По умолчанию curl не следует перенаправлениям и показывает сам ответ 301/302. Проследить всю цепочку:
curl -sIL https://example.ru/old-page | grep -iE '^(HTTP|location)'HTTP/1.1 301 Moved Permanently
Location: https://example.ru/old-page
HTTP/2 301
location: https://www.example.ru/new-page
HTTP/2 200-L— следовать редиректам;--max-redirs 5— ограничить число переходов (по умолчанию 50);-w '%{num_redirects} %{url_effective}\n'— сколько было переходов и где закончилось.
При переходе на другой хост curl не передаёт дальше заголовок Authorization и данные -u — это защита от утечки. Если это действительно нужно, есть --location-trusted.
Запрос на конкретный сервер в обход DNS
Самый полезный приём при переезде, настройке балансировщика или проверке одного узла из нескольких.
--resolve — подставить IP-адрес для имени:
curl --resolve example.ru:443:192.0.2.10 https://example.ru/curl подключится к 192.0.2.10, но Host, SNI и проверка сертификата будут для example.ru — ровно как у браузера после смены DNS. Так проверяют новый сервер до переключения записи.
--connect-to — подменить хост и порт подключения:
curl --connect-to example.ru:443:backend-2.internal:8443 https://example.ru/Удобно, чтобы пройти мимо балансировщика прямо на один из серверов.
Почему не -H 'Host: …'. Запрос curl -H 'Host: example.ru' https://192.0.2.10/ поменяет только заголовок Host, а SNI и проверка сертификата пойдут для 192.0.2.10: сервер вернёт сертификат по умолчанию, и curl выдаст ошибку несовпадения имени. Для HTTPS используйте --resolve или --connect-to. Для HTTP -H 'Host: …' работает.
Замер времени
Ключ -w (write-out) выводит переменные после запроса. Разбивка по этапам:
curl -s -o /dev/null -w '
dns: %{time_namelookup}
tcp: %{time_connect}
tls: %{time_appconnect}
ttfb: %{time_starttransfer}
total: %{time_total}
code: %{http_code}
http: %{http_version}
ip: %{remote_ip}
size: %{size_download}
' https://example.ru/Все времена — в секундах от начала запроса, нарастающим итогом:
time_namelookup— DNS; больше 0,1 с — проблема с резолвером;time_connect − time_namelookup— установка TCP, примерно один круг до сервера (RTT);time_appconnect − time_connect— рукопожатие TLS;time_starttransfer − time_appconnect— время, пока сервер готовил ответ (TTFB без сети). Если большое — проблема в приложении или базе, а не в сети;time_total − time_starttransfer— загрузка тела.
Шаблон удобно держать в файле и вызывать -w @curl-format.txt. С curl 7.70 есть -w '%{json}' — все переменные сразу в JSON, а с 7.83 — %{header_json} для заголовков ответа.
Проверка стабильности — серия запросов:
for i in $(seq 1 20); do
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' https://example.ru/
doneВыбор версии и протокола
curl --http1.1 https://example.ru/
curl --http2 https://example.ru/
curl --http3 https://example.ru/ # если сборка поддерживает HTTP/3
curl -4 https://example.ru/ # только IPv4
curl -6 https://example.ru/ # только IPv6Если сайт открывается по IPv4 и не открывается у части пользователей, проверьте -6: частая причина — запись AAAA на адрес, где сайт не слушает.
Прокси
curl -x http://proxy.example.ru:3128 https://example.ru/
curl -x socks5h://127.0.0.1:1080 https://example.ru/ # h — DNS тоже через прокси
curl --noproxy '*' https://example.ru/ # игнорировать переменные окруженияcurl учитывает переменные http_proxy, https_proxy, no_proxy. Если запрос из одного окружения работает, а из другого нет, проверьте env | grep -i proxy — прокси мог подхватиться незаметно.
Коды возврата и скрипты
По умолчанию curl завершается успешно (код 0) и при ответе 404 или 500 — ошибкой он считает только сбой соединения. Для скриптов и проверок:
curl -fsS https://example.ru/health || echo 'сервис недоступен'
curl --fail-with-body -sS https://api.example.ru/v1/check # 7.76+: код ошибки и тело ответа-f(--fail) — при ответе 400 и выше код возврата 22;--retry 3 --retry-delay 2— повторить при временных ошибках (таймаут, 408, 429, 5xx);--connect-timeout 5 --max-time 20— ограничить время подключения и всего запроса. Без них curl может ждать зависший сервер очень долго.
Частые коды ошибок curl: 6 — не удалось разрешить имя; 7 — не удалось подключиться; 28 — таймаут; 35 — ошибка рукопожатия TLS; 60 — сертификат не прошёл проверку.
Полная трассировка
Когда -v недостаточно — например, нужно увидеть точные байты тела запроса или порядок событий:
curl --trace-ascii trace.txt --trace-time https://example.ru/В файле — каждый отправленный и полученный блок данных с временной меткой. --trace пишет то же с шестнадцатеричным дампом.
Скопировать запрос из браузера
В инструментах разработчика (F12) на вкладке Network щёлкните правой кнопкой по запросу → Copy → Copy as cURL. Получится команда со всеми заголовками и cookie браузера. Это самый быстрый способ повторить в консоли запрос, который ведёт себя странно, и затем по одному убирать заголовки, чтобы найти причину.
Учтите: такой запрос повторит заголовки, но не отпечаток TLS браузера. Если сайт за системой защиты от ботов отвечает браузеру 200, а тому же запросу из curl — 403, дело скорее всего в отпечатке.
Типичные ошибки
-Iдля проверки приложения, которое не обрабатывает HEAD, — ложные 404 и 405.-H 'Host: …'для HTTPS вместо--resolve— ошибка сертификата и неверный сайт по умолчанию.-kв скриптах проверки — истекший или чужой сертификат остаётся незамеченным.- Проверка доступности без
-f— скрипт считает 502 успехом. - JSON через
-dбезContent-Type— curl отправляетapplication/x-www-form-urlencoded, и приложение не видит данных. - Нет
--max-timeв cron-задачах — зависшие процессы curl копятся.
// Похожая задача
Если у вас похожая ситуация
Эта статья относится к одной из рабочих тем. Можно продолжить чтение по теме, перейти на главную, чтобы понять, чем я занимаюсь, или сразу открыть услуги.
Тема статьи
Деплой и стабильная работа
Docker, CI/CD, релизы, мониторинг, observability и разбор инцидентов.
Часто с этим приходят
- Настроить деплой без ручных действий и хаоса
- Подключить мониторинг, алерты и базовую observability
- Разобрать инциденты и стабилизировать production
// Следующий шаг
Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.
Открыть услуги// Reviews
Отзывы по теме
Пришел с дорогим запросом по настройке VPS-сервера, но в процессе консультации Михаил предложил гораздо более простое и экономичное решение. В итоге сэкономил бюджет и время. Михаил — настоящий эксперт, который работает на результат клиента, а не на чек. Рекомендую!
Пришел с дорогим запросом по настройке VPS-сервера, но в процессе консультации Михаил предложил гораздо более простое и экономичное решение. В итоге сэкономил бюджет и время. Михаил — настоящий эксперт, который работает …
Настройка vps, настройка сервера
12.05.2026 · ★ 5/5
Отличная работа! Очень быстро настроил сервер, установил панель, прописал IP. Однозначно могу порекомендовать!
Отличная работа ! Очень быстро настроил сервер, установил панель прописал IP Однозначно могу по рекомендовать !
Всё отлично, помог оперативно и профессионально, спасибо, рекомендую сообществу
Всё отлично, помог оперативно и профессионально, спасибо, рекомендую сообществу
Настройка vps, настройка сервера
16.04.2026 · ★ 5/5
Было несколько проблем касаясь как технической части так и понимания в целом. Михаил быстро ответил на запрос, помог разобраться и решил проблеммы технические и помог разобраться в понимании, за что отдельное спасибо. Результатом доволен.
Было несколько проблем касаясь как технической части так и понимания в целом. Михаил быстро ответил на запрос, помог разобраться и решил проблеммы технические и помог разобраться в понимании, за что отдельное спасибо. …
Настройка vps, настройка сервера
18.02.2026 · ★ 5/5
Все было сделано быстро и четко. Рекомендую
Все было сделано быстро и четко. Рекомендую
Настройка vps, настройка сервера
17.01.2026 · ★ 5/5
Всё прошло хорошо, исполнитель быстро реагировал на вопросы и помог решить проблему. Спасибо!
Всё прошло хорошо, исполнитель быстро реагировал на вопросы и помог решить проблему. Спасибо!
Настройка vps, настройка сервера
16.12.2025 · ★ 5/5
// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related