# Как исправить ERR_TUNNEL_CONNECTION_FAILED в Playwright и Puppeteer

Source: https://ipvolt.com/ru/guides/fix-err-tunnel-connection-failed
Markdown: https://ipvolt.com/ru/guides/fix-err-tunnel-connection-failed.md
Language: ru

[ipvolt — главная](https://ipvolt.com/ru.md) / [Руководства](https://ipvolt.com/ru/guides.md) / Как исправить ERR_TUNNEL_CONNECTION_FAILED в Playwright и Puppeteer

Диагностика
Проверено: 2026-09-17
Опубликовано: 2026-09-17
9 мин чтения
Автор: ipvolt

Разбираем ERR_TUNNEL_CONNECTION_FAILED и ERR_PROXY_CONNECTION_FAILED по проверенной матрице отказов прокси и показываем, как узнать статус CONNECT, скрытый Chromium.

`net::ERR_TUNNEL_CONNECTION_FAILED` означает, что Chromium дошёл до вашего прокси, запросом `CONNECT` попросил его открыть туннель к HTTPS-назначению, и прокси ответил чем-то, кроме успеха. `net::ERR_PROXY_CONNECTION_FAILED` означает, что Chromium до этого не дошёл: он вообще не смог установить соединение с прокси. Оба кода приходят из сетевого стека Chromium, поэтому Playwright, Puppeteer и любой другой инструмент, управляющий Chromium, сообщают те же строки, обычно в виде `page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://...`.

Самое досадное — то, что Chromium опускает. Прокси, который отказывает в туннеле с 403, прокси, который ограничивает вам частоту запросов с 429, и прокси, у которого не работает upstream с 502, — все дают одинаковый `ERR_TUNNEL_CONNECTION_FAILED`. Это руководство показывает, какое поведение прокси даёт какую ошибку в Playwright, Puppeteer и curl, — воспроизведённую на небольших контролируемых прокси, а не собранную по форумным темам, — а затем даёт короткую процедуру восстановления статуса, который браузер скрывает.

## Видите это в Chrome или Edge без всякого кода?

В обычном окне браузера смысл тот же. Chrome и Edge используют сетевой стек Chromium и по умолчанию берут настройки прокси из операционной системы, поэтому ошибка говорит о том, что где-то настроен прокси и он отказался открывать туннель (`ERR_TUNNEL_CONNECTION_FAILED`) либо оказался вовсе недоступен (`ERR_PROXY_CONNECTION_FAILED`). Сам сайт не лежит; браузер просто не прошёл дальше прокси. Обычные источники такой конфигурации — VPN-клиент, который на время подключения устанавливает системный прокси, браузерное расширение прокси или VPN, корпоративная политика или PAC-скрипт на управляемом устройстве, либо прокси, введённый вручную и забытый.

Как это исправить, в порядке, который быстрее всего находит причину:

- Откройте `chrome://net-internals/#proxy` (или `edge://net-internals/#proxy`), чтобы увидеть действующие настройки прокси, которые браузер использует прямо сейчас. Если вы не ожидали там увидеть прокси, в этом и проблема.
- Отключите VPN или расширения прокси, перезагрузите страницу и сравните. Если страница загрузилась, прокси VPN или расширения отказывал в туннеле или был недоступен.
- На рабочем или учебном устройстве правила администратора прокси определяют, какие сайты разрешены. `ERR_TUNNEL_CONNECTION_FAILED` на HTTPS-сайте, заблокированном политикой, — ожидаемое поведение, и изменить его может только администратор.
- Если страницы `http://` загружаются, а `https://` — нет, прокси отказывает в `CONNECT` к порту 443. Это случай туннеля из матрицы ниже, и причину называет собственный код статуса прокси.

Остальная часть руководства написана для разработчиков, которые сами настроили прокси в Playwright или Puppeteer, но каждая строка ошибки означает ровно то же самое и в адресной строке.

## Две ошибки, два этапа

Для HTTPS-назначения через HTTP-прокси Chromium разрешает имя прокси, открывает к нему TCP-соединение, отправляет `CONNECT host:443`, ждёт ответ `2xx` и только затем начинает TLS-рукопожатие с целевым сервером внутри туннеля. Два кода ошибок отмечают две разные точки этого пути:

- **`ERR_PROXY_CONNECTION_FAILED`**: имя прокси не разрешилось, никто не принял TCP-соединение или соединение с прокси оборвалось до обмена какими-либо HTTP-данными. Частый вариант, который создают себе сами: написать `https://` перед шлюзом, который говорит только на обычном HTTP, — тогда Chromium пытается выполнить TLS-рукопожатие с сервером, ожидающим открытый текст.
- **`ERR_TUNNEL_CONNECTION_FAILED`**: TCP-соединение установлено и прокси ответил на `CONNECT`, но не успешным статусом. Chromium отбрасывает код статуса, фразу-причину и любое тело, которое отправил прокси.

Всё остальное, что вы можете увидеть (`ERR_CONNECTION_RESET`, `ERR_INVALID_HTTP_RESPONSE`, `ERR_SOCKS_CONNECTION_FAILED`, обычный таймаут навигации), относится к другому этапу и рассматривается ниже.

## Как выглядит каждый отказ прокси

В таблице записано, что сообщил каждый клиент при одном намеренно заданном поведении прокси. Playwright использовал опцию запуска `proxy`; Puppeteer — сырые флаги Chromium (`--proxy-server`) с `page.authenticate` для учётных данных; curl — `-x` с `--proxy-user`. Все три работали с одной и той же сборкой Chromium 153 или curl 8.18 под Linux; подробности в разделе о методике.

| Поведение прокси | Playwright 1.63 (Chromium 153) | Puppeteer 25 (тот же Chromium) | curl 8.18 |
| --- | --- | --- | --- |
| Имя прокси не разрешается | `ERR_PROXY_CONNECTION_FAILED` | то же | `(5) Could not resolve proxy` |
| На порту прокси никто не слушает | `ERR_PROXY_CONNECTION_FAILED` | то же | `(7) Failed to connect` |
| Схема `https://`, но прокси говорит на обычном HTTP | `ERR_PROXY_CONNECTION_FAILED` | то же | `(35) TLS connect error` |
| Прокси принимает TCP и никогда не отвечает | таймаут навигации | таймаут навигации | `(28) Connection timed out` |
| Прокси принимает TCP и сразу закрывает соединение | `ERR_CONNECTION_RESET` | то же | `(56) Proxy CONNECT aborted` или `(56) Recv failure: Connection reset by peer` |
| Порт отвечает, но не по HTTP | `ERR_INVALID_HTTP_RESPONSE` | то же | `(56) Proxy CONNECT aborted` |
| На CONNECT ответ 403 | `ERR_TUNNEL_CONNECTION_FAILED` | то же | `(7) CONNECT tunnel failed, response 403` |
| На CONNECT ответ 429 | `ERR_TUNNEL_CONNECTION_FAILED` | то же | `(7) CONNECT tunnel failed, response 429` |
| На CONNECT ответ 502 или 503 | `ERR_TUNNEL_CONNECTION_FAILED` | то же | `(7) CONNECT tunnel failed, response 502` или `503` |
| На CONNECT ответ 407, учётные данные не заданы | навигация завершается ответом со статусом 407, затем `ERR_TUNNEL_CONNECTION_FAILED` на запросе | `ERR_INVALID_AUTH_CREDENTIALS` | `(7) CONNECT tunnel failed, response 407` |
| На CONNECT ответ 407, неверные учётные данные | навигация завершается ответом со статусом 407, затем `ERR_TUNNEL_CONNECTION_FAILED` на запросе | навигация завершается ответом со статусом 407 и страницей ошибки Chromium, затем `ERR_HTTP_RESPONSE_CODE_FAILURE` | `(7) CONNECT tunnel failed, response 407` |
| Верные учётные данные | 200 от целевого сервера | 200 | 200, `http_connect` 200 |
| На CONNECT ответ 200, затем прокси обрывает туннель | `ERR_CONNECTION_CLOSED` или `ERR_CONNECTION_RESET` | `ERR_CONNECTION_RESET` | `(35) Send failure: Broken pipe` |
| Схема `socks5://` против HTTP-прокси | `ERR_SOCKS_CONNECTION_FAILED` | то же | `(97) Received invalid version in initial SOCKS5 response` |
| `socks5://` с именем пользователя и паролем | отказ при запуске: `Browser does not support socks5 proxy authentication` | не проверялось | не проверялось |
| Обычное `http://` назначение, прокси отвечает 403 или 407 | ошибки нет: собственная страница 403 или 407 прокси становится ответом навигации | то же | 403 или 407 с `http_connect` 000 |

Три строки заслуживают отдельного внимания. Любой неуспешный статус `CONNECT` от 403 до 503 схлопывается в одну ошибку браузера, поэтому по одному лишь браузеру нельзя понять, заблокированы ли вы, ограничены по частоте запросов или имеете дело с неработающим upstream. 407 — единственный статус, который Chromium обрабатывает особым образом, и Playwright с Puppeteer показывают его по-разному. А обычное `http://` назначение никогда не даёт ошибку туннеля, потому что туннеля нет: отказ прокси приходит как обычный ответ со статусом и телом прокси, из-за чего один и тот же скрипт может «работать» на HTTP-тестовой странице и падать на нужном вам HTTPS-сайте.

## Восстановите статус CONNECT с помощью curl

curl сохраняет статус, который Chromium выбрасывает. Выполните один ограниченный запрос к тому же шлюзу, целевому серверу и с теми же учётными данными, что и ваш браузерный скрипт, и выведите и статус целевого сервера, и статус `CONNECT`. Команда читает `PROXY_URL`, `PROXY_USERNAME` и `PROXY_PASSWORD` из окружения, поэтому пароль никогда не попадает в аргумент shell или в историю команд; для подстановки переменных требуется curl 8.3 или новее.

```sh
: "${PROXY_URL:?Set the gateway as http://host:port (no credentials in the URL)}"
CHECK_URL=${CHECK_URL:-https://example.com/}
curl --disable --silent --show-error --output /dev/null \
  --noproxy '' --proxy "$PROXY_URL" --proxy-basic \
  --variable %PROXY_USERNAME --variable %PROXY_PASSWORD \
  --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \
  --max-time 15 \
  --write-out 'destination=%{http_code} connect=%{http_connect} exit=%{exitcode}\n' \
  "$CHECK_URL"
```

`connect=200` вместе со статусом целевого сервера означает, что туннель работает и проблема браузера в чём-то другом. Ненулевое значение `connect` — это статус, который скрыл Chromium:

- **407**: прокси хочет учётные данные, которые он не принял. Проверьте аккаунт или субпользователя, percent-encoding и то, аутентифицирует ли этот шлюз по паролю или по разрешённому исходному IP-адресу. [Руководство по ошибке 407](/ru/guides/fix-proxy-error-407) проходит этот порядок по шагам.
- **403**: прокси принял соединение, но отказывает именно в этом туннеле. Типичные причины — целевой сервер или порт вне разрешённого провайдером списка, ограничение аккаунта либо параметр страны или сессии, который шлюз отвергает.
- **429**: ограничения параллелизма или частоты запросов на прокси. Поищите заголовок `Retry-After` в выводе `curl -v` и уменьшите число параллельных браузеров, прежде чем повторять.
- **502, 503, 504**: прокси не смог достучаться до исходящего выхода или выбрать его. Немедленный повтор редко помогает; запишите время и спросите у провайдера, что зафиксировал в логах его шлюз.

`connect=000` с кодом выхода curl, отличным от 0, означает, что сбой произошёл до какого-либо ответа на `CONNECT`, что соответствует строкам `ERR_PROXY_CONNECTION_FAILED` и сброса соединения выше. [Руководство по таймаутам](/ru/guides/proxy-timeout-troubleshooting) показывает, как измерить каждый этап, когда сбой медленный, а не мгновенный.

## Playwright: 407 не выбрасывает исключение

Без учётных данных прокси или с неверными `page.goto` в записанном прогоне не отклонялся. Он завершался ответом со статусом 407 и `statusText` `Proxy Authentication Required`, с читаемым на этом ответе заголовком `Proxy-Authenticate` от прокси и пустым телом; для той же навигации срабатывало событие `requestfailed` с `ERR_TUNNEL_CONNECTION_FAILED`. Поэтому скрипт, который лишь дожидается `goto` и идёт дальше, продолжает работать с пустой страницей. Проверяйте `response.ok()` и считайте 407 проблемой прокси, а не целевого сервера:

```js
import { chromium } from 'playwright';

function required(name) {
  const value = process.env[name];
  if (!value) throw new Error('Missing environment variable: ' + name);
  return value;
}

const browser = await chromium.launch({
  proxy: {
    server: required('PROXY_URL'),           // http://host:port, no credentials in the URL
    username: required('PROXY_USERNAME'),
    password: required('PROXY_PASSWORD'),
  },
});
try {
  const page = await browser.newPage();
  page.on('requestfailed', (request) => {
    console.error('request failed:', request.failure()?.errorText, request.url());
  });
  const response = await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' });
  if (!response) throw new Error('No navigation response');
  if (response.status() === 407) throw new Error('Proxy rejected the credentials (407)');
  if (!response.ok()) throw new Error('Destination answered ' + response.status());
} finally {
  await browser.close();
}
```

Задавайте учётные данные прокси в `proxy.username` и `proxy.password`. В записанном прогоне учётные данные, переданные через опцию контекста `httpCredentials`, тоже удовлетворяли вызов прокси, потому что Playwright отвечает на запрос аутентификации Chromium из любого источника. Не полагайтесь на это: `httpCredentials` предназначены для целевого сервера, и их повторное использование для прокси отправляет логин от сайта оператору прокси.

Ещё две детали Playwright из прогона. Playwright сам добавляет `<-loopback>` в список обхода, поэтому назначение на `localhost` или `127.0.0.1` идёт через прокси; сырой Chromium делает наоборот (см. раздел о Puppeteer). А сервер `socks5://` с именем пользователя и паролем отклоняется ещё до запуска браузера с сообщением `Browser does not support socks5 proxy authentication`. В Chromium нет поддержки аутентификации SOCKS5, поэтому решение — HTTP-шлюз с Basic-аутентификацией или списком разрешённых IP-адресов, а не другая настройка SOCKS. [Руководство HTTP vs SOCKS5](/ru/guides/http-vs-socks5-proxies) описывает, что меняется между ними.

## Puppeteer: аутентифицируйтесь до первой навигации

Puppeteer передаёт прокси в Chromium флагом и отвечает на вызовы 407 только после вызова `page.authenticate`. Без него записанный прогон давал `net::ERR_INVALID_AUTH_CREDENTIALS` — код, который многие никак не связывают с прокси. При неверных учётных данных `goto` завершался ответом со статусом 407 и встроенной страницей ошибки Chromium в качестве тела, плюс событием `requestfailed` с `ERR_HTTP_RESPONSE_CODE_FAILURE`.

```js
import puppeteer from 'puppeteer';

function required(name) {
  const value = process.env[name];
  if (!value) throw new Error('Missing environment variable: ' + name);
  return value;
}

const browser = await puppeteer.launch({
  args: [
    '--proxy-server=' + required('PROXY_URL'),   // http://host:port
    '--proxy-bypass-list=<-loopback>',          // only if local destinations must use the proxy
  ],
});
try {
  const page = await browser.newPage();
  await page.authenticate({
    username: required('PROXY_USERNAME'),
    password: required('PROXY_PASSWORD'),
  });
  page.on('requestfailed', (request) => {
    console.error('request failed:', request.failure()?.errorText, request.url());
  });
  const response = await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' });
  if (!response) throw new Error('No navigation response');
  if (response.status() === 407) throw new Error('Proxy rejected the credentials (407)');
  if (!response.ok()) throw new Error('Destination answered ' + response.status());
} finally {
  await browser.close();
}
```

Здесь важны два значения Chromium по умолчанию. Во-первых, Chromium обходит прокси для `localhost`, `127.0.0.1` и `[::1]`, если список обхода не содержит `<-loopback>`. В прогоне скрипт Puppeteer, направленный на прокси, который отклонял каждый туннель, всё равно загрузил локальную HTTPS-страницу со статусом 200, потому что к прокси никто не обращался. Тест, который «проходит» на локальном сервере, ничего не доказывает о прокси. Во-вторых, сырой Chromium, запущенный с `--proxy-server`, направлял через прокси и собственный фоновый трафик: в записанном логе прокси видны `GET` к `clients2.google.com` и `CONNECT` к `update.googleapis.com:443` до навигации на страницу. Ожидайте эти имена хостов в логах провайдера и в учитываемом трафике и не принимайте их сбои за сбой вашей навигации. Флаги запуска Playwright в том же прогоне такого трафика не создавали.

## Ошибки, которые не являются ошибками туннеля

- **`ERR_CONNECTION_RESET` или `ERR_CONNECTION_CLOSED` сразу после подключения**: прокси принял TCP-соединение и оборвал его — либо до ответа на `CONNECT`, либо сразу после 200. Провайдеры делают так, когда выход недоступен или соединение ограничивается по частоте на уровне сокета. curl для того же поведения сообщает `Proxy CONNECT aborted` или `Send failure: Broken pipe`.
- **`ERR_INVALID_HTTP_RESPONSE`**: на этом порту что-то ответило, но не по HTTP. Обычно номер порта принадлежит SOCKS-слушателю, слушателю только для TLS или другому сервису.
- **`ERR_SOCKS_CONNECTION_FAILED`**: вы настроили `socks5://`, а сервер говорил на HTTP. Смените схему на документированный протокол шлюза, прежде чем менять что-либо ещё.
- **Таймаут навигации без сетевой ошибки**: прокси принял соединение и так и не ответил. Увеличение таймаута не поможет; проверьте порт и протокол с помощью curl, который в той же ситуации завершается по таймауту с `(28)`.
- **`ERR_PROXY_CONNECTION_FAILED` на шлюзе, который работает в curl**: сравните схему. Chromium пытается установить TLS для прокси `https://`, а большинство шлюзов — это обычные конечные точки `http://`, которые несут HTTPS-назначения внутри туннеля.

## Порядок диагностики

1. Воспроизведите с помощью curl с теми же шлюзом, целевым сервером и учётными данными и прочитайте `http_connect`. Это меньше чем за минуту превращает односложную ошибку браузера в фактический статус прокси.
2. Сверьте схему прокси (`http://`, `https://` или `socks5://`) с актуальными инструкциями провайдера. Две из трёх строк `ERR_PROXY_CONNECTION_FAILED` выше — ошибки в схеме.
3. Размещайте учётные данные там, где их ожидает инструмент: `proxy.username` и `proxy.password` в Playwright, `page.authenticate` до первой навигации в Puppeteer. В обоих явно проверяйте `response.status() === 407`.
4. Тестируйте HTTPS-назначение, а не HTTP. HTTP-назначения пропускают `CONNECT` и прячут проблемы туннеля за обычными ответами прокси.
5. Проверьте правила обхода. Локальные и внутренние назначения в сыром Chromium обходят прокси, а корпоративные настройки или настройки прокси из окружения могут переопределить то, что вы передали.
6. Сообщайте версии клиентов, время в UTC, хост и порт шлюза, имя целевого хоста и значение curl `http_connect`. Не включайте пароли, URL с учётными данными и сырые трассировки; в [руководстве по ошибке 407](/ru/guides/fix-proxy-error-407) есть шаблон очищенного отчёта.

## Методика и файлы для загрузки

ipvolt выполнил воспроизведение 17 сентября 2026 года на Linux-хосте с Node.js 24.20.0, Playwright 1.63.0 (Chromium 153.0.8010.12, headless), puppeteer-core 25.11.0, управляющим той же сборкой Chromium, и curl 8.18.0. Каждый «прокси» был небольшим сервером на Node.js на 127.0.0.1 ровно с одним поведением; назначением служил локальный HTTPS-сервер с одноразовым самоподписанным сертификатом, поэтому в браузерных случаях ошибки сертификата целевого сервера игнорировались, что не влияет на то, как Chromium общается с прокси. Firefox и WebKit не проверялись, коммерческий шлюз не задействовался: таблица описывает реакцию Chromium на поведение прокси, а не политику какого-либо провайдера.

[Архив лаборатории](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/chromium-proxy-tunnel-errors.zip) содержит [скрипт лаборатории](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/tunnel-errors-lab.mjs), [манифест пакета](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/package.json), [README](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/README.md) и [записанные результаты](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/results.json), включая лог на стороне прокси, который показывает, дошёл ли каждый клиент до прокси и пришли ли учётные данные. Он работает только на loopback и не требует аккаунта прокси.

Если хотите узнать, когда откроется доступ к ipvolt, [присоединяйтесь к списку раннего доступа](https://ipvolt.com/#waitlist-closing). Одно письмо, когда доступ откроется. Больше ничего. Эти примеры — клиентская диагностика, а не документация доступной конечной точки ipvolt.

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

- [Chromium network error list (net_error_list.h)](https://chromium.googlesource.com/chromium/src/+/main/net/base/net_error_list.h)
- [Chromium proxy support and bypass rules (proxy.md)](https://chromium.googlesource.com/chromium/src/+/main/net/docs/proxy.md)
- [Playwright: HTTP proxy configuration](https://playwright.dev/docs/network#http-proxy)
- [Puppeteer: page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate)
- [curl: --write-out variables including http_connect](https://curl.se/docs/manpage.html#-w)
- [RFC 9110: the CONNECT method](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect)
- [RFC 9110: 407 Proxy Authentication Required](https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-req)

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

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

## О ipvolt

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

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

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

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

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

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

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

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

