ERR_CONNECTION_RESET: кто сбросил соединение и как это найти
«Соединение сброшено» — ошибка Chrome с тремя равновероятными виновниками: ваш компьютер, сеть между вами и сайтом или сам сервер. Разбираем, что такое TCP RST, чем RESET отличается от REFUSED и TIMED_OUT, что проверить у себя за пять минут и как администратору найти источник сброса через curl, tcpdump и логи nginx.
ERR_CONNECTION_RESET (код -101 в Chromium) — ошибка, при которой TCP-соединение с сайтом было установлено, а затем оборвано пакетом RST: одна из сторон или узел между ними отказались продолжать обмен. В отличие от ERR_CONNECTION_REFUSED сервер был найден и ответил, в отличие от ERR_CONNECTION_TIMED_OUT — не молчал. По одному коду нельзя сказать, кто виноват: RST может прислать сервер, файрвол, провайдерское оборудование или антивирус на самом компьютере.
Что такое TCP RST и чем RESET отличается от REFUSED, TIMED_OUT и CLOSED
RST — флаг TCP-сегмента, означающий «этого соединения не существует, прекрати». По RFC 9293 (действующая редакция спецификации TCP, заменившая RFC 793) стек, получивший корректный RST в состоянии ESTABLISHED, обязан немедленно прервать соединение и сообщить приложению об ошибке — без обмена FIN. Система возвращает браузеру ECONNRESET (в Linux errno 104, в Windows WSAECONNRESET 10054), а Chromium, по данным файла net_error_list.h, показывает код -101.
Сводная таблица кодов Chromium на сентябрь 2026:
| Ошибка Chrome | Код | Что произошло в TCP | Кто чаще виноват |
|---|---|---|---|
| ERR_CONNECTION_RESET | -101 | Соединение было, пришёл RST | Клиент, сеть или сервер — поровну |
| ERR_CONNECTION_REFUSED | -102 | На SYN сразу ответили RST: порт закрыт | Сервер: сервис не запущен или слушает не тот адрес |
| ERR_CONNECTION_TIMED_OUT | -118 | На SYN не ответили вообще | Файрвол с DROP, маршрут, сервер выключен |
| ERR_TIMED_OUT | -7 | Соединение есть, ответа на запрос нет | Сервер: зависший бэкенд |
| ERR_CONNECTION_CLOSED | -100 | Соединение закрыто штатно (FIN) до конца ответа | Сервер или прокси: лимиты, ошибка в приложении |
| ERR_EMPTY_RESPONSE | -324 | Сервер закрыл соединение, не прислав ни байта | Сервер: упавший воркер, nginx return 444 |
Формулировки — перевод комментариев из net_error_list.h: -100 «соответствует TCP FIN», -101 «соответствует TCP RST», -324 «сервер закрыл соединение, не отправив данных». CLOSED и RESET — разница между вежливым «я закончил» и грубым «нас тут нет».
Как за минуту понять, проблема у меня или у всех
Первый вопрос — воспроизводится ли ошибка из другой сети и на другом устройстве. Откройте сайт с телефона через мобильный интернет (не через домашний Wi-Fi): если открылся — источник сброса на вашей стороне или у вашего провайдера; если нет — проблема на сервере или в сети рядом с ним.
Методика разделения «у меня / у провайдера / у сайта» подробно разобрана в статье «Сайт не работает: как понять, у кого проблема». Дальше две ветки: для пользователя и для администратора.
Что проверить на своём компьютере, если ошибка в Chrome
На стороне клиента RST рождает не браузер, а программа между ним и сетью: антивирус с проверкой HTTPS, корпоративный прокси, VPN-клиент. Второй источник — неверный MTU: большие пакеты теряются, и соединение обрывается на первой же «тяжёлой» странице.
# Windows, от администратора — сброс сетевого стека и кэша DNS ipconfig /flushdns netsh winsock reset netsh int ip reset # затем перезагрузка netsh winhttp show proxy # не прописан ли системный прокси # Тест MTU: 1472 байта данных + 28 байт заголовков = 1500 ping -f -l 1472 example.com # Windows ping -M do -s 1472 example.com # Linux (macOS: ping -D -s 1472)
Ответ «Packet needs to be fragmented» означает, что MTU на пути меньше 1500 — сбросы на больших ответах объясняются этим. Что делать дальше — в статье про MTU, MSS и фрагментацию.
| Причина на клиенте | Как проверить | Как исправить |
|---|---|---|
| Антивирус или файрвол с инспекцией HTTPS | Временно отключить веб-защиту | Добавить сайт в исключения или отключить сканирование HTTPS |
| VPN или прокси | Отключить VPN, проверить системный прокси | Сменить сервер VPN, режим (TCP/UDP) или убрать прокси |
| Расширение браузера или кеш | Окно инкогнито: расширения там отключены, кеш и cookies не используются | Отключать расширения по одному; очистить данные сайта |
| MTU роутера или туннеля | ping -f -l 1472; мелкие страницы открываются, большие нет | Снизить MTU на роутере (для PPPoE обычно 1492) или MSS clamping |
Когда соединение сбрасывает сеть: DPI, NAT и провайдер
Сброс, который не отправляли ни клиент, ни сервер, — инъекция RST промежуточным узлом: DPI, файрволом дата-центра или NAT, потерявшим запись о соединении. В России RST-инъекция описана как типовой механизм ограничения доступа: по техническим разборам 2024–2025 годов, оборудование ТСПУ дожидалось первых 16–20 пакетов TLS-сессии и при совпадении SNI с ограничиваемым доменом отправляло RST — пользователь видел ERR_CONNECTION_RESET через одну-две секунды после начала загрузки. В разборах лета 2026 года описан переход к отбрасыванию пакетов, которое браузер показывает уже как таймаут. Администратору важен симптом: сайт открывается из одних регионов и сбрасывается из других при исправном сервере.
Отличить инъекцию от «настоящего» RST помогает поле TTL: пакеты от сервера приходят с одним значением, а RST от узла на полпути — с другим, потому что прошёл меньше маршрутизаторов.
| Источник в сети | Признак | Что делать владельцу сайта |
|---|---|---|
| DPI / ТСПУ | Сброс на 1–2-й секунде TLS, зависит от оператора, TTL у RST не совпадает с TTL сервера | Проверить домен и IP в реестре, мониторить из регионов |
| NAT провайдера (CGNAT) или роутера | Рвутся долгие «тихие» соединения: WebSocket, long-polling | TCP keepalive короче таймаута NAT, ping-фреймы в WebSocket |
Владельцу сайта с аудиторией в России стоит держать отдельную проверку блокировки РКН: она сверяет домен и IP с реестром и предупредит раньше, чем посетители пришлют скриншоты с ERR_CONNECTION_RESET.
Что на сервере может отправить RST
Сервер отправляет RST в четырёх ситуациях: сокет закрыт с SO_LINGER=0, процесс умер посреди ответа, ядро отбило соединение из-за переполненной очереди, файрвол настроен на REJECT с tcp-reset. Пятая, самая коварная: сокет закрыт с непрочитанными данными в приёмном буфере — по RFC 2525 стек в этом случае обязан ответить RST, а не FIN.
| Причина на сервере | Где это настроено | Как проявляется |
|---|---|---|
| nginx закрывает по таймауту сбросом | reset_timedout_connection on (по умолчанию off); с 1.15.2 действует и для 444 | Медленные клиенты получают RST вместо FIN после send_timeout (60 с) |
| Гонка на keep-alive | keepalive_requests (по умолчанию 1000, до 1.19.10 — 100), keepalive_timeout 75s | Браузер отправил запрос в соединение, которое сервер в ту же миллисекунду закрыл — данные пришли на закрытый сокет |
| Слишком большой запрос | client_max_body_size 1m; large_client_header_buffers 4 8k | Сервер отвечает 413/400/414 и закрывает сокет, не дочитав тело; клиент ещё шлёт и получает RST раньше кода ответа |
| Переполнен accept-backlog | net.core.somaxconn (4096 с ядра 5.4, раньше 128), net.ipv4.tcp_abort_on_overflow | При abort_on_overflow=1 лишние соединения получают RST; при 0 (по умолчанию) — тишина и повтор |
| Файрвол с REJECT tcp-reset | iptables -j REJECT --reject-with tcp-reset, аналог в nftables | Мгновенный RST на SYN (REFUSED) или на данные (RESET) для адресов под правилом |
| Процесс упал во время ответа | OOM-killer, segfault в PHP-FPM или воркере приложения | Ядро закрывает сокеты умершего процесса; непрочитанные данные — RST |
За Cloudflare сброс от origin посетитель увидит как ошибку 520: среди её причин документация называет падения origin, блокировку IP-адресов Cloudflare файрволом, заголовки больше 128 КБ и пустой ответ. Отдельный случай — когда WAF или антибот режет не посетителей, а вашу систему мониторинга: об этом статья «WAF блокирует мониторинг».
Диагностика: curl, tcpdump, ss и логи
Первая команда — curl -v с сервера и с проблемной точки: она покажет, на каком этапе приходит сброс — до TLS, во время рукопожатия или после отправки запроса. Это отсекает половину гипотез.
$ curl -v --trace-time https://example.com/ -o /dev/null # пример вывода: сброс сразу после TLS ClientHello 14:02:11.318 * Connected to example.com (203.0.113.10) port 443 14:02:11.320 * TLSv1.3 (OUT), TLS handshake, Client hello (1): 14:02:12.404 * OpenSSL SSL_connect: Connection reset by peer in connection to example.com:443 14:02:12.404 * closing connection #0 curl: (35) OpenSSL SSL_connect: Connection reset by peer in connection to example.com:443 # пример вывода: сброс после отправки запроса, при чтении ответа > GET /export/report.csv HTTP/1.1 > Host: example.com > * Recv failure: Connection reset by peer * closing connection #0 curl: (56) Recv failure: Connection reset by peer
Код выхода curl подсказывает этап: 35 — сброс на TLS-рукопожатии (типичен для DPI и антивирусов), 56 — сброс при получении данных (сервер, лимиты, таймауты), 52 — сервер закрыл соединение, не ответив ничего (аналог ERR_EMPTY_RESPONSE), 7 — вообще не подключились.
Вторая — tcpdump на сервере с фильтром по флагу RST. Синтаксис tcp[tcpflags] & tcp-rst != 0 описан в man pcap-filter. Ключевой вопрос: чей это RST — исходящий с сервера или входящий от клиента?
# Все RST на порту 443 с TTL, без резолва имён sudo tcpdump -ni eth0 -v 'tcp port 443 and tcp[tcpflags] & tcp-rst != 0' # пример вывода: сервер сам шлёт RST — виновник здесь 14:02:12.401 IP (ttl 64) 203.0.113.10.443 > 198.51.100.7.51234: Flags [R.], seq 1, ack 518, length 0 # пример вывода: данные клиента идут с TTL 114, а RST «от него же» — с TTL 53. # Разный TTL у одного отправителя — признак инъекции промежуточным узлом 14:05:40.112 IP (ttl 114) 198.51.100.7.51301 > 203.0.113.10.443: Flags [P.], seq 1:518, length 517 14:05:40.113 IP (ttl 53) 198.51.100.7.51301 > 203.0.113.10.443: Flags [R], seq 518, length 0
Если RST уходят с самого сервера, следующий шаг — счётчики ядра и логи nginx. Переполненный backlog виден в ss -ltn (Recv-Q подбирается к Send-Q у слушающего сокета) и в счётчике ListenOverflows утилиты nstat.
# Очереди слушающих сокетов и счётчики отбитых соединений ss -ltn nstat -az | grep -E 'ListenOverflows|ListenDrops|TCPAbortOnData|TCPAbortOnClose|TcpOutRsts' # Что говорит nginx: 413/400/414 и запросы, оборванные клиентом grep -E ' (400|413|414|444|499) ' /var/log/nginx/access.log | tail -20 grep -iE 'reset by peer|too large|worker process .* exited' /var/log/nginx/error.log | tail -20 # Кто убил воркер, и есть ли правила файрвола со сбросом journalctl -k --since "1 hour ago" | grep -iE 'oom|killed process' sudo iptables -S | grep -i 'tcp-reset'
TcpOutRsts растёт — сервер сам генерирует сбросы. TCPAbortOnClose — сокет закрыт с непрочитанными данными (обрыв загрузки при 413), TCPAbortOnData — данные пришли в уже закрываемое соединение (гонка keep-alive). В error.log «worker process exited on signal 11» объясняет сброс падением, «client intended to send too large body» — лимитом client_max_body_size.
Симптом → причина → проверка → исправление
| Симптом | Вероятная причина | Как проверить | Как исправить |
|---|---|---|---|
| Сброс сразу после Client Hello, только из части регионов | RST-инъекция по SNI | curl -v из разных сетей; в tcpdump TTL у RST не совпадает с TTL клиента | Реестр, обращение к хостеру или оператору, мониторинг из регионов |
| Ошибка через раз, F5 помогает | Гонка keep-alive: сервер закрыл соединение одновременно с запросом | nstat: растёт TCPAbortOnData | keepalive_timeout на сервере больше, чем у прокси и клиента; второй параметр директивы — в заголовок Keep-Alive |
| Сброс только при загрузке файлов | client_max_body_size или лимит WAF/CDN | error.log: «client intended to send too large body» | Поднять лимит, оставить lingering_close on |
| Массовые сбросы в пик нагрузки | Переполнен backlog, abort_on_overflow=1 или воркеры падают по OOM | ss -ltn, ListenOverflows, journalctl -k | Больше воркеров и памяти, backlog в listen, abort_on_overflow=0 |
| Сброс у одного клиента на всех сайтах | Антивирус, VPN, прокси, MTU | Инкогнито, отключить защиту, ping -f -l 1472 | Исключения в антивирусе, MTU роутера, netsh winsock reset |
Где смотреть на Windows, macOS, Linux и Android
Порядок один на всех платформах: сначала журнал браузера (chrome://net-export пишет полный лог сетевого стека Chromium в файл), затем пакеты на уровне системы.
| Система | Захват пакетов | Сокеты и прокси | Сброс сетевого стека |
|---|---|---|---|
| Windows 10 (сборка 19041+) и 11 | pktmon (встроен, есть подсчёт отброшенных пакетов) или Wireshark | netstat -ano, Get-NetTCPConnection, netsh winhttp show proxy | netsh winsock reset, netsh int ip reset, ipconfig /flushdns |
| macOS | tcpdump встроен: sudo tcpdump -ni en0 'tcp[tcpflags] & tcp-rst != 0' | sudo lsof -i -P -n, networksetup -getwebproxy Wi-Fi | sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder |
| Linux | tcpdump, ss -ti (retrans, rtt), nstat | ss -tanp, env | grep -i proxy | resolvectl flush-caches; перезапуск NetworkManager |
| Android | Без root — снифферы на базе VPN-API (например, PCAPdroid), с root — tcpdump | Настройки → Сеть: VPN, частный DNS, прокси в параметрах Wi-Fi | Переключить Wi-Fi на мобильные данные; «Сброс настроек сети» |
Один дамп отвечает на вопрос «пришёл ли RST», два — «кто его отправил». Если в дампе клиента RST есть, а в дампе сервера исходящего RST нет, пакет родился в сети между ними — такое доказательство примут и хостер, и провайдер.
Как поймать сброс, который случается раз в час
Самые неприятные RST — плавающие: гонка keep-alive, пиковая нагрузка, региональная инъекция. Разовый curl их не ловит: в момент проверки всё работает. Нужны регулярные запросы из нескольких сетей с историей по каждой точке.
Пруфен выполняет HTTP-проверки и проверку TCP-порта с интервалом от 2 минут из 13 точек мониторинга — 11 в России, а также Минск и Испания. Сброшенное соединение фиксируется как неуспешный запуск в конкретной локации; инцидент открывается, когда недоступность подтверждает заданная доля точек. Во вкладке «По локациям» видно, из каких регионов соединение сбрасывается, а из каких нет — это ответ на вопрос «сервер или сеть» без ручных дампов.
Пруфен присылает уведомление в Email, Telegram или Макс, как только проверка перестала проходить, и второе — когда соединение восстановилось. Если ресурс так и не поднялся, подключается голосовой звонок. Время обнаружения равно интервалу проверки. Бесплатный план включает 5 проверок — хватит на главную, API и порт базы данных.
Частые вопросы
Почему ошибка только у части пользователей, а у меня сайт открывается?
Потому что RST, который видят они, рождается не на сервере: DPI конкретного оператора, антивирус на их компьютерах, MTU их провайдера или CGNAT. Соберите от нескольких жалующихся оператора связи, регион и вывод curl -v: совпадает оператор — вопрос к сети; у всех разные — ищите на сервере лимиты, которые срабатывают на конкретные запросы (размер cookie, тела, URL).
Может ли ERR_CONNECTION_RESET быть признаком блокировки?
Да, это характерный симптом: сброс стабильно происходит на первых секундах TLS-сессии, воспроизводится из сетей определённых операторов и исчезает через другой канал. Но сам по себе код ничего не доказывает — тот же RST даёт корпоративный прокси. Подтверждение — разный TTL у RST и остальных пакетов от того же адреса плюс проверка домена в реестре.
Чем ERR_CONNECTION_RESET отличается от ERR_CONNECTION_CLOSED?
CLOSED (-100) — соединение закрыто штатным FIN раньше, чем браузер получил полный ответ. RESET (-101) — соединение прервано RST, без вежливого завершения. CLOSED почти всегда означает сервер или его прокси, RESET требует проверки всех трёх сторон. Если на одном URL чередуются оба кода — скорее всего, дело в лимитах или падениях на сервере.
Помогает ли включить reset_timedout_connection в nginx?
Директива не чинит сбросы, а создаёт их: при таймауте nginx закрывает сокет с SO_LINGER=0, и клиент получает RST вместо FIN. Её включают осознанно, чтобы не держать память под сокеты зависших клиентов, например под атакой. Если после включения появились жалобы на ERR_CONNECTION_RESET на долгих запросах, верните off и поднимите send_timeout для нужных location.