I am researching Tor, and as part of my research I was curious how many distinct exit relays a real-world client would include in building circuits. For my purposes, I am only interested in US exit nodes.

I found this project: https://github.com/mattes/rotating-proxy, which load balances proxy requests across multiple Tor instances. Specifically, HAProxy load balances over N polipo instances connected to the SOCKS port of N tor instances:

                          <-> Polipo 1 <-socks-> Tor Proxy 1
Client <-http->  HAproxy  <-> Polipo 2 <-socks-> Tor Proxy 2
                          <-> Polipo n <-socks-> Tor Proxy n

I modified the Tor arguments in order to maximize the diversity of exit nodes:

    --SocksPort {PORT}

    # Allow creating new circuits after 30 seconds
    --NewCircuitPeriod 30

    # Never reuse a circuit older than 120 seconds
    --MaxCircuitDirtiness 120

    # Only use exit nodes in the US
    --ExitNodes {us}

    # Do not operate an exit relay
    --ExitRelay 0

    # Allow exit nodes not in the consensus
    --RefuseUnknownExits 0

    # Operate in client mode only
    --ClientOnly 1

    # Interpret the above ExitNodes argument strictly (nly US)
    --StrictNodes 1

    # Allow exit nodes supporting single hop circuits (idk if this does anything)
    --AllowSingleHopCircuits 1

    --DataDirectory /var/lib/tor/10011
    --PidFile /var/run/tor/10011.pid
    --Log warn syslog
    --RunAsDaemon 1

The test:

  • Start the rotating proxy with 100 tor backends
  • Repeatedly request ipinfo.io/json through the rotating proxy, log the IP address
  • Sort the resulting file by unique IP addresses

Result after 30 minutes:

  • 1581 total requests
  • 66 unique IP addresses

Checking the haproxy stats page confirms that requests are being load balanced across all 100 tor instances.

Given that there are 500+ unique exit relays in the USA, I would expect far more unique IP addresses.

Why are there only 66 unique IP addresses? It appears that Tor is not rebuilding circuits as often as it should be, according to the arguments. Or it is rebuilding circuits, but keeping the same exit nodes.

Could it be because polipo is keeping a persistent socks connection?


I made some improvements and am now seeing better performance. I am still curious if I'm missing anything.

Improvements I made:

  • polipo was caching the ipinfo.io requests for each proxy, which obviously makes it hard to test if the IP is changing... I fixed this by adding ipinfo.io to /etc/polipo/uncachable and doing all further tests on my own test server that explicitly forces clients to NOT cache responses

  • I enabled the control port on each tor instance so that the daemonized docker script can periodically force a circuit change by sending the newnym signal to the control port ) via https://www.thesprawl.org/research/tor-control-protocol

Here are the new args:

"--NewCircuitPeriod 15",
"--MaxCircuitDirtiness 15",
"--NumEntryGuards 8",
"--CircuitBuildTimeout 5",
"--ExitNodes {us}",
"--ExitRelay 0",
"--RefuseUnknownExits 0",
"--ClientOnly 1",
"--StrictNodes 1",
"--AllowSingleHopCircuits 1",

So far the test has sent 175 requests, with 61 unique IPs... far better than before, in terms of percentages. We'll see.


2 Answers 2


It is good to see that you want to do research on the Tor network. First please make sure that you have Tor's ethical research guidelines in mind.

In general you try to create new circuits during short time periods. This puts some load on the nodes and on the network in general. Tor offers the possibility to create an own test network and furthermore there is the Tor Path Simulator. This helps you to answer all kinds of questions regarding circuit building inside Tor.

So please use another library and not the live network for your experiments.


Actually you need to tunnel your Tor instances through a different external IPs, better if even in different AS blocks. Use an IP pool and let's see the result ;)

  • I was thinking that might be the problem. Is this because the directory servers see multiple Tor clients coming from one IP address, and so they cache the "most optimized" circuits?
    – Miles R
    Mar 24, 2016 at 15:32
  • Yes, but not exactly like this
    – Alexey Vesnin
    Mar 24, 2016 at 15:33
  • The implication of your comment is that the client AS of a circuit maps deterministically to a subset of exit nodes. If two Verizon wireless customers on the east coast both connect to the Tor network, is it likely they will both receive circuits terminating at the same exit node? That seems like a problem for anonymity, since it enables you to build a mapping of exit node IP <--> AS numbers. It seems like Tor should be agnostic in assigning circuits to clients? Why should the IP address of a client affect the choice of exit node for its circuit? Does this have to do with guard nodes?
    – Miles R
    Mar 24, 2016 at 16:01
  • AS is a very strong filter. try to avoid same C-class networks etc - play with a filter rules
    – Alexey Vesnin
    Mar 24, 2016 at 16:07
  • Can I disable entry guards? Or would it help to set NumEntryGuards to a very high number?
    – Miles R
    Mar 24, 2016 at 16:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .