# Tunnel connection failed: 502/503 через прокси: причины и решения

Source: https://ipvolt.com/ru/guides/fix-proxy-tunnel-502-503
Markdown: https://ipvolt.com/ru/guides/fix-proxy-tunnel-502-503.md
Language: ru

[ipvolt — главная](https://ipvolt.com/ru.md) / [Руководства](https://ipvolt.com/ru/guides.md) / Tunnel connection failed: 502/503 через прокси: причины и решения

Диагностика
Опубликовано: 2026-11-05
7 мин чтения
Автор: ipvolt

Ошибка 502, 503 или 504 при CONNECT приходит от прокси, а 502 после открытия туннеля — от сайта. Как различить их в каждом клиенте и что исправлять.

`502 Bad Gateway`, `503 Service Unavailable` или `504 Gateway Timeout`, пришедший в тот момент, когда клиент открывает туннель через прокси, отправил прокси: туннель так и не открылся, и сайт вашего запроса не видел. `502`, пришедший после открытия туннеля, отправил сайт или то, что стоит перед ним. Код тот же, источник другой, и исправление другое. Каждая строка ошибки и каждое число ниже получены на loopback-стенде 5 ноября 2026 года; ссылка на него — в конце.

## Кто отправил 502

Для URL `https://` клиент сначала просит прокси открыть туннель запросом `CONNECT host:443` ([RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect)). Если прокси отвечает чем-либо, кроме 2xx, туннеля нет, и большинство клиентов выбрасывают исключение. Если туннель открылся, а сайт ответил 502, вы получаете обычный ответ.

| Клиент | Прокси отказал в туннеле | Сайт ответил 502 |
| --- | --- | --- |
| curl 8.5.0 | код выхода 56, `curl: (56) CONNECT tunnel failed, response 502` | код выхода 0, `%{http_code}` равен 502, `%{http_connect}` равен 200 |
| curl 8.18.0 | код выхода 7, `curl: (7) CONNECT tunnel failed, response 502` | код выхода 0, `%{http_code}` равен 502, `%{http_connect}` равен 200 |
| Requests 2.34 | `requests.exceptions.ProxyError` с текстом `Tunnel connection failed: 502 Bad Gateway` | `Response` с `status_code == 502` |
| HTTPX 0.28 | `httpx.ProxyError: 502 Bad Gateway` | `Response` с `status_code == 502` |
| aiohttp 3.14 | `ClientHttpProxyError: 502, message='Bad Gateway'` | ответ со `status == 502` |
| Playwright 1.63 | `page.goto: net::ERR_TUNNEL_CONNECTION_FAILED` | `page.goto` завершается успешно, `status()` равен 502 |
| Node.js 24 fetch | `TypeError: fetch failed`, а `err.cause.cause.message` равен `Proxy response (502) !== 200 when HTTP Tunneling` | `response.status` равен 502 |

503 и 504 ведут себя так же, только со своим номером, например `Tunnel connection failed: 503 Service Unavailable` или `curl: (7) CONNECT tunnel failed, response 504`. Chromium во всех трёх случаях сообщил `net::ERR_TUNNEL_CONNECTION_FAILED` без статуса; это семейство ошибок разобрано в [руководстве по ERR_TUNNEL_CONNECTION_FAILED](/ru/guides/fix-err-tunnel-connection-failed).

Requests пишет `Max retries exceeded`, хотя по умолчанию ничего не повторяет: прокси на стенде получал ровно один CONNECT на запрос. Node прячет статус на два уровня глубже, поэтому логируйте всю цепочку `cause`.

Из этого правила есть два исключения. Для обычного URL `http://` туннеля нет, поэтому curl, Requests, HTTPX, aiohttp и Playwright возвращают собственный 502 прокси как обычный ответ; сравните его заголовок `Server` и тело с тем, что обычно отдаёт сайт. Fetch в Node туннелирует и URL `http://`, так что там это остаётся исключением. А прокси, который закрывает соединение без статуса, вообще не даёт номера: curl вывел `curl: (56) Proxy CONNECT aborted`, Requests выбросил `ConnectionError` с `RemoteDisconnected('Remote end closed connection without response')`, HTTPX — `RemoteProtocolError: Server disconnected without sending a response.`, а Chromium — `net::ERR_EMPTY_RESPONSE`.

## Проверка одним запросом curl

Выведите оба кода статуса для проблемного URL через тот же прокси:

```sh
curl --disable -sS -o /dev/null -x "$PROXY_URL" \
  -w 'connect=%{http_connect} http=%{http_code} exit=%{exitcode}\n' \
  https://example.com/
```

- `connect=502 http=000`: прокси отказал в туннеле; смотрите причины ниже.
- `connect=200 http=502`: 502 ответил сайт; смотрите раздел [если 502 отправил сайт](#если-502-отправил-сайт).
- `connect=000` и `Proxy CONNECT aborted`: прокси закрыл соединение без статуса. Сначала проверьте порт.

## Причины на стороне прокси

**Сайт недоступен с выходного узла (502).** Прокси не смог подключиться дальше; на стенде отклонённое соединение превратилось в `502 Bad Gateway` во всех клиентах. Запросите тот же URL без прокси и через другой выходной узел или страну. Если не работает только один узел, сайт оттуда недоступен или блокирует эту сеть, поэтому смените узел. Если не работает ни один, проверьте хост и порт в строке CONNECT.

**Выходной узел офлайн или меняет IP (503, иногда 502).** Шлюзу некуда отправить запрос. Повторяйте идемпотентные запросы с паузами, как показано ниже, и проверьте состояние узла в панели провайдера.

**Прокси не дождался (504).** Истёк собственный срок, который прокси даёт себе на подключение к сайту. Прокси на стенде ждал 3 секунды, и все клиенты получили ошибку через 3,0–3,5 секунды. Таймаут клиента должен быть больше этого срока, иначе вместо 504 вы увидите собственный таймаут; [руководство по таймаутам прокси](/ru/guides/proxy-timeout-troubleshooting) помогает их различить.

**Не тот порт или протокол.** Мы направили все клиенты, как на HTTP-прокси, на порт, который понимает только SOCKS5 (pproxy 2.7.9). Сервер закрыл соединение без ответа, так что никакого 502 не было: curl 8.5.0 и 8.18.0 вывели `curl: (56) Proxy CONNECT aborted`, aiohttp выбросил `ServerDisconnectedError`, а fetch в Node не завершился, пока не сработал его 10-секундный таймаут. Копируйте схему, хост и порт со страницы настройки у провайдера. URL прокси `https://` на обычном HTTP-порту ломается по-другому; смотрите [SSL WRONG_VERSION_NUMBER за прокси](/ru/guides/fix-ssl-wrong-version-number-proxy).

**Нехватка мощности у провайдера.** Перегруженный шлюз может отвечать 502 или 503 на новые туннели. Снизьте параллельность, сделайте паузу и отправьте провайдеру время сбоев в UTC.

На том же шаге 407 означает проблему аутентификации ([как исправить ошибку прокси 407](/ru/guides/fix-proxy-error-407)), а 403 — намеренный отказ ([CONNECT tunnel failed, response 403](/ru/blog/connect-tunnel-failed-403)).

## Мобильные прокси и смена IP

В мобильном прокси выходной узел — это устройство в сети оператора связи. Пока оно меняет IP, рабочего выхода может на мгновение не быть; в зависимости от шлюза клиент тогда видит 502 или 503 на CONNECT либо закрытое соединение и сообщает о них так, как описано выше. Реальную смену IP мы не измеряли, поэтому длительностей в этом руководстве нет. Если вы запускаете смену сами, приостановите запросы, пока не пройдёт дешёвый тестовый запрос.

Стенд имитировал выходной узел, недоступный 4 секунды, и отправлял один запрос Requests в секунду. Секунды с 0 по 3 завершились ошибкой `Tunnel connection failed: 503 Service Unavailable`; начиная с 4-й секунды каждый запрос возвращал 200. 4 секунды — настройка стенда: опыт показывает форму смены IP, а не её длительность.

Встроенные повторы обращаются с двумя сторонами по-разному. `curl --retry 2` отправил CONNECT на сбойный прокси один раз и остановился, но трижды запросил у сайта его 502; с `--retry-all-errors` он повторял и CONNECT. `Retry(total=2, status_forcelist=[502, 503, 504])` из urllib3 повторял и то и другое. Fetch в Node ничего не повторял после статуса, но когда прокси закрывал соединение без статуса, переподключился 160 357 раз за 10 секунд, пока его не остановил `AbortSignal.timeout`. Всегда передавайте signal.

Повторяйте только GET-запросы. Неудавшийся CONNECT до сайта не дошёл, но 502 от сайта может прийти уже после того, как сайт выполнил работу, и повторённый POST выполнится дважды; см. [один потерянный ответ — два созданных задания](/ru/blog/proxy-retries-duplicate-jobs). Эта функция повторяет GET после 502, 503 или 504 от прокси или сайта с ограниченными паузами со случайным разбросом и останавливается на всём остальном, например на 407:

```python
import random, re, time
import requests

RETRYABLE = {502, 503, 504}
TUNNEL_STATUS = re.compile(r"Tunnel connection failed: (\d{3})")

def get_with_retry(session, url, attempts=5, base_delay=1.0, max_delay=8.0, **kwargs):
    for attempt in range(1, attempts + 1):
        try:
            response = session.get(url, **kwargs)
        except requests.exceptions.ProxyError as exc:
            match = TUNNEL_STATUS.search(str(exc))  # Requests reports the CONNECT status only as text
            if match is None or int(match.group(1)) not in RETRYABLE or attempt == attempts:
                raise
        else:
            if response.status_code not in RETRYABLE or attempt == attempts:
                return response
        time.sleep(min(max_delay, base_delay * 2 ** (attempt - 1)) * random.uniform(0.5, 1.0))
```

В записанном прогоне она пережила 4-секундное окно недоступности на четвёртой попытке, через 5,7 секунды. С сайтом, который продолжал отвечать 502, она сдалась после пяти попыток и 9,9 секунды и вернула 502.

## Если 502 отправил сайт

Если туннель открылся, прокси свою работу сделал: 502 пришёл от шлюза, балансировщика нагрузки или CDN сайта, которые не получили пригодного ответа от приложения за ними. Смена прокси или IP этого не исправит. Запросите URL без прокси; если и так не работает, подождите и повторяйте GET с помощью функции выше. Если ошибка возникает только через прокси, сайт может отдавать ошибки этой сети; сравните тело и заголовки с прямым запросом, прежде чем менять узел.

## Как воспроизвести стенд

В [папке загрузки](/downloads/fix-proxy-tunnel-502-503/README.md) лежат `lab.mjs` (прокси на `127.0.0.1`, который отвечает на CONNECT кодом 502, 503 или 504 либо обрывает соединение, и TLS-сервер, который сам отвечает 502), по одному скрипту на клиент, `wrong_port.mjs`, `node_checks.mjs` и `retry_get.py` с функцией выше. В [results.json](/downloads/fix-proxy-tunnel-502-503/results.json) записаны версии: curl 8.5.0 и 8.18.0, Python 3.14.4, Requests 2.34.2, urllib3 2.8.0, HTTPX 0.28.1, aiohttp 3.14.5, Node.js 24.22.1 с undici 7.30.1 и Playwright 1.63.0 с Chromium 153. Не проверялись: macOS и Windows, SOCKS- и HTTPS-прокси и реальные шлюзы провайдеров.

В агенте для программирования [Proxy Toolkit MCP](/mcp) помогает диагностировать ошибки; передайте ему клиент и очищенный текст ошибки, но никогда не учётные данные.

[Мобильные прокси](/pricing) ipvolt — это выделенные устройства в сетях операторов; вы меняете IP по запросу или по расписанию, так что смена IP не застанет вас врасплох.

## Источники и дополнительное чтение

- [RFC 9110: CONNECT](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect)
- [RFC 9110: 502 Bad Gateway](https://www.rfc-editor.org/rfc/rfc9110.html#name-502-bad-gateway)
- [RFC 9110: 503 Service Unavailable](https://www.rfc-editor.org/rfc/rfc9110.html#name-503-service-unavailable)
- [RFC 9110: 504 Gateway Timeout](https://www.rfc-editor.org/rfc/rfc9110.html#name-504-gateway-timeout)
- [curl manual: --retry](https://curl.se/docs/manpage.html#--retry)
- [curl manual: --retry-all-errors](https://curl.se/docs/manpage.html#--retry-all-errors)
- [urllib3 documentation: Retry](https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Retry)
- [Requests documentation: proxies](https://requests.readthedocs.io/en/latest/user/advanced/#proxies)
- [HTTPX documentation: proxies](https://www.python-httpx.org/advanced/proxies/)
- [aiohttp documentation: proxy support](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support)
- [Playwright: HTTP proxy](https://playwright.dev/docs/network#http-proxy)
- [Node.js CLI documentation: NODE_USE_ENV_PROXY](https://nodejs.org/api/cli.html#node_use_env_proxy1)
- [pproxy on PyPI](https://pypi.org/project/pproxy/)

## Связанные руководства

- [Как исправить ошибку прокси 407, не гадая](https://ipvolt.com/ru/guides/fix-proxy-error-407.md)
- [Как исправить ERR_TUNNEL_CONNECTION_FAILED в Playwright и Puppeteer](https://ipvolt.com/ru/guides/fix-err-tunnel-connection-failed.md)
- [Диагностика таймаутов прокси: по одному этапу за раз](https://ipvolt.com/ru/guides/proxy-timeout-troubleshooting.md)

## О ipvolt

Примеры используют обобщённые настройки прокси со ссылками на оригинальную техническую документацию. Поведение конкретного продукта уточняйте у своего провайдера. ipvolt пока в разработке.

[Читать оригинал на английском](https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md)

## Узнайте, когда откроется доступ.

ipvolt · В разработке

Мы строим прокси-инфраструктуру для разработчиков и команд, работающих с данными. Оставьте email, чтобы получить уведомление, когда ipvolt будет готов.

Одно письмо, когда откроется доступ. Больше ничего.

[Получить ранний доступ](https://ipvolt.com/ru/guides/fix-proxy-tunnel-502-503#waitlist-closing)

[Конфиденциальность](https://ipvolt.com/privacy)

