Как создать общий прокси-шлюз ProxyScrape на Linux с Privoxy и HAProxy
Превратите конечную точку ProxyScrape SOCKS5 в один HTTP-прокси-адрес, которым сможет пользоваться вся ваша команда, с циклическим переключением между несколькими вышестоящими прокси, проверками работоспособности и контролем доступа из частной сети.
Обзор
Настройка прокси на каждой машине не масштабируется. Когда нескольким людям, паре 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 вне системы контроля версий и меняйте учётные данные, редактируя конфиги экземпляров и перезапуская шаблонные юниты по одному, чтобы шлюз никогда не отключался полностью.