Если вы администрируете серверы, пишете скрипты автоматизации или деплоите приложения в корпоративной инфраструктуре — рано или поздно столкнётесь с необходимостью пустить трафик curl или wget через прокси. Это может быть корпоративный прокси, обход гео-блокировок при скачивании пакетов, или ротация IP при массовых запросах к внешним API. В этой статье — только практика: команды, конфиги, примеры кода без воды.
1. Как curl и wget работают с прокси: базовые механизмы
Прежде чем лезть в конфиги, важно понять, что происходит под капотом. Оба инструмента поддерживают два основных протокола прокси: HTTP/HTTPS и SOCKS5. Механика у них разная, и это влияет на то, какой тип прокси выбирать под конкретную задачу.
HTTP-прокси работает как посредник на уровне прикладного протокола. Когда curl отправляет запрос через HTTP-прокси, он буквально говорит прокси-серверу: «сделай GET-запрос вот на этот URL вместо меня». Для HTTPS-трафика используется метод CONNECT — curl просит прокси установить туннель до целевого хоста, после чего TLS-рукопожатие происходит напрямую между клиентом и сервером назначения. Это важно: прокси в таком случае не видит содержимое HTTPS-трафика.
SOCKS5 работает на более низком уровне — он проксирует TCP/UDP-соединения без привязки к протоколу прикладного уровня. Это делает SOCKS5 универсальнее: через него можно пустить не только HTTP/HTTPS, но и другие протоколы. Кроме того, SOCKS5 поддерживает DNS-разрешение на стороне прокси-сервера — это критически важно для предотвращения DNS-утечек.
💡 Ключевое различие для практики:
Если нужно просто скачать файл или сделать API-запрос — HTTP-прокси достаточно. Если нужна полная анонимность, обход DNS-утечек или работа с нестандартными протоколами — используйте SOCKS5.
curl поддерживает оба протокола нативно начиная с очень ранних версий. wget исторически имел более ограниченную поддержку SOCKS5 — в старых версиях (до 1.19) поддержки SOCKS5 нет вообще, только HTTP-прокси. Это нужно учитывать при написании скриптов, которые должны работать на разных дистрибутивах.
Проверить версию wget можно командой wget --version. Для curl — curl --version, там же будет видно, с какими протоколами собрана библиотека libcurl.
2. Переменные окружения: самый быстрый способ настройки
Самый элегантный способ настроить прокси для curl и wget — через переменные окружения. Это работает системно: не нужно менять каждый скрипт, достаточно выставить переменные один раз в сессии или добавить их в профиль пользователя.
Оба инструмента читают одни и те же стандартные переменные:
# Для HTTP-трафика export http_proxy="http://proxy.example.com:3128" # Для HTTPS-трафика export https_proxy="http://proxy.example.com:3128" # Дублируем в верхнем регистре (некоторые программы читают только их) export HTTP_PROXY="http://proxy.example.com:3128" export HTTPS_PROXY="http://proxy.example.com:3128" # Для FTP (если нужно) export ftp_proxy="http://proxy.example.com:3128" # Исключения — адреса, которые НЕ идут через прокси export no_proxy="localhost,127.0.0.1,::1,192.168.0.0/16,.internal.company.com"
Важный нюанс: curl чувствителен к регистру переменных в зависимости от версии. Чтобы не было сюрпризов — всегда выставляйте обе версии: в нижнем и верхнем регистре. Это стандартная практика в DevOps.
Чтобы настройки применялись постоянно для конкретного пользователя, добавьте строки в ~/.bashrc или ~/.profile. Для системных скриптов и сервисов — в /etc/environment или в юнит-файл systemd через директиву Environment=.
# /etc/systemd/system/myservice.service
[Service]
Environment="http_proxy=http://proxy.example.com:3128"
Environment="https_proxy=http://proxy.example.com:3128"
Environment="no_proxy=localhost,127.0.0.1"
ExecStart=/usr/bin/myapp
Если прокси требует аутентификацию, логин и пароль вставляются прямо в URL переменной:
export http_proxy="http://username:[email protected]:3128" export https_proxy="http://username:[email protected]:3128"
⚠️ Безопасность:
Не храните пароли в открытом виде в .bashrc или в переменных окружения на продакшн-серверах. Используйте vault-решения (HashiCorp Vault, AWS Secrets Manager) или как минимум ограничьте права на файл с переменными.
3. Флаги curl для работы с прокси: полный разбор
curl предоставляет богатый набор флагов для управления прокси прямо из командной строки. Это удобно, когда нужно сделать разовый запрос через прокси, не меняя системные настройки.
Основной флаг — -x или --proxy:
# Базовый HTTP-прокси curl -x http://proxy.example.com:3128 https://api.example.com/data # Короткая форма curl -x proxy.example.com:3128 https://api.example.com/data # С явным указанием протокола curl --proxy http://proxy.example.com:3128 https://api.example.com/data # Проверить внешний IP через прокси curl -x http://proxy.example.com:3128 https://api.ipify.org
Для игнорирования переменных окружения и прямого соединения (обход настроенного прокси) используется флаг --noproxy:
# Игнорировать прокси для конкретного хоста curl --noproxy "internal.company.com" https://internal.company.com/api # Игнорировать прокси полностью (даже если выставлены env-переменные) curl --noproxy "*" https://api.example.com/data
Полезные флаги для отладки прокси-соединений:
# Verbose-режим: видно все заголовки, включая CONNECT к прокси curl -v -x http://proxy.example.com:3128 https://api.example.com/data # Только заголовки ответа curl -I -x http://proxy.example.com:3128 https://api.example.com/data # Показать время соединения через прокси curl -w "Connect: %{time_connect}s\nTotal: %{time_total}s\n" \ -x http://proxy.example.com:3128 \ -o /dev/null -s https://api.example.com/data
Настройка прокси через конфиг-файл ~/.curlrc — удобно, если не хочется каждый раз прописывать флаги:
# ~/.curlrc
proxy = http://proxy.example.com:3128
proxy-user = username:password
noproxy = localhost,127.0.0.1,.internal.company.com
Для системных скриптов можно создать отдельный конфиг и указывать его явно через curl -K /path/to/config — это позволяет иметь разные профили прокси для разных задач.
4. Настройка прокси в wget: флаги и конфиг-файл
wget менее гибок, чем curl, но для типичных задач — скачивание файлов, рекурсивное зеркалирование сайтов — его возможностей вполне достаточно. Прокси в wget можно настроить тремя способами: через переменные окружения (рассмотрели выше), через флаги командной строки и через конфиг-файл ~/.wgetrc.
Флаги командной строки wget для прокси:
# HTTP-прокси через флаг wget -e use_proxy=yes \ -e http_proxy=http://proxy.example.com:3128 \ https://example.com/file.tar.gz # HTTPS через прокси wget -e use_proxy=yes \ -e https_proxy=http://proxy.example.com:3128 \ https://example.com/file.tar.gz # С аутентификацией wget -e use_proxy=yes \ -e http_proxy=http://username:[email protected]:3128 \ https://example.com/file.tar.gz # Отключить прокси для конкретной команды (если выставлены env-переменные) wget --no-proxy https://internal.company.com/file.tar.gz
Конфиг-файл ~/.wgetrc — предпочтительный способ для постоянной настройки:
# ~/.wgetrc use_proxy = on http_proxy = http://proxy.example.com:3128 https_proxy = http://proxy.example.com:3128 ftp_proxy = http://proxy.example.com:3128 no_proxy = localhost,127.0.0.1,.internal.company.com # Если прокси требует аутентификацию proxy_user = username proxy_password = secretpassword
Для системного применения (все пользователи) используется /etc/wgetrc — тот же формат, но применяется глобально. Удобно для серверов, где все операции скачивания должны идти через корпоративный прокси.
Практический пример: рекурсивное скачивание сайта через прокси с ограничением глубины и скорости:
wget -e use_proxy=yes \
-e http_proxy=http://proxy.example.com:3128 \
--recursive \
--level=2 \
--limit-rate=500k \
--wait=1 \
--random-wait \
--user-agent="Mozilla/5.0 (compatible; Googlebot/2.1)" \
https://example.com/docs/
5. SOCKS5 прокси в curl и wget: настройка и примеры
SOCKS5 — более предпочтительный протокол для задач, где важна анонимность или работа с нестандартными портами. Для системных администраторов и DevOps-инженеров SOCKS5 часто используется при работе через SSH-туннели, а также при подключении к резидентным прокси, которые имитируют трафик реальных пользователей.
В curl SOCKS5 поддерживается через специальный префикс в URL прокси:
# SOCKS5 с DNS-разрешением на стороне клиента (может быть DNS-утечка!) curl --socks5 proxy.example.com:1080 https://api.example.com/data # SOCKS5 с DNS-разрешением на стороне прокси (рекомендуется!) curl --socks5-hostname proxy.example.com:1080 https://api.example.com/data # Через флаг -x с явным указанием протокола curl -x socks5h://proxy.example.com:1080 https://api.example.com/data # С аутентификацией curl -x socks5h://username:[email protected]:1080 https://api.example.com/data # SOCKS5 через переменную окружения export all_proxy="socks5h://proxy.example.com:1080" curl https://api.example.com/data
📌 socks5 vs socks5h — в чём разница?
socks5 — DNS-запрос выполняется локально, через прокси идёт только TCP-соединение по IP. Возможна DNS-утечка.socks5h (h = hostname) — DNS-запрос выполняется на стороне прокси-сервера. Полная анонимность. Рекомендуется для большинства задач.
Популярный сценарий в DevOps — использование SSH как SOCKS5-прокси для туннелирования трафика через бастион-хост:
# Открываем SSH-туннель с SOCKS5 на локальном порту 1080 ssh -D 1080 -f -C -q -N [email protected] # Теперь используем этот туннель в curl curl -x socks5h://localhost:1080 https://internal-api.private.network/data # Или через переменную окружения для всех запросов в сессии export all_proxy="socks5h://localhost:1080" wget https://internal-resource.private.network/file.tar.gz
wget поддерживает SOCKS5 начиная с версии 1.19. В более старых версиях (CentOS 7, Ubuntu 16.04) придётся использовать обходные решения: proxychains, tsocks, или переходить на curl для задач, требующих SOCKS5.
6. Аутентификация на прокси: логин и пароль
Большинство коммерческих прокси и корпоративные прокси-серверы требуют аутентификации. Есть несколько способов передать учётные данные — каждый со своими плюсами и минусами с точки зрения безопасности.
Способ 1: Учётные данные в URL — просто, но небезопасно (пароль виден в списке процессов):
curl -x http://user:p%[email protected]:3128 https://api.example.com/data # Спецсимволы в пароле нужно URL-кодировать: @ → %40, : → %3A
Способ 2: Флаг --proxy-user в curl — пароль можно не указывать в командной строке, curl запросит его интерактивно:
# Логин и пароль в флаге (всё ещё виден в ps aux) curl -x http://proxy.example.com:3128 \ --proxy-user "username:password" \ https://api.example.com/data # Только логин — curl спросит пароль интерактивно curl -x http://proxy.example.com:3128 \ --proxy-user "username" \ https://api.example.com/data
Способ 3: Через .netrc файл — наиболее безопасный для скриптов:
# ~/.netrc machine proxy.example.com login username password secretpassword # Ограничиваем права доступа к файлу chmod 600 ~/.netrc # Используем в curl curl -x http://proxy.example.com:3128 --proxy-netrc https://api.example.com/data
Способ 4: Через переменные окружения из секретного хранилища — рекомендуется для CI/CD и продакшн-окружений:
# В скрипте читаем учётные данные из переменных (которые задаёт CI/CD)
#!/bin/bash
PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:3128"
curl -x "${PROXY_URL}" https://api.example.com/data
Таблица сравнения методов аутентификации:
| Метод | Удобство | Безопасность | Подходит для |
|---|---|---|---|
| URL (user:pass@host) | ⭐⭐⭐ | ⭐ | Тестирование |
| --proxy-user флаг | ⭐⭐⭐ | ⭐⭐ | Разовые команды |
| .netrc файл | ⭐⭐ | ⭐⭐⭐ | Локальные скрипты |
| Env переменные из vault | ⭐⭐ | ⭐⭐⭐⭐⭐ | CI/CD, продакшн |
7. Исключения и no_proxy: как обойти прокси для локальных адресов
В корпоративных и облачных окружениях часто нужна тонкая настройка: внешний трафик — через прокси, внутренний — напрямую. Переменная no_proxy (или NO_PROXY) позволяет задать список исключений.
# Базовые исключения export no_proxy="localhost,127.0.0.1,::1" # Исключение по домену (с точкой — все поддомены) export no_proxy="localhost,127.0.0.1,.internal.company.com,.corp.local" # Исключение по IP-диапазону (CIDR нотация работает не везде!) export no_proxy="localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Для AWS: исключаем metadata endpoint и внутренние адреса export no_proxy="localhost,127.0.0.1,169.254.169.254,.amazonaws.com.internal"
⚠️ Важная особенность no_proxy:
CIDR-нотация (10.0.0.0/8) поддерживается не всеми инструментами. curl поддерживает её начиная с версии 7.86.0. wget — не поддерживает вообще. Для совместимости лучше перечислять конкретные IP или маски типа 10. (всё, что начинается с 10.).
Практический пример для Kubernetes-окружения, где нужно исключить API-сервер и внутренние сервисы:
export no_proxy="localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/16,.cluster.local,.svc,.default"
export NO_PROXY="${no_proxy}"
8. Прокси в CI/CD: GitHub Actions, GitLab CI, Docker
Настройка прокси в CI/CD-пайплайнах — одна из самых частых задач DevOps-инженеров, работающих в корпоративных сетях или с ограниченным доступом в интернет. Разберём конкретные конфигурации для популярных платформ.
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
env:
http_proxy: ${{ secrets.PROXY_URL }}
https_proxy: ${{ secrets.PROXY_URL }}
no_proxy: "localhost,127.0.0.1,.github.com"
steps:
- uses: actions/checkout@v3
- name: Download dependencies
run: |
curl -x "${http_proxy}" https://external-api.example.com/config.json -o config.json
wget -e use_proxy=yes -e http_proxy="${http_proxy}" https://releases.example.com/app-v1.0.tar.gz
GitLab CI
# .gitlab-ci.yml
variables:
http_proxy: "http://proxy.company.com:3128"
https_proxy: "http://proxy.company.com:3128"
no_proxy: "localhost,127.0.0.1,.gitlab.company.com"
build:
stage: build
script:
- curl -x "${http_proxy}" https://registry.npmjs.org/package -o package.json
- wget -e use_proxy=yes -e http_proxy="${http_proxy}" https://example.com/resource.tar.gz
Docker: прокси при сборке образов
# Передача прокси через build args docker build \ --build-arg http_proxy=http://proxy.example.com:3128 \ --build-arg https_proxy=http://proxy.example.com:3128 \ --build-arg no_proxy=localhost,127.0.0.1 \ -t myapp:latest . # В Dockerfile используем ARG для получения переменных
# Dockerfile FROM ubuntu:22.04 ARG http_proxy ARG https_proxy ARG no_proxy ENV http_proxy=${http_proxy} ENV https_proxy=${https_proxy} ENV no_proxy=${no_proxy} RUN apt-get update && apt-get install -y curl wget RUN curl -x "${http_proxy}" https://example.com/setup.sh | bash # Очищаем прокси-переменные в финальном образе (опционально) ENV http_proxy="" ENV https_proxy=""
Глобальная настройка прокси для Docker daemon (для docker pull через прокси):
# /etc/systemd/system/docker.service.d/proxy.conf [Service] Environment="HTTP_PROXY=http://proxy.example.com:3128" Environment="HTTPS_PROXY=http://proxy.example.com:3128" Environment="NO_PROXY=localhost,127.0.0.1,.internal.registry.com" # Перезапускаем docker systemctl daemon-reload systemctl restart docker
9. Ротация прокси в bash-скриптах
Если вам нужно делать большое количество запросов к внешним API или сервисам — ротация прокси позволяет распределить нагрузку и избежать блокировок по IP. Это особенно актуально при мониторинге цен, сборе данных или тестировании доступности ресурсов из разных регионов.
Для таких задач хорошо подходят прокси дата-центров — они обеспечивают высокую скорость и стабильность при массовых запросах.
#!/bin/bash # rotate_proxy.sh — ротация прокси из списка PROXY_LIST=( "http://user:[email protected]:3128" "http://user:[email protected]:3128" "http://user:[email protected]:3128" "http://user:[email protected]:3128" ) URLS_FILE="urls.txt" OUTPUT_DIR="./results" mkdir -p "${OUTPUT_DIR}" PROXY_COUNT=${#PROXY_LIST[@]} INDEX=0 while IFS= read -r url; do PROXY="${PROXY_LIST[$INDEX]}" FILENAME=$(echo "${url}" | md5sum | cut -d' ' -f1) echo "Requesting: ${url} via proxy $((INDEX + 1))/${PROXY_COUNT}" curl -x "${PROXY}" \ --max-time 30 \ --retry 3 \ --retry-delay 2 \ --silent \ --output "${OUTPUT_DIR}/${FILENAME}.html" \ "${url}" if [ $? -eq 0 ]; then echo " ✓ Success" else echo " ✗ Failed, trying next proxy..." INDEX=$(( (INDEX + 1) % PROXY_COUNT )) curl -x "${PROXY_LIST[$INDEX]}" \ --max-time 30 \ --silent \ --output "${OUTPUT_DIR}/${FILENAME}.html" \ "${url}" fi # Переходим к следующему прокси INDEX=$(( (INDEX + 1) % PROXY_COUNT )) # Небольшая пауза между запросами sleep 0.5 done < "${URLS_FILE}" echo "Done! Results saved to ${OUTPUT_DIR}"
Более продвинутый вариант — проверка работоспособности прокси перед использованием:
#!/bin/bash # check_proxy.sh — проверка доступности прокси check_proxy() { local proxy_url="$1" local test_url="https://api.ipify.org" result=$(curl -x "${proxy_url}" \ --max-time 10 \ --silent \ --write-out "%{http_code}" \ --output /dev/null \ "${test_url}") if [ "${result}" -eq 200 ]; then echo "ALIVE" else echo "DEAD" fi } # Получаем внешний IP через прокси get_proxy_ip() { local proxy_url="$1" curl -x "${proxy_url}" --max-time 10 --silent https://api.ipify.org } PROXY="http://user:[email protected]:3128" STATUS=$(check_proxy "${PROXY}") echo "Proxy status: ${STATUS}" if [ "${STATUS}" == "ALIVE" ]; then EXTERNAL_IP=$(get_proxy_ip "${PROXY}") echo "External IP via proxy: ${EXTERNAL_IP}" fi
10. Отладка и типичные ошибки
Работа с прокси неизбежно сопровождается ошибками — особенно при первоначальной настройке. Разберём самые распространённые проблемы и способы их диагностики.
Диагностика с помощью verbose-режима
# Максимально подробный вывод curl curl -vvv -x http://proxy.example.com:3128 https://api.example.com/data 2>&1 | head -50 # Что смотреть в выводе: # * Connected to proxy.example.com — соединение с прокси установлено # CONNECT api.example.com:443 — запрос на туннель # HTTP/1.1 200 Connection established — туннель открыт # * SSL connection using TLS — TLS работает # Отладка wget wget -d -e use_proxy=yes -e http_proxy=http://proxy.example.com:3128 https://api.example.com/data
Типичные ошибки и решения
| Ошибка | Причина | Решение |
|---|---|---|
407 Proxy Authentication Required |
Не переданы учётные данные | Добавить user:pass в URL прокси или флаг --proxy-user |
Connection refused |
Неверный порт или прокси недоступен | Проверить порт: nc -zv proxy.host 3128 |
SSL certificate error |
Корпоративный прокси с SSL-инспекцией | Добавить корпоративный CA: --cacert /path/to/ca.crt |
Could not resolve proxy |
DNS не резолвит имя прокси | Использовать IP вместо имени или проверить DNS |
Timeout |
Прокси медленный или перегружен | Увеличить таймаут: |