Ротирующий Tor HTTP-прокси в Kubernetes

Published: 2026-05-30

Любая статья про прокси в итоге заканчивается вопросом: «а можно автоматически ротировать IP?» Ответ, работающий на этом сервере, — zhaow-de/rotating-tor-http-proxy: контейнер, запускающий N параллельных Tor-цепочек за общим фронтендом HAProxy. Каждый запрос идёт через другую цепочку и выходит с другим exit IP — без специальных действий на стороне клиента.

Что работает внутри контейнера

Образ включает:

  • N пар Privoxy + Tor (настраивается через TOR_INSTANCES)
  • HAProxy спереди — распределяет запросы по всем экземплярам Privoxy по кругу (round-robin)
  • Cron-задачу, отправляющую NEWNYM на control socket каждого Tor раз в TOR_REBUILD_INTERVAL секунд

Каждый Tor-процесс независимо поддерживает собственную цепочку. Когда HAProxy направляет запрос на экземпляр №3, запрос выходит через текущий exit node экземпляра №3. Следующий запрос может пойти на экземпляр №1 с совершенно другим exit node.

Stats UI на :30444 показывает количество сессий и трафик на каждый backend — именно это страница прокси тянет для отображения таблицы «Tor stats».

Настройка Kubernetes

Всё живёт в отдельном namespace tor. Deployment простой — один под, стратегия Recreate (rolling update здесь не даёт преимуществ), emptyDir для /var/lib/tor, чтобы Tor мог писать state-файлы:

yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: tor-proxy
  namespace: tor
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: tor-proxy
  template:
    metadata:
      labels:
        app: tor-proxy
    spec:
      containers:
      - name: tor-proxy
        image: zhaowde/rotating-tor-http-proxy:latest
        env:
        - name: TOR_INSTANCES
          value: "5"
        - name: TOR_REBUILD_INTERVAL
          value: "1800"
        ports:
        - containerPort: 3128   # HAProxy HTTP
        - containerPort: 4444   # HAProxy stats
        volumeMounts:
        - name: tor-data
          mountPath: /var/lib/tor
      volumes:
      - name: tor-data
        emptyDir: {}

Два NodePort-сервиса открывают его наружу: 30128 для прокси и 30444 для Stats UI HAProxy.

Без аутентификации

На Tor-прокси намеренно нет аутентификации. Exit IP — это Tor exit nodes: они публичны, их логирует каждый крупный CDN, и они ротируются каждые 30 минут. Добавлять пароль было бы имитацией безопасности. NodePort открыт на публичном IP VPS, так что технически прокси может воспользоваться кто угодно, но на практике никто не знает порт.

Если бы это была общая инфраструктура, я бы добавил проверку заголовка Proxy-Authorization в HAProxy. Для персональной установки с 5 цепочками и интервалом пересборки 1800 секунд — не имеет значения.

Задержки

Tor медленный. Прямой curl https://ifconfig.me с VPS занимает ~50 мс. Через Tor-прокси — обычно 2–8 секунд в зависимости от того, какой exit node в цепочке. Для задач, где нужен другой IP, это нормально. Для стриминга — нет.

bash# проверить ротацию — каждый вызов должен вернуть другой IP
for i in 1 2 3 4 5; do
  curl -s --proxy http://91.184.248.13:30128 https://ifconfig.me
  echo
done

В хороший день 5 запросов дадут 4–5 различных IP.

Интеграция со статистикой HAProxy

Эндпоинт статистики :30444/haproxy?stats;csv;norefresh возвращает CSV с одной строкой на каждый бэкенд. Эндпоинт /stats/tor на странице прокси забирает этот CSV, парсит его и возвращает JSON:

json{
  "ok": true,
  "backends": [
    {"name": "tor1", "status": "UP", "scur": 0, "stot": 12, "bin": 4096, "bout": 8192},
    ...
  ],
  "total_stot": 60,
  "total_bin": 20480,
  "total_bout": 40960
}

Фронтенд опрашивает его каждые 60 секунд и рендерит таблицу со статусом и накопленным трафиком каждой цепочки.

Пересборка цепочки vs NEWNYM

Здесь есть два разных способа «ротировать» цепочки:

  1. Сигнал NEWNYM (каждые 10 минут по умолчанию) — говорит Tor построить новую цепочку для будущих потоков. Быстро, но старая цепочка может сохраняться для открытых соединений.
  2. Полный перезапуск контейнера (TOR_REBUILD_INTERVAL=1800) — убивает все Tor-процессы и запускает их заново. Гарантирует свежие цепочки, но даёт ~60 секунд простоя, пока Tor строит начальные цепочки и подключается к сети.

TOR_REBUILD_INTERVAL в Kubernetes-манифесте — 1800 (30 минут). Для большинства задач хватает NEWNYM; полная пересборка — скорее страховка на случай, если цепочка застряла.

Скрипт установки

Скрипт k0s-setup/21-setup-tor-proxy.sh применяет манифест, ждёт перехода пода в Running, затем выдерживает паузу в 60 секунд, пока Tor строит начальные цепочки, и только потом запускает проверку из 3 запросов. Пауза важна: прокси принимает соединения сразу, но возвращает ошибки, пока Tor реально не подключился к сети.

bashssh root@server 'bash -s' < k0s-setup/21-setup-tor-proxy.sh

Скрипт печатает exit IP для каждого из 3 тестовых запросов. Если видите 3 разных IP — ротация работает.


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

Прокси возвращает ошибки сразу после запуска:
Tor нужно 30–90 секунд на bootstrap цепочек после старта контейнера. Liveness probe должен учитывать это:

yamllivenessProbe:
  httpGet:
    path: /haproxy?stats;csv;norefresh
    port: 4444
  initialDelaySeconds: 90
  periodSeconds: 30

Все 5 запросов возвращают одинаковый IP:
Возможно, HAProxy некорректно распределяет запросы по кругу или все цепочки используют один exit node. Попробуйте увеличить TOR_INSTANCES до 10 и проверьте статистику на порту 30444.

Очень медленно или 100% ошибок:
Некоторые страны блокируют Tor. Проверьте, не находится ли ваш VPS-провайдер в регионе с ограничениями.

bashkubectl exec -n tor deploy/tor-proxy -- tor --verify-config
kubectl logs -n tor deploy/tor-proxy | grep -i error

Лимиты ресурсов

Tor мало нагружает CPU, но требователен к памяти. Каждая цепочка использует ~50 МБ RAM. Для 5 экземпляров:

yamlresources:
  requests:
    memory: "256Mi"
    cpu: "50m"
  limits:
    memory: "512Mi"
    cpu: "200m"

На VPS с 2 ГБ RAM 5 экземпляров — безопасное число. Для 10 экземпляров стоит поднять лимит до 1 ГБ.


Итог

Компонент Назначение
N Tor-процессов Каждый держит независимую цепочку
HAProxy Round-robin по всем цепочкам
Сигнал NEWNYM Обновление цепочек без перезапуска
TOR_REBUILD_INTERVAL Принудительная полная пересборка
NodePort 30128 Доступ к HTTP-прокси
NodePort 30444 Stats UI HAProxy