С чего начать
Переменная прокси может быть задана, а запрос при этом уходит напрямую к целевому серверу. Проверьте клиент, схему назначения и правила обхода, прежде чем винить шлюз.
Отделяйте выбор по назначению от соединения с прокси
Эти переменные — соглашения, которые каждый клиент интерпретирует по-своему, а не переключатель операционной системы, направляющий трафик всех приложений. Работающая команда curl не доказывает, что другая библиотека унаследовала или учла те же настройки.
Имя переменной обычно определяет схему целевого адреса. HTTPS_PROXY может содержать URL прокси вида http://: целевой сервер использует HTTPS, а клиент сначала подключается к HTTP-прокси и запрашивает туннель CONNECT. Схема в URL прокси описывает соединение с самим прокси.
- http_proxy / HTTP_PROXY: выбор прокси для HTTP-назначения с учётом правил клиента о регистре.
- https_proxy / HTTPS_PROXY: выбор прокси для HTTPS-назначения.
- all_proxy / ALL_PROXY: запасной вариант в curl и Requests, когда не выбран подходящий прокси для конкретной схемы. Не предполагайте, что его реализует каждый клиент.
- no_proxy / NO_PROXY: запрос прямого соединения для подходящих назначений, когда действует выбор прокси из окружения. Это исключение из маршрутизации, а не ещё один адрес прокси.
Определите клиент и версию, которые реально выполняют запрос
Локальные проверки маршрутизации для этого руководства выполнялись на curl 8.7.1, Requests 2.34.2 на Python 3.14.7 и Node.js 26.8.1. В примечаниях к выпуску Node.js 24.5.0 отдельно задокументировано появление поддержки прокси из окружения для стандартных агентов HTTP/HTTPS; fetch получил такую опциональную поддержку раньше, в 24.0.0. Эти исторические версии проверены по документации, а не запускались здесь.
- curl принимает http_proxy в нижнем регистре, но намеренно игнорирует HTTP_PROXY в верхнем, поскольку в CGI-окружениях это имя может быть образовано из заголовка входящего запроса. HTTPS_PROXY и ALL_PROXY принимаются. Переменная для конкретного протокола имеет приоритет над ALL_PROXY.
- Requests обычно читает все четыре семейства переменных, включая имена в верхнем регистре. Механизм обнаружения прокси в Python предпочитает нижний регистр, если значения в двух регистрах расходятся; в CGI-окружениях с установленным REQUEST_METHOD HTTP_PROXY в верхнем регистре игнорируется. Значения из окружения могут переопределять session.proxies, поэтому один словарь сессии не является границей изоляции.
- Встроенная поддержка окружения в Node требует явного включения: запускайте процесс с NODE_USE_ENV_PROXY=1. Тогда стандартные агенты HTTP/HTTPS и нативный fetch используют HTTP_PROXY, HTTPS_PROXY и NO_PROXY; нижний регистр имеет приоритет. Одного ALL_PROXY в этом встроенном режиме недостаточно. Пользовательские агенты, диспетчеры и сторонние пакеты требуют отдельной проверки конфигурации.
Относитесь к NO_PROXY как к изменению маршрута
Начните со списка точных разрешённых целевых хостов через запятую, затем проверьте, какие запросы реально под него подпадают. Не вставляйте в список хостов полные URL или пути. Подстановочный знак * запрашивает прямой маршрут для всех назначений во всех рассматриваемых здесь клиентах; он не годится как быстрое «решение» для обязательного прокси.
Нет переносимой грамматики сопоставления, на которую можно рассчитывать во всех этих клиентах. Например, curl документирует сопоставление по CIDR начиная с 7.86.0; во встроенной документации Node перечислены имена хостов, суффиксы доменов, диапазоны адресов и записи host:port. Запись домена, подстановочный знак или подсеть, работающие в одном клиенте, требуют отдельной проверки в другом. DNS-псевдонимы и IP-литералы тоже меняют имя, с которым идёт сопоставление.
Если внутренний запрос неожиданно идёт через прокси, изучите фактическое имя целевого хоста и правила сопоставления конкретного клиента. Если внешний запрос неожиданно идёт напрямую, проверьте NO_PROXY в обоих регистрах и любую явную конфигурацию агента. Меняйте только то правило маршрутизации, которое утверждено для данного развёртывания.
Наблюдайте выбор прокси без реального шлюза
Сохраните этот файл как proxy_env_lab.py и запустите python3 proxy_env_lab.py при установленном curl. Он поднимает два HTTP-сервера-маркера на случайных loopback-портах: один представляет прямое назначение, другой — выбранный прокси. Маркер прокси отвечает локально; он не пересылает трафик и не проверяет CONNECT, TLS, аутентификацию или исходящий IP-адрес.
Каждый процесс curl получает только переданное тестовое окружение. --disable стоит первой опцией, чтобы личный curlrc не мог повлиять на эксперимент. Ожидаемые результаты: proxy, direct, direct, proxy. Это показывает, что даже явный --proxy подчиняется NO_PROXY, пока список обхода не очищен явно для этой локальной диагностики.
proxy_env_lab.py · стандартная библиотека Python 3 + curl
import shutil
import subprocess
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
curl = shutil.which("curl")
if not curl:
raise SystemExit("Install curl before running this local lab")
def marker(label):
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
body = label.encode()
self.send_response(200)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, *_):
pass
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
threading.Thread(target=server.serve_forever, daemon=True).start()
return server, "http://127.0.0.1:" + str(server.server_port)
origin, destination = marker("direct")
proxy_server, proxy = marker("proxy")
cases = [
("environment", {"http_proxy": proxy}, [], "proxy"),
("host bypass", {"http_proxy": proxy, "NO_PROXY": "127.0.0.1"}, [], "direct"),
("explicit + bypass", {"NO_PROXY": "127.0.0.1"}, ["--proxy", proxy], "direct"),
("explicit + cleared bypass", {"NO_PROXY": "127.0.0.1"},
["--proxy", proxy, "--noproxy", ""], "proxy"),
]
try:
for label, environment, options, expected in cases:
result = subprocess.run(
[curl, "--disable", "--silent", "--show-error", "--fail",
"--connect-timeout", "2", "--max-time", "3", *options, destination],
env=environment, capture_output=True, text=True, timeout=5,
)
if result.returncode or result.stdout != expected:
raise SystemExit("Local route check failed: " + label)
print(label + ": " + result.stdout)
finally:
for server in (origin, proxy_server):
server.shutdown()
server.server_close()Задайте базовую конфигурацию приложения осознанно
Для диагностики через curl с обязательным прокси используйте явный --proxy вместе с --noproxy '', как показано в существующем руководстве по настройке curl. Для Requests передавайте аргумент proxies в самом запросе; используйте отдельную Session с trust_env=False, когда базовая конфигурация должна игнорировать унаследованные настройки прокси. Это также отключает аутентификацию и конфигурацию CA-bundle, получаемые из окружения, поэтому при необходимости явно передавайте утверждённый пользовательский набор доверенных сертификатов.
Для Node выберите либо проверенное включение через окружение, либо явный совместимый агент/диспетчер. Не предполагайте, что пользовательский агент библиотеки наследует глобальную настройку. Уточните, какой именно runtime используется воркером или сервисом, а не только версию, установленную в интерактивном терминале.
Когда локальное правило понятно, сравните одно разрешённое назначение с одним шлюзом из документации провайдера. Держите проверку TLS включённой, задайте дедлайн и подтвердите путь запроса контролируемыми наблюдениями на конечной точке или прокси. Успешный HTTP-статус сам по себе не показывает, какой маршрут был выбран.
Записывайте решения, не записывая секреты
Сравните окружение процесса, выполняющего запрос, с конфигурацией его запускающего процесса, контейнера или сервиса. Фиксируйте имена переменных и факт их установки, версию клиента, схему назначения и наблюдаемый маршрут. Избегайте дампов всего окружения, трассировки shell, подробных протокольных логов и сырого текста исключений: URL прокси может содержать пароль.
Пусть утверждённый менеджер секретов приватно подставляет необходимые учётные данные в окружение процесса. Не вставляйте их в команду, не коммитьте файл окружения и не отправляйте сырую конфигурацию в поддержку. Переменные окружения — механизм доставки, а не хранилище секретов. Эта локальная лаборатория не использует учётные данные и ничего не говорит о доступности сервиса ipvolt.
Перед выпуском
- Определите фактический клиент, версию runtime и схему назначения.
- Проверьте имена переменных в верхнем и нижнем регистре, не логируя их значения.
- Проверьте сопоставление NO_PROXY и выбранный маршрут на разрешённом назначении.
- Сравните контролируемое окружение с явной конфигурацией, прежде чем добавлять повторы.
Источники и дополнительное чтение
Технические материалы, использованные при подготовке руководства. Сверяйтесь с документацией вашей версии и с поддерживаемой конфигурацией вашего провайдера.
- Everything curl: proxy environment variables and case rules
- curl manual: --disable, --proxy and --noproxy
- Requests: environment proxy configuration
- Python: proxy discovery and CGI handling
- Node.js 24.5.0: environment proxy support in HTTP clients
- Node.js HTTP documentation: built-in proxy and NO_PROXY rules