Skip to content

Repository files navigation

multi-proxy-nodes

SOCKS5 proxy pool: HAProxy + N Tor exit nodes in Docker with dynamic service discovery.

Architecture

Client (SOCKS5) -> HAProxy (TCP :1080, leastconn) -> tor (N replicas, SOCKS5 :9050)
                                                       ^
Discovery (every 15s) -> HAProxy Runtime API (:5555): add/enable/del backends dynamically
Rotator (every 60s)   -> DNS -> all replica IPs -> SIGNAL NEWNYM via ControlPort

Each Tor node gets a fresh circuit <= 60s via MaxCircuitDirtiness 60 + SIGNAL NEWNYM. New connections use new circuits; in-flight connections are not interrupted. Backends are discovered dynamically via Docker DNS and HAProxy Runtime API.

Quick Start

cd multi-proxy-nodes

# Generate .env
cp .env.example .env
# Edit .env - set CONTROL_PASSWORD
#   openssl rand -base64 24   (use output as CONTROL_PASSWORD)

# Start with 5 Tor replicas
docker compose up -d --build --scale tor=5

# Wait for bootstrap
echo "Waiting 120s..."
sleep 120

# Test
curl -s -x socks5h://127.0.0.1:1080 https://check.torproject.org/api/ip
# {"IsTor": true, "IP": "some.tor.exit.ip"}

# Stats
curl -s -u "admin:changeme" http://127.0.0.1:8404/stats | grep "UP"

Or one-shot: bash scripts/setup.sh 5

Config

Variable Default Purpose
CONTROL_PASSWORD required Tor ControlPort auth
STATS_PASSWORD changeme HAProxy stats page auth
ROTATE_INTERVAL 60 Seconds between rotation cycles
SOCKS_PORT 1080 Host port for SOCKS5
STATS_PORT 8404 Host port for stats page

Service Discovery

This project uses dynamic service discovery instead of hardcoded backend servers:

  1. Discovery container (tor-discovery): resolves the Docker DNS name tor every 15s (5 queries to beat DNS round-robin), then diffs against current HAProxy backends via the Runtime API (TCP :5555). New IPs get add server + enable server; stale IPs get del server.
  2. Rotator (tor-rotator): similarly resolves tor via DNS each cycle to find all replica IPs, then sends AUTHENTICATE + SIGNAL NEWNYM to each ControlPort every 60s.

This eliminates the need to regenerate config files when scaling (docker compose up -d --scale tor=N).

Security Notes

  • ControlPort protected by HashedControlPassword (generated from CONTROL_PASSWORD at container start)
  • Stats page requires HTTP Basic Auth
  • SOCKS5 frontend (1080) has no auth - restrict to localhost via firewall if exposed externally
  • All services on isolated torpool bridge; only HAProxy ports exposed to host
  • Tor container runs as non-root (tor user, Alpine system user)
  • HAProxy Runtime API on TCP :5555 (internal torpool network only)
  • CONTROL_PASSWORD visible in docker inspect and /proc/*/environ - use Docker Swarm secrets for production
  • Base images: alpine:3.21@sha256:..., haproxy:3.0-alpine@sha256:... (pinned digests)

Troubleshooting

Symptom Fix
curl hangs Tor bootstrapping - wait 2 min
curl returns 503 Backends DOWN - docker compose logs haproxy or docker compose exec discovery bash -c 'echo "show servers state tor_pool" | socat - tcp:haproxy:5555'
Rotator shows FAIL Wrong CONTROL_PASSWORD or Tor still bootstrapping (normal first 2 min)
Stats returns 401 Use admin:changeme or check STATS_PASSWORD in .env

Scaling

# Scale up to 20 replicas (hot, no rebuild needed)
docker compose up -d --scale tor=20

# Discovery adds new backends within 30s
sleep 30

# Back to 3 replicas
docker compose up -d --scale tor=3
sleep 30

Cleanup

docker compose down -v   # removes containers + volumes

Logs

docker compose logs -f                     # all services
docker compose logs tor | grep -i boot     # Tor bootstrap progress
docker compose logs discovery --tail 5     # latest discovery cycles
docker compose logs rotator --tail 5       # latest rotation cycle
docker compose exec discovery bash -c 'echo "show servers state tor_pool" | socat - tcp:haproxy:5555' | awk '!/^#/ && NF>0 {print $4, $5, "op=" $6}'  # backends status

About

SOCKS5 proxy pool: HAProxy + Tor container swarm in Docker with dynamic service discovery and automatic circuit rotation.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages