v0.1.0
The first release with notes. The earlier v0.0.x tags were created automatically by
every push to main, so their numbers counted pushes rather than changes and none of
them was ever accompanied by an entry here — this release is also where that stopped.
Added
- A pool of Tor instances in one container, behind a single sticky SOCKS5 and HTTP proxy
endpoint. - Sticky sessions. The SOCKS5 username (or
Proxy-Authorizationuser) is a session
key; a caller keeps the same instance, and so the same exit IP, until it rotates.
Callers with no credentials are pinned by client IP. - Instant rotation.
POST /api/sessions/{key}/rotatereassigns a session to an
already-built instance, skipping Tor's ~10s NEWNYM cooldown. - Failure-driven remediation. Failures are counted per instance from transport
errors and from client reports, and a bad instance escalates through new circuit →
wipe-restart → restart with exponential backoff. - Management dashboard with live updates over SSE: instance grid with per-instance
actions, sessions view, filterable audit log, and timeline charts. - REST API for instances, sessions, events and history, plus live pool resize.
- Prometheus metrics at
/metrics, and a/healthcheck that reports routability
rather than process health. - Multi-arch images (
linux/amd64,linux/arm64) onghcr.io/lncrawl/tor-pool. PIN_EXIT_RELAYlocks each instance to a single exit relay, so one instance really
is one exit IP until it rotates. Off by default: a pinned instance depends on one relay.BOOTSTRAP_STALL_TIMEOUTrestarts an instance that stops making bootstrap progress,
keeping its state on the first attempt and wiping it on the next.exit_confirmedandpinned_exiton the instance API, surfaced in the dashboard: an
exit no traffic has used yet is shown as the guess it is.
Changed
latestnow means the newest release, not the last push tomain. Every push used
to bump a patch tag and movelatest, so a README fix became a version number and
unreleased work reached everyone trackinglatest. Pushes tomainpublishedge;
releases are cut deliberately fromCHANGELOG.md. The weekly rebuild is gone with it —
tornow updates when you pull a newer image rather than on a timer.- Conflux is off by default (
TOR_CONFLUX). Each set Tor pre-builds has its own exit
relay and successive requests land on different sets, so one instance handed a caller
several exit IPs with no rotation at all. POST /api/instances/{id}/rotatereturns as soon as the instance is out of service,
finishing Tor's cooldown in the background, instead of holding the request open for up to
~13 seconds.
Fixed
- Rotation no longer drops requests in flight. Retiring an instance's circuits spared
only the ones carrying a connected stream, so a request still waiting for its exit to
reach the destination had its circuit closed underneath it. Measured at 4–5% of requests
failing while rotating under load, against 0% at rest. Any circuit with a stream on it is
now left standing, whatever state that stream is in. - A rotation no longer quarantines the instance it rotated. The failures a rotation
causes were scored against the instance, so a few rotations were enough to quarantine a
healthy one — whose remediation rotated it again. Failures inside an instance's own
rotation window are no longer counted against it. POST /api/pool/rotatekeeps the pool serving. It rotated every instance at once,
leaving nothing to route to for a second or two. It now sweeps one instance at a time and
returns immediately, reporting whether a sweep was already running.- The reported exit IP no longer jumps after a rotation. Tor holds several
exit-bearing circuits and builds more preemptively, and the API named whichever looked
newest — an exit no traffic had used. Only a circuit carrying a stream now confirms an
exit, an inferred one can never displace a confirmed one, andexit_confirmedsays which
it is. - A session is no longer routed to an instance that is mid-rotation. Diverting covered
the sessions pinned when the rotation began, but not the ones arriving during it. - A stalled bootstrap is now remediated. Tor can wedge part-way through with a live
process, which neither the supervisor nor the failure ladder catches, leaving the pool
quietly under strength — instances were observed sitting at 45% indefinitely. See
BOOTSTRAP_STALL_TIMEOUT. - The maintenance loop cannot be stalled by a control port. The exit poll shared a loop
with session sweeping and process supervision, and one instance's NEWNYM cooldown blocked
all three for up to ten seconds — a pool-wide rotation, for tens of seconds. Control
commands also had no I/O deadline, so a Tor that stopped answering wedged it forever. - HTTP proxy: keep-alive requests are routed individually. A client sending requests
for several hosts down one proxy connection had the second delivered to the first host.
Each request is now routed and dialled on its own, which also means a rotation takes
effect on the next plain request rather than when the client happens to reconnect. - HTTP proxy: IPv6 destinations work. A bracketed literal was passed to Tor as a
hostname to resolve. - A control connection lost while Tor keeps running is redialled, instead of leaving an
instance that serves traffic but can never be rotated or report its exit again. - Rotating an instance that has not bootstrapped is refused with 409 rather than spending
the NEWNYM cooldown on a Tor with no circuits — which silently swallowed the rotation
asked for once it was ready. - Rotating a session that lands back on its own instance (a one-instance pool, or one
instance routable) now rotates that instance's circuit, instead of reporting success
while changing nothing. - Instance indexes are reused instead of counted upwards, so enough resizes can no longer
hand an instance a SOCKS port that is another instance's control port. - Remediation backoff grows with the attempts at the current rung, not with the instance's
lifetime count — an instance that misbehaved last week no longer starts at maximum
backoff. - Retired instances no longer leave their per-instance counters behind, a resize honours
SPAWN_STAGGER,POST /api/instances/{id}/drainanswers 404 for an instance that does
not exist, and?newnym=1is accepted alongside?newnym=true. - Fixed data races on an instance's process handle during a restart, and on the NEWNYM
cooldown timestamp.