Ротирующий 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
Здесь есть два разных способа «ротировать» цепочки:
- Сигнал NEWNYM (каждые 10 минут по умолчанию) — говорит Tor построить новую цепочку для будущих потоков. Быстро, но старая цепочка может сохраняться для открытых соединений.
- Полный перезапуск контейнера (
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 |