API не отвечает: таймаут, connection reset или блокировка
Коротко: запрос к API проходит четыре слоя: DNS узнаёт адрес сервера, TCP устанавливает соединение, TLS договаривается о шифровании, HTTP передаёт сам запрос и ответ. «API не отвечает» значит, что запрос умер на одном из них, и какой это слой, видно по тексту ошибки. Таймаут и reset означают разное. При таймауте ответа не было вовсе. Connection reset by peer значит, что соединение оборвала другая сторона: сервер, прокси перед ним или оборудование на пути.
Сначала прочитайте ошибку#
Текст ошибки обычно сразу называет слой. Одна и та же проблема в разных инструментах звучит по-разному:
| Что пишет инструмент | Слой | Что это значит |
|---|---|---|
Could not resolve host (curl, код 6), ENOTFOUND (Node.js), no such host (Go), Name or service not known (Python на Linux) | DNS | Адрес сервера не нашёлся |
Connection refused (curl, код 7), ECONNREFUSED | TCP | Сервер доступен, но на этом порту никто не слушает или файрвол отказал явно |
Connection timed out after … milliseconds (curl, код 28), ETIMEDOUT, i/o timeout | TCP | Пакеты уходят в пустоту: неверный адрес, файрвол молча их отбрасывает или маршрут не работает |
Connection reset by peer (curl, код 35 во время TLS, 56 позже), ECONNRESET | TCP или TLS | Кто-то отправил сигнал сброса: упал сервер, прокси или оборудование на пути |
SSL certificate problem (curl, код 60) | TLS | Не прошла проверка сертификата |
Operation timed out … with 0 bytes received (curl, код 28) | HTTP | Соединение установлено, но сервер не ответил за отведённое время |
502, 503, 504 | HTTP | Ответил прокси или балансировщик: сам сервис за ним не отвечает |
Коды curl удобно смотреть в переменной $? сразу после команды: curl https://api.example.com; echo $?.
Строки с таймаутом из таблицы появляются, когда задан --connect-timeout или --max-time. Без них curl ждёт, пока соединение не оборвёт система, это минута-две, и пишет Failed to connect to … after 75003 ms: Could not connect to server. Код при этом бывает и 28, и 7, в зависимости от версии. Поэтому первую проверку лучше делать с таймаутами.
Что пишет клиент?
- Что случилось
- Кто-то прислал сброс соединения: сервер, балансировщик или оборудование на пути. HTTP-ответа нет.
- Как падает
- Сразу. Чаще всего после Client hello, тогда это рукопожатие TLS (код 35). Позже будет код 56.
- Где искать
- Перезапуск сервера, прокси, лимиты. Если из другой сети проходит, вмешательство на пути.
- Проверьте
openssl s_client -connect api.example.com:443 -servername api.example.com- В Tetiva
request failed: Get "https://api.example.com/health": read tcp 192.0.2.15:52876->203.0.113.10:443: read: connection reset by peer
Что значит connection reset by peer#
Connection reset by peer значит, что другая сторона соединения прислала TCP-пакет RST и оборвала его. «Другой стороной» для программы выглядит любой, кто ответил от имени сервера: сам сервер, балансировщик или прокси перед ним, файрвол на пути. HTTP-ответа при этом нет вовсе.
Та же ошибка в разных языках и программах:
- Python на Linux:
ConnectionResetError: [Errno 104] Connection reset by peer, на macOS[Errno 54]. В requests она завёрнута вConnectionError: ('Connection aborted.', ConnectionResetError(104, ...)). - Windows:
[WinError 10054] Удаленный хост принудительно разорвал существующее подключение, в старых программахsocket error 10054. - Node.js:
Error: read ECONNRESETилиsocket hang upс кодомECONNRESET. - Java:
java.net.SocketException: Connection reset. - Go:
read tcp …: read: connection reset by peer. - curl:
Recv failure: Connection reset by peer, код 56. Если сброс пришёл во время рукопожатия TLS, код будет 35, а в подробном выводеOpenSSL SSL_connect: Connection reset by peer. - SSH:
kex_exchange_identification: read: Connection reset by peer. Проверка та же, только порт 22:nc -vz host 22. Если порт открыт, а SSH всё равно сбрасывает, на сервере обычно срабатывает лимитMaxStartups: слишком много незавершённых подключений, часто от сканеров. Бан fail2ban выглядит иначе, какConnection refused.
Если сброс приходит сразу после Client hello, переходите к шагу 3, про TLS.
Если reset бывает не всегда
Если сброс случается время от времени, а повтор проходит, чаще всего клиент отправил запрос в соединение, которое сервер уже закрыл по простою. HTTP-клиенты держат соединения открытыми (keep-alive) и отправляют в них следующие запросы, а сервер закрывает простаивающие раньше: у Node.js-сервера keepAliveTimeout по умолчанию 5 секунд. Помогает время простоя в пуле клиента меньше серверного и один повтор для идемпотентных запросов (GET, PUT, DELETE). Ещё одна частая причина: сервер перезапускается при выкладке и рвёт открытые соединения.
Пройдите по слоям сверху вниз#
Для начала запустите curl -v с коротким таймаутом. По тому, на какой строке остановился вывод, видно, до какого слоя запрос дошёл:
curl -v --connect-timeout 5 --max-time 20 https://api.example.com/health
nc -vz -w 5 api.example.com 443и тот же запрос из другой сети1. DNS: нашёлся ли адрес
Если вместо строки Host api.example.com:443 was resolved curl сразу пишет Could not resolve host, дело в DNS. Проверьте, что отвечают разные резолверы:
dig +short api.example.com
dig +short api.example.com @1.1.1.1
dig +short api.example.com @77.88.8.8
Если ответы разные или один из резолверов не знает адреса, проблема в DNS, а не в API. Чтобы проверить сервер в обход DNS, подставьте адрес вручную: curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/health.
С середины августа 2026 года часть абонентов нескольких российских провайдеров сообщает, что зашифрованный DNS Google и Cloudflare (DoH и DoT) у них перестал работать, а на обычные запросы к 8.8.8.8 и 1.1.1.1 отвечает другой резолвер. Это замеры пользователей на Хабре, официального подтверждения нет. Но если в коде или на сервере жёстко прописан внешний резолвер, проверить его стоит в первую очередь.
2. TCP: connection refused или connection timed out
Если соединение установилось, сразу после строки Trying 203.0.113.10:443... начинается TLS: строки ALPN и Client hello. Если их нет:
Connection refusedпришёл сразу: сервер на месте, но порт закрыт. Проверьте порт в адресе и что сервис запущен.- Пауза, а потом
Connection timed out: пакеты не доходят. Это может быть неверный адрес, файрвол или проблема на маршруте.
Проверить сам порт без HTTP можно командой nc -vz api.example.com 443, в Windows Test-NetConnection api.example.com -Port 443. Если у сервера есть и IPv4, и IPv6, сравните curl -4 и curl -6: иногда сломан только один из путей.
3. TLS: ошибка сертификата или reset после Client hello
После Client hello сервер должен ответить строкой Server hello и прислать сертификат. Если сертификат не прошёл проверку, curl напишет SSL certificate problem, и это отдельная история: про сертификаты Минцифры и ошибку unable to get local issuer certificate есть отдельная статья.
Хуже, когда рукопожатие обрывается без объяснений: Recv failure: Connection reset by peer сразу после Client hello или тишина до таймаута. Подробности покажет openssl s_client -connect api.example.com:443 -servername api.example.com. Если та же команда из другой сети проходит, а из вашей нет, что-то на пути вмешивается в соединение по имени сайта. Ровно так в августовских замерах выглядела проблема с DoT: TCP-соединение устанавливается, а потом приходит reset.
4. HTTP: что ответил сервер
Если TLS прошёл, а ответа нет, сервер принял запрос и завис. curl закончит его по --max-time с сообщением 0 bytes received. Если ответ есть, смотрите на код:
- 502 и 504: до прокси вы дошли, а сервис за ним не ответил ему.
- 503: сервис перегружен или на обслуживании. Иногда в заголовке
Retry-Afterнаписано, когда вернуться. - 429: вы упёрлись в лимит запросов.
- 403 без понятного тела: часто это защита от ботов или фильтр по стране и IP, а не права доступа.
На любой из этих ответов curl завершается с кодом 0: обмен по HTTP состоялся. Чтобы скрипт заметил ошибку, добавьте --fail: тогда код будет 22, а curl напишет The requested URL returned error: 502.
Сбой или блокировка#
По одной ошибке причину не понять. Помогает сравнение:
- Тот же запрос из другой сети. Мобильный интернет, сервер в другой стране, онлайн-проверка доступности. Если оттуда работает, а от вас нет, проблема на пути, а не в API.
- Страница статуса сервиса. У крупных API она есть, и о сбоях там пишут раньше, чем в чатах.
- Другой клиент с той же машины. Если браузер открывает адрес, а скрипт нет, дело в настройках скрипта: прокси, сертификатах, DNS.
Если запрос не проходит ниоткуда, сбой на стороне сервиса. Если только из одной сети, а шаги выше показали reset или тишину на TLS, похоже на вмешательство на пути. Писать «заблокировали» по одному reset не стоит: сервер, который перезапускается, выглядит точно так же.
Что видно в API-клиенте#
Тайминги по фазам (DNS, подключение, TLS) Tetiva не показывает, только общее время ответа, поэтому слой ищут curl'ом. Сами ошибки в клиенте выглядят так:
- Таймаут. Tetiva ждёт ответа до 30 секунд и потом пишет
request timed out after 30s. Пока запрос идёт, тикает счётчик секунд, а кнопкаCancelего прерывает. - DNS. Ошибка выглядит как
DNS resolution failed for "api.example.com". - Подключение. Ошибки подключения, кроме DNS и таймаута, показаны строкой
connection refusedс адресом сервера. Для DNS, подключения и таймаута клиент подсказывает, что проверить. - Reset и обрыв TLS. Приходят исходным текстом после
request failed:, например…: read: connection reset by peer.
Неудачная попытка остаётся в истории вместе с текстом ошибки. Фильтр по статусу ошибка покажет, с какого момента запрос перестал проходить. Последнюю удачную и первую неудачную записи можно выделить с зажатым Cmd (Ctrl в Windows и Linux) и нажать «Сравнить», чтобы увидеть, что изменилось в запросе.
Что приложить к обращению в поддержку#
Чтобы поддержке было проще разобраться, приложите:
- полный вывод
curl -v(заголовокAuthorizationзамените заглушкой); - время запроса с часовым поясом;
- ваш внешний IP и провайдер;
- что ответил
digи откуда запрос проходит, а откуда нет.
Если запрос падает в браузере, вместо вывода curl приложите HAR-файл: как его записать и что из него вычистить.
Шпаргалка#
- DNS:
dig +short host, сравнить резолверы,curl --resolveв обход. - TCP:
refusedзначит закрыт порт, долгий таймаут значит не доходят пакеты.nc -vz host 443. - TLS:
SSL certificate problemэто сертификат, обрыв после ClientHello это вмешательство на пути.openssl s_client. - HTTP:
0 bytes receivedзначит сервер завис, 502/504 значит не отвечает сервис за прокси, 429 значит лимит. - Блокировка или сбой: тот же запрос из другой сети.