С чего начать
Все способы выбора прокси в curl — от одного флага -x до переменных окружения — с деталями аутентификации, SOCKS5 и туннеля, от которых зависит, выполнится ли запрос.
Прокси для одного запроса через -x
Опция -x, в длинной форме --proxy, направляет один запрос curl через прокси. Укажите схему, хост и порт прокси. Если схема опущена, curl подставляет http://, а если опущен порт — 1080, поэтому указывайте и то и другое явно.
Схема описывает соединение с прокси, а не с целевым сервером. Для целевого адреса https:// через обычный HTTP-прокси по-прежнему используется -x http://host:port; curl открывает через него туннель CONNECT. Пишите -x https://host:port только тогда, когда провайдер терминирует TLS на самом прокси. curl также принимает здесь socks4://, socks4a://, socks5:// и socks5h://.
Команда ниже сохраняет две привычки из остальной части руководства: --disable игнорирует curlrc, который мог бы добавить собственный прокси, а --noproxy '' отменяет любое унаследованное исключение no_proxy, так что запрос действительно уходит через указанный вами шлюз. proxy.example.invalid намеренно не резолвится; подставьте шлюз вашего провайдера. Без --compressed команда не отправляет заголовок Accept-Encoding, поэтому сервер, который сжимает ответ только по запросу, вернёт через прокси всю страницу без сжатия; если вы платите за гигабайт, посмотрите, какие клиенты не запрашивают сжатие и как проверить байты.
curl -x · один запрос через прокси
curl --disable --noproxy '' \
-x http://proxy.example.invalid:8080 \
https://example.com/Аутентификация на прокси: -U, --proxy-user и 407
Учётные данные прокси отделены от учётных данных целевого сервера. -U или --proxy-user отправляет их прокси; -u или --user отправляет их целевому серверу. Если их перепутать, вы получите 407 от прокси или 401 от целевого сервера, хотя пароль верный.
Учётные данные можно также встроить в URL прокси в виде http://user:password@host:port. Сначала закодируйте зарезервированные символы через percent-encoding: символ @ в пароле должен превратиться в %40, иначе curl воспримет его как начало хоста. По умолчанию для аутентификации на прокси используется схема Basic; --proxy-digest, --proxy-ntlm и --proxy-anyauth выбирают другие схемы, если провайдер их документирует.
Если ввести пароль прямо в команду, он может сохраниться в истории оболочки и попадёт в начальные аргументы процесса. Переменная позволяет не писать пароль в самой команде, если заполнить её приватно, но --proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" всё равно раскрывает его в аргумент до запуска curl. В поддерживаемых системах curl скрывает аргумент после запуска; более поздний список процессов может не показать это раскрытие. См. документацию curl о proxy-user.
Для скриптов с curl 8.3.0 или новее пример ниже импортирует экспортированные переменные внутри curl. Передавайте их через менеджер секретов, отключайте трассировку оболочки и не вставляйте команды export с секретами в историю. Пароль не попадёт в аргументы curl, но унаследованное окружение и память остаются доступны учётным записям с правом их просмотра. Для интерактивной проверки --proxy-user username без двоеточия запрашивает пароль отдельно.
Обработка аргументов не шифрует соединение с прокси. Данные HTTP Basic, отправленные прокси http://, не защищены последующим HTTPS-туннелем к целевому серверу. Используйте шлюз https://, если провайдер его поддерживает, и сохраняйте проверку сертификата прокси.
- connect=407 или сообщение Received HTTP code 407 from proxy after CONNECT означает, что прокси отклонил учётные данные или не получил их вовсе. Проверьте значение -U, кодирование и формат имени пользователя у провайдера.
- 401 от целевого сервера при успешном туннеле — проблема целевого сервера; этап прокси уже работает.
- Если провайдер кодирует страну, сессию или протокол в имени пользователя, следуйте его документированному формату. --proxy-user ожидает имя и пароль, разделённые двоеточием; это не этап URL-кодирования.
curl 8.3+ · импорт учётных данных внутри curl
: "${PROXY_USERNAME:?}" "${PROXY_PASSWORD:?}"
curl --disable --noproxy '' \
-x http://proxy.example.invalid:8080 \
--variable %PROXY_USERNAME \
--variable %PROXY_PASSWORD \
--expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \
https://example.com/Переменные окружения: http_proxy, https_proxy, no_proxy и .curlrc
Без -x curl ищет прокси в окружении. Переменную http_proxy он читает только в нижнем регистре, потому что имя в верхнем регистре может быть установлено заголовками CGI-запроса; https_proxy или HTTPS_PROXY, all_proxy или ALL_PROXY, а также no_proxy или NO_PROXY он принимает в обоих вариантах. Переменная выбирается по схеме целевого адреса: для https:// используется https_proxy, поэтому одного http_proxy недостаточно для настройки HTTPS-маршрута; на него всё ещё могут влиять ALL_PROXY или другие настройки. curl_cffi, Python-обёртка над libcurl, следует тому же правилу нижнего регистра; оно записано в руководстве Прокси в curl_cffi вместе с исключениями, которые вызывают отклонённый CONNECT и неудачное рукопожатие SOCKS.
no_proxy — список имён хостов или суффиксов доменов через запятую, которые обходят прокси; одиночная * полностью отключает проксирование. -x заменяет шлюз, выбранный переменными прокси, но no_proxy всё ещё может направить запрос в обход него. --noproxy переопределяет no_proxy; пустое значение --noproxy отменяет унаследованные исключения.
Файл ~/.curlrc может задавать proxy = "http://host:port" для каждого вызова — это удобно на рабочей станции и неожиданно внутри контейнера или CI-задания. Запускайте curl с --disable или его короткой формой -q первым аргументом, когда скрипт должен его игнорировать.
http_proxy и https_proxy · сессия оболочки
export http_proxy='http://proxy.example.invalid:8080'
export https_proxy='http://proxy.example.invalid:8080'
export no_proxy='localhost,127.0.0.1,.internal.example'
curl https://example.com/ # uses https_proxy
curl --noproxy '*' https://example.com/ # bypasses the proxy onceSOCKS5 в curl: socks5 против socks5h
curl работает с SOCKS через ту же опцию -x. socks5:// резолвит имя целевого хоста на вашей машине и отправляет прокси IP-адрес. socks5h:// отправляет имя хоста и позволяет прокси резолвить его самому — это то, что нужно, когда целевой адрес должен резолвиться из сети прокси или когда локальный DNS вообще не должен видеть целевой адрес. Длинные опции --socks5 и --socks5-hostname эквивалентны.
Аутентификация SOCKS5 по имени пользователя и паролю использует ту же опцию --proxy-user. У SOCKS нет HTTP-статуса CONNECT; отклонённое SOCKS-рукопожатие может вернуть код выхода 97 с пояснением вместо HTTP 407. В этом совместимом примере оболочка всё ещё раскрывает учётные данные в начальные аргументы; чтобы избежать этого, используйте показанный выше импорт curl 8.3+.
curl socks5h · DNS на стороне прокси
curl --disable --noproxy '' \
-x socks5h://proxy.example.invalid:1080 \
--proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" \
https://example.com/Целевые адреса HTTPS: туннель CONNECT и -v
Для целевого адреса https:// через HTTP-прокси curl сначала отправляет прокси CONNECT example.com:443. После успешного ответа CONNECT curl начинает TLS с целевым сервером внутри туннеля. Обычный пересылающий прокси не может прочитать этот зашифрованный HTTP-обмен; прокси с перехватом TLS, которому доверяет клиент, — другой случай. Используйте -v, чтобы увидеть оба этапа: ответ CONNECT приходит раньше заголовков целевого сервера. -p или --proxytunnel включает такой туннель и для цели http://.
Для обычного целевого адреса http:// туннеля нет. curl отправляет прокси полный URL, прокси загружает его, и заголовки ответа, которые вы видите, могут прийти от любой из сторон. Когда код статуса нужно отнести к определённому слою, предпочитайте туннелируемый вариант и читайте статус CONNECT отдельно через переменную %{http_connect} в --write-out.
С прокси https:// curl проверяет сертификат прокси так же, как и сертификат целевого сервера. --proxy-cacert задаёт собственный набор доверенных сертификатов для прокси; оставляйте обе проверки включёнными вместо того, чтобы прибегать к --proxy-insecure или -k.
Отправьте один ограниченный запрос как базовую проверку
Сохраните это как proxy-check.sh и запустите командой sh proxy-check.sh. Требуется curl 8.3.0 или новее и аутентификация на прокси по HTTP Basic. Пусть ваш менеджер секретов экспортирует PROXY_USERNAME и PROXY_PASSWORD, а в экспортированной переменной PROXY_URL укажите шлюз вашего провайдера со схемой и портом; https://proxy.example.invalid:8443 — иллюстративное значение, которое намеренно не подключается.
curl сам импортирует учётные данные, поэтому пароль не передаётся в его аргументах. Проверки отклоняют отсутствующие и пустые значения; ограничения окружения и трассировки сохраняются. Команда печатает статус целевого сервера, статус CONNECT и затраченное время, а тело ответа отбрасывает. Сохраните эту базовую проверку, прежде чем добавлять браузер, параллелизм или код приложения.
proxy-check.sh · curl 8.3+
: "${PROXY_URL:?Set your provider proxy URL}"
: "${PROXY_USERNAME:?}" "${PROXY_PASSWORD:?}"
curl --disable --silent --show-error --fail \
--noproxy '' \
--proxy "$PROXY_URL" \
--variable %PROXY_USERNAME \
--variable %PROXY_PASSWORD \
--expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \
--connect-timeout 10 --max-time 30 \
--output /dev/null \
--write-out 'http=%{http_code} connect=%{http_connect} seconds=%{time_total}\n' \
'https://example.com/'Читайте коды выхода curl и находите отказавший слой
Синтетическая локальная проверка с curl 8.7.1 сравнила два способа: раскрытие переменных оболочкой помещало пароль в начальные аргументы, внутренний импорт curl — нет. Оба способа отправляли одинаковые тестовые учётные данные. В более позднем списке процессов curl уже стёр раскрытое значение: один такой список не обнаружил бы утечку через аргументы. Проверка показывает локальное поведение команды, а не безопасность или производительность сервиса прокси.
Повторите проверку с локальным тестовым стендом и изучите синтетические результаты. Проверяется только HTTP Basic с вымышленными данными, а не внешний сервис прокси.
Успешный ответ доказывает, что этот запрос выполнился; он не устанавливает конкретную страну выхода или оператора. Для этого используйте документированную диагностическую конечную точку вашего провайдера или конечную точку под вашим контролем, которая сообщает наблюдаемый адрес источника.
Сравнивая своё приложение с curl, сохраняйте тот же целевой адрес и те же учётные данные. Если изменить три настройки сразу, успешный повтор будет трудно объяснить. Передавайте в поддержку код выхода, тайминги и очищенный статус, а не подробную трассировку с данными аутентификации.
- Код 5, could not resolve proxy: имя хоста шлюза неверно или локальный DNS его не видит.
- Код 7, failed to connect: хост прокси разрешился, но порт закрыт, фильтруется или недоступен из этой сети.
- Код 28, operation timed out: сопоставьте лимиты подключения и общего времени с измеренным временем. Повторение само по себе не показывает, виноват ли шлюз, целевой сервер или выбранный лимит.
- connect=407: прокси требует аутентификацию. В нашей локальной проверке curl 8.7.1 вернул код выхода 22 с --fail и 56 без этой опции. Читайте статус CONNECT вместе с кодом выхода; не ждите обязательно 56, прежде чем проверить учётные данные.
- Код 97, proxy handshake error: рукопожатие SOCKS отклонено; проверьте схему socks5 против socks5h и учётные данные.
- Код 35 или 60, ошибка TLS: проверьте имя хоста, цепочку доверия и часы. Оставляйте проверку сертификатов включённой.
- Код 35 с wrong version number — это не проблема сертификата: на рукопожатие TLS ответили открытым текстом, либо порт прокси, либо порт назначения. В руководстве SSL WRONG_VERSION_NUMBER через прокси показано, как %{http_connect} отличает одно от другого.
Перед выпуском
- Используйте реальный шлюз вашего провайдера со схемой и портом, которые он документирует.
- Передавайте учётные данные приватно; не вставляйте секреты в историю оболочки.
- Зафиксируйте одну ограниченную базовую проверку, прежде чем тестировать параллельный трафик.
- Прежде чем менять настройки, отметьте, произошёл ли сбой на этапе CONNECT или на целевом сервере.
Источники и дополнительное чтение
Технические материалы, использованные при подготовке руководства. Сверяйтесь с документацией вашей версии и с поддерживаемой конфигурацией вашего провайдера.