Manage a multi-region Tor proxy pool entirely from the terminal.
a single-file TUI that gives you one tor instance per exit country, with per-instance SOCKS5 + HTTP ports, exit-country verification and systemd supervision.
| OS | Debian 9+ / Ubuntu 18.04+ (any Linux with bash 4.4+ and systemd) |
| Architecture | x86_64, i686, arm64 (anything your distro ships tor for) |
| Packages | tor, tor-geoipdb, curl, iproute2, gawk (auto-installed on apt systems) |
curl -fsSL https://raw.githubusercontent.com/xHossein/torpool/master/torpool.sh -o /tmp/torpool \
&& sudo install -m 755 /tmp/torpool /usr/local/bin/torpool \
&& sudo torpoolAfterwards just sudo torpool from anywhere.
To try it without installing:
bash <(curl -fsSL https://raw.githubusercontent.com/xHossein/torpool/master/torpool.sh)
On first run a setup wizard installs the dependencies, disables the distro's always-on tor.service (torpool runs its own per-country instances instead), creates the layout under /opt/torpool and registers the systemd template unit.
| Key | Action |
|---|---|
| ↑ ↓ | Move (k j also work) |
| Space | Toggle (multi-select) |
| a / n | Select all / none |
| / | Filter |
| 1-9 | Jump straight to an entry |
| Enter | Confirm |
| Esc | Back |
| q | Quit |
Every instance binds SOCKS5 + HTTP to 127.0.0.1 only.
curl -x http://127.0.0.1:19843 https://ifconfig.co/json # HTTP
curl -x socks5h://127.0.0.1:21471 https://ifconfig.co/json # SOCKS5Use socks5h:// rather than socks5:// so DNS is resolved through tor instead of leaking to your local resolver.
Each instance pins its exit with ExitNodes {cc} and StrictNodes 1, so tor will refuse to use any other exit rather than silently falling back to one.
That is not the whole story, though: tor picks the exit using its own bundled GeoIP database, while the rest of the internet geolocates you with commercial feeds, and the two disagree regularly. torpool therefore verifies every instance end-to-end by fetching its real exit IP through the proxy and asking, in order:
ifconfig.co/jsonfree.freeipapi.com/api/jsonapi.myip.comapi.country.is
| Verdict | Meaning |
|---|---|
ok |
the exit IP geolocates to the country you asked for |
mismatch |
tor pinned the country, but the geo-IP feeds place the exit elsewhere |
unknown |
no provider could place the IP — not treated as a mismatch, so it never triggers a rotation |
booting |
still bootstrapping, below 100% |
unreachable |
the proxy answered nothing — circuit still building, or the exit is dead |
down |
the systemd service is not running |
Rotate exit IP / verify country in the menu gives you three actions:
| Action | What it does |
|---|---|
| Verify exit country now | probes and reports, changes nothing |
| Rotate exit IP once | one SIGNAL NEWNYM, then re-probes |
| Rotate until the exit country matches | rotates repeatedly, parking each wrong exit in an ExcludeExitNodes list so it is not handed back |
tor enforces a ~10 s cooldown between
NEWNYMsignals per instance.
A cron job (/etc/cron.d/torpool) re-checks the pool on an interval you choose in the menu.
| Setting | Default | Behaviour |
|---|---|---|
| Interval | 5 min | how often the pool is checked |
| Auto-restart dead instances | on | restarts a service that has failed twice in a row |
| Auto-rotate on wrong country | off | when enabled, rotates an instance whose exit geolocates elsewhere |
History lands in /opt/torpool/logs/watchdog.log, and the last verdict per instance is shown in the rotate screen.
/opt/torpool/
├── bin/torpool # copy invoked by the cron watchdog
├── configs/ # torrc_<cc> per instance
├── instances/<cc>/ # DataDirectory + control auth cookie
├── consensus-cache/ # cached exit-relay counts per country
├── state/ # last verdict per instance
├── logs/watchdog.log # watchdog history
├── watchdog.conf # watchdog settings
└── bridges.conf # optional, %include-ed into every torrc
/etc/systemd/system/torpool@.service # template unit
/etc/cron.d/torpool # watchdog schedule
Each country is a systemd template instance:
systemctl status torpool@de # check one instance
journalctl -u torpool@de -f # follow its logs
systemctl restart torpool@de # restart it manuallyEach instance also opens a control port on 127.0.0.1 with cookie authentication. That is what rotation, bootstrap progress and tor's own GeoIP answer are read from.
| Option | Description |
|---|---|
--status |
Print the pool state and exit (no TUI) |
--verify [CC|all] |
Check the exit country of one or all instances |
--rotate [CC|all] |
Rotate until the exit country matches, then exit |
--watchdog-run |
Run one watchdog pass (used by the cron job) |
--no-color |
Disable ANSI colors |
--ascii |
Use ASCII-only borders |
-v |
Print version and exit |
-h |
Show help and exit |
TORPOOL_PREFIX |
Override the install prefix (default: /opt/torpool) |
TORPOOL_SYSTEMD_DIR |
Override the systemd unit directory (default: /etc/systemd/system) |
NO_COLOR |
Disable colors when set |
| Symptom | Fix |
|---|---|
Instance shows booting for a long time |
journalctl -u torpool@<cc> -f — usually no outbound network, or a censored connection that needs bridges in bridges.conf |
Instance shows unreachable |
The circuit is still building — give it 10-30 s, then rotate once |
GEO column shows XX or unknown |
Every geo-IP provider failed to place the exit. This is a lookup problem, not a tor problem, and torpool will not rotate because of it |
| Exit country keeps mismatching | Rotate until match; if it never settles, that country has few exits and the feeds disagree with tor's GeoIP about them |
Everything goes unreachable after many rotations |
The exclusion list starved the country of exits. torpool clears it automatically, or rm /opt/torpool/state/quarantine_<cc> |
Instance shows down |
Port conflict or a bad torrc: tor -f /opt/torpool/configs/torrc_<cc> --verify-config |
| Watchdog never runs | systemctl status cron (or crond) and check /etc/cron.d/torpool exists |
MIT. Unofficial wrapper around tor — not affiliated with or endorsed by The Tor Project.
