Skip to content
Advanced / 4 min read

Как создать общий прокси-шлюз ProxyScrape на Linux с Privoxy и HAProxy

Превратите конечную точку ProxyScrape SOCKS5 в один HTTP-прокси-адрес, которым сможет пользоваться вся ваша команда, с циклическим переключением между несколькими вышестоящими прокси, проверками работоспособности и контролем доступа из частной сети.

Linux SOCKS5 HTTP(S) Другое

Обзор

Настройка прокси на каждой машине не масштабируется. Когда нескольким людям, паре CI-раннеров и нескольким контейнерам нужен один и тот же пул прокси, учётные данные в итоге копируются в каждый лаунчер и скрипт, и никто не может сказать, какой трафик использовал какой вышестоящий прокси.

В этом руководстве мы соберём обратное: один Linux-хост, который хранит ваши учётные данные ProxyScrape в одном месте и предоставляет один HTTP-прокси-адрес вашей частной сети.

Client apps -> HAProxy (TCP :3128) -> Privoxy instances (127.0.0.1:8118-8120) -> ProxyScrape SOCKS5 -> Internet

В руководстве используются вышестоящие прокси ProxyScrape SOCKS5, потому что локальный интерфейс должен передавать имя пользователя и пароль вышестоящему прокси, а Privoxy поддерживает учётные данные для вышестоящих SOCKS5, но не для вышестоящих HTTP. Если вам конкретно нужно цепочить через аутентифицируемый HTTP-прокси, используйте вместо этого инструмент цепочек, поддерживающий аутентификацию родительского HTTP-прокси.

Уровень Программное обеспечение Что делает
Клиентский край HAProxy (режим TCP) Даёт клиентам один хост и порт, распределяет новые подключения между локальными экземплярами прокси, удаляет экземпляры, которые перестали отвечать
Локальный прокси Privoxy Принимает HTTP-прокси-запросы и перенаправляет каждый из них в одну конечную точку ProxyScrape SOCKS5
Вышестоящий прокси ProxyScrape SOCKS5 Разрешает и загружает целевой URL, используя прокси-IP из пула

Одно практическое следствие такой архитектуры: ротация происходит для каждого нового подключения, а не для каждого запроса. Клиент, который переиспользует keep-alive-соединение, остаётся на том же вышестоящем экземпляре до повторного подключения.

Предварительные требования

  • Linux-хост (семейство Debian/Ubuntu или RHEL/Fedora) со стабильным адресом в частной сети, VPN или tailnet. Не открывайте порт шлюза в публичный интернет.
  • Данные конечной точки ProxyScrape SOCKS5 из вашей панели управления: хост, порт, имя пользователя и пароль.
  • Доступ sudo и разрешение открыть один порт (3128 в примерах ниже) в частной сети.
  • Базовое знакомство с systemd-юнитами и редактированием конфигурационных файлов.

Шаги

Шаг 1: Проверьте конечную точку ProxyScrape SOCKS5 перед тем, как что-либо собирать

Поместите учётные данные в переменные оболочки, чтобы последующие проверки оставались согласованными:

export PS_HOST="socks5-host-from-your-dashboard"
export PS_PORT="1080"
export PS_USER="your-username"
export PS_PASS="your-password"

Сделайте один запрос напрямую через конечную точку:

curl --silent --show-error \
  --proxy "socks5h://${PS_USER}:${PS_PASS}@${PS_HOST}:${PS_PORT}" \
  https://api.ipify.org
printf '\n'

Схема socks5h:// заставляет curl отправлять DNS-запросы через прокси, а это именно то, что нужно для шлюза. Запустите команду два или три раза и запишите адреса, которые вернутся. Если первая команда не работает, исправьте учётные данные, хост и порт, прежде чем продолжать, потому что от этого зависит каждый последующий уровень.

Шаг 2: Установите Privoxy и HAProxy

Debian и Ubuntu:

sudo apt update
sudo apt install --yes privoxy haproxy

RHEL, Fedora и совместимые системы:

sudo dnf install --yes privoxy haproxy

Убедитесь, что бинарные файлы присутствуют, и запишите их пути, поскольку systemd-юнит ниже напрямую ссылается на бинарный файл Privoxy:

command -v privoxy
command -v haproxy

Шаг 3: Создайте один экземпляр Privoxy на каждый вышестоящий прокси

Privoxy читает один плоский конфигурационный файл, что позволяет легко запускать несколько независимых экземпляров, по одному на каждую вышестоящую конечную точку. Начните с каталога для них:

sudo mkdir -p /etc/privoxy/instances

Создайте /etc/privoxy/instances/instance-1.conf:

confdir /etc/privoxy
logdir /var/log/privoxy
logfile instance-1.log

toggle 0
listen-address 127.0.0.1:8118

forward-socks5t / USERNAME:PASSWORD@HOST:PORT .

Замените USERNAME, PASSWORD, HOST и PORT на ваши значения ProxyScrape SOCKS5.

  • toggle 0 отключает фильтрацию содержимого Privoxy. Шлюз должен передавать трафик без изменений, а не переписывать или блокировать его.
  • listen-address 127.0.0.1:8118 оставляет экземпляр доступным только на хосте. Единственной открытой поверхностью будет HAProxy.
  • forward-socks5t отправляет запросы вышестоящему SOCKS5-прокси и также разрешает DNS удалённо, поэтому имена хостов не разрешаются из вашей собственной сети.
  • Ведущий / соответствует любому URL, а завершающая . является частью формы правила SOCKS-перенаправления, используемой в документации Privoxy для Tor и подобных конфигураций.

Закройте доступ к файлу, потому что он содержит учётные данные:

sudo chown root:privoxy /etc/privoxy/instances/instance-1.conf
sudo chmod 640 /etc/privoxy/instances/instance-1.conf

Если пакет дистрибутива уже запустил службу Privoxy на порту 8118, сначала остановите её, чтобы освободить порт:

sudo systemctl disable --now privoxy

Проверьте экземпляр в foreground-режиме:

sudo privoxy --no-daemon /etc/privoxy/instances/instance-1.conf

Во втором терминале отправьте через него запрос:

curl --silent --proxy http://127.0.0.1:8118 https://api.ipify.org
printf '\n'

Если он вернёт адрес, самая сложная часть сделана. Остановите foreground-процесс сочетанием Ctrl+C и повторите конфигурационный файл для каждой дополнительной конечной точки ProxyScrape, которую хотите использовать, меняя только имя лог-файла и порт прослушивания.

Шаг 4: Запустите экземпляры как шаблонную systemd-службу

Создайте /etc/systemd/system/[email protected]:

[Unit]
Description=Privoxy proxy gateway instance %i
Documentation=man:privoxy(8)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=privoxy
Group=privoxy
ExecStart=/usr/sbin/privoxy --no-daemon /etc/privoxy/instances/instance-%i.conf
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Если command -v privoxy вывела другой путь, измените ExecStart соответственно. Затем включите экземпляры:

sudo systemctl daemon-reload
sudo systemctl enable --now privoxy-gateway@1 privoxy-gateway@2 privoxy-gateway@3
systemctl list-units 'privoxy-gateway@*' --no-pager

Убедитесь, что каждый экземпляр прослушивает свой собственный loopback-порт:

for port in 8118 8119 8120; do
  printf '%s -> ' "$port"
  curl --silent --proxy "http://127.0.0.1:${port}" https://api.ipify.org
  printf '\n'
done

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

Шаг 5: Поставьте HAProxy впереди как TCP-балансировщик нагрузки

Интерфейсу не нужно понимать HTTP. Ему нужно только ретранслировать TCP-соединения, что делает режим TCP в HAProxy хорошим выбором для HTTP-прокси перед вышестоящими SOCKS5-прокси.

Сделайте резервную копию поставляемого конфига и замените /etc/haproxy/haproxy.cfg на следующий. Замените 10.8.0.1 на частный адрес этого хоста.

global
    log /dev/log local0
    maxconn 4000
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s

defaults
    mode tcp
    log global
    option tcplog
    retries 2
    timeout connect 10s
    timeout client 5m
    timeout server 5m

frontend proxy_gateway
    bind 10.8.0.1:3128
    default_backend privoxy_instances

frontend proxy_gateway_sticky
    bind 10.8.0.1:3129
    default_backend privoxy_instance_1

backend privoxy_instances
    balance roundrobin
    server privoxy1 127.0.0.1:8118 check
    server privoxy2 127.0.0.1:8119 check
    server privoxy3 127.0.0.1:8120 check

backend privoxy_instance_1
    server privoxy1 127.0.0.1:8118 check

listen stats
    bind 127.0.0.1:8404
    mode http
    stats enable
    stats uri /stats
    stats refresh 10s

Несколько замечаний по сделанным здесь выборам:

  • Порт 3128 — это точка входа с ротацией. Каждое новое TCP-соединение отправляется к следующему работоспособному экземпляру Privoxy.
  • Порт 3129 привязан к одному экземпляру для задач, где вы хотите, чтобы каждый запрос во время запуска выходил через один и тот же вышестоящий прокси.
  • Простое ключевое слово check выполняет проверку TCP-подключения, поэтому экземпляр, который перестаёт принимать подключения, автоматически исключается из ротации.
  • Страница статистики привязана только к loopback. Получайте к ней доступ через SSH-туннель или внутренний jump-хост, а не открывайте порт 8404 для сети.

Проверьте и перезагрузите:

sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl restart haproxy
systemctl --no-pager --lines=20 status haproxy

Шаг 6: Ограничьте доступ вашей частной сетью

Привязка HAProxy к частному адресу, адресу VPN или tailnet означает, что шлюз доступен только изнутри этой сети. Если у хоста также есть публичный интерфейс, добавьте правило брандмауэра, чтобы ничто на этом интерфейсе не могло достичь прокси-портов.

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

sudo nft add table inet proxygw
sudo nft add chain inet proxygw input '{ type filter hook input priority 0; }'
sudo nft add rule inet proxygw input tcp dport { 3128, 3129 } ip saddr != 10.8.0.0/24 drop

Этот стек не аутентифицирует клиентов; контроль доступа обеспечивается сетью, к которой привязан шлюз. Если вам нужны учётные данные для каждого человека, завершайте пользовательский доступ на VPN или tailnet перед хостом.

Шаг 7: Проверьте ротацию от начала до конца

Отправьте серию отдельных запросов на порт с ротацией:

for i in $(seq 1 6); do
  curl --silent --proxy http://10.8.0.1:3128 https://api.ipify.org
  printf '\n'
done

Каждый вызов curl открывает новое соединение, поэтому вы должны увидеть разброс адресов, а не один повторяющийся. Затем откройте страницу статистики (при необходимости через туннель) и убедитесь, что каждый бэкенд помечен UP:

ssh -L 8404:127.0.0.1:8404 user@gateway-host
# in the browser on your workstation: http://127.0.0.1:8404/stats

Наконец, направьте реальный клиент на шлюз, например сессию оболочки, которая использует прокси для инструментов командной строки:

export http_proxy="http://10.8.0.1:3128"
export https_proxy="http://10.8.0.1:3128"
curl --silent https://api.ipify.org
printf '\n'
unset http_proxy https_proxy

Поведение с ротацией и фиксированное поведение

Выберите порт интерфейса, который соответствует задаче. Оба варианта уже настроены выше.

  • С ротацией (3128): новые подключения распределяются между всеми работоспособными экземплярами. Хороший вариант по умолчанию для браузеров, обычного просмотра и задач, которые часто открывают новые подключения.
  • Фиксированный (3129): весь трафик идёт к одному экземпляру. Хорошо для рабочих процессов, которым нужно сохранять один и тот же исходный адрес на протяжении сессии.
  • Изоляция по группам: создайте второй бэкенд с подмножеством экземпляров и направьте на него новый порт интерфейса, чтобы одна команда никогда не потребляла весь пул.

Устранение неполадок

Симптом Вероятная причина Исправление
Privoxy возвращает ответ 403 Включена фильтрация содержимого, и правило фильтра совпало с запросом Убедитесь, что в конфиге экземпляра присутствует toggle 0, и перезапустите этот экземпляр
Privoxy возвращает 502 или ошибку подключения к вышестоящему прокси Неверный хост, порт или учётные данные SOCKS5 Повторно выполните прямой тест curl --proxy "socks5h://..." из шага 1
Все бэкенды отображаются как DOWN на странице статистики Экземпляры Privoxy не запущены или не прослушивают там, где ожидает HAProxy Выполните systemctl list-units 'privoxy-gateway@*' и `ss -ltnp
Каждый запрос выходит с одного и того же адреса Клиент переиспользует keep-alive-соединение или активен только один экземпляр Принудительно открывайте новые подключения для каждого запроса и убедитесь, что все бэкенды сообщают UP
Имена хостов разрешаются из вашей собственной сети Экземпляр использует forward-socks5 вместо forward-socks5t Переключитесь на forward-socks5t, чтобы DNS разрешался через прокси
HAProxy не запускается с ошибкой /dev/log На хосте нет сокета syslog Удалите строку log /dev/log local0 или установите и включите службу syslog
Большие загрузки прерываются по тайм-ауту в середине передачи Тайм-ауты HAProxy по умолчанию слишком малы для этой нагрузки Увеличьте timeout client и timeout server в секции defaults

Итог

Теперь у вас есть единый HTTP-прокси-адрес, который стоит перед несколькими конечными точками ProxyScrape SOCKS5, с автоматической проверкой работоспособности на стороне HAProxy и ротацией для каждого подключения на порту 3128. Учётные данные хранятся в одном наборе конфигурационных файлов, принадлежащих root, вместо копирования в каждый инструмент на каждой машине.

Естественные следующие шаги: добавляйте экземпляр и строку server, когда захотите увеличить ёмкость вышестоящих прокси, держите конфигурационные файлы Privoxy вне системы контроля версий и меняйте учётные данные, редактируя конфиги экземпляров и перезапуская шаблонные юниты по одному, чтобы шлюз никогда не отключался полностью.