Skip to content
Back to skills

Tor Building On Tor Software Patterns

BSecurity

Use when writing code that talks to Tor — SOCKS with socks5h and stream isolation, the control port, ephemeral onion services via ADD_ONION or stem, long-lived onion services in torrc, client authorization v3, Onion-Location and Alt-Svc headers, torsocks and its limits, embedding Arti, testing against a private chutney network, and building your own private or custom onion-routing network. Covers §13.1–§13.4, §13.6 and handbook §1. Companion to the other Tor and onion-network skills.

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agentspythonrustgobashnodetestinggitapibackend

Works with

  • cli
  • api

Security analysis

B88/100
  • mediumUses curl or wget to download content
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 19, 2026

npx -y skills add the-vibey-project/vibey --skill tor-building-on-tor-software-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tor Building On Tor Software Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Tor Building On Tor Software Patterns
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/the-vibey-project-tor-building-on-tor-software-patterns/badge)](https://www.skillsdirectory.com/skills/the-vibey-project-tor-building-on-tor-software-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: tor-building-on-tor-software-patterns
description: "Use when writing code that talks to Tor — SOCKS with socks5h and stream isolation, the control port, ephemeral onion services via ADD_ONION or stem, long-lived onion services in torrc, client authorization v3, Onion-Location and Alt-Svc headers, torsocks and its limits, embedding Arti, testing against a private chutney network, and building your own private or custom onion-routing network. Covers §13.1–§13.4, §13.6 and handbook §1. Companion to the other Tor and onion-network skills."
---

# Building on Tor: Software Patterns

> **Part 7 of 8** of the *Tor and Onion Networks* reference (plugin `tor-and-onion-networks`),
> covering §13.1–§13.4, §13.6 and handbook §1. Sibling skills:
> `tor-protocol-circuits-and-cell-cryptography` (§1–§5),
> `tor-network-consensus-guards-and-paths` (§6–§7),
> `tor-onion-services-and-hardening` (§8–§9),
> `tor-censorship-circumvention-and-bridges` (§10),
> `tor-attack-literature-and-threat-model` (§11),
> `tor-ecosystem-alternatives-and-governance` (§12, §14–§16),
> `tor-running-relays-bridges-and-hardware` (§13.5 and handbook §2–§6).
> Section numbers are shared across the set; a reference written as §N → `skill` points into
> that sibling skill.
>
> **Currency:** compiled 16 September 2026. Config options checked against C tor **0.4.9.x**
> (stable since Feb 2026) and Arti **2.6.x** (Sept 2026). When in doubt: `man tor`,
> <https://community.torproject.org/>, <https://onionservices.torproject.org/>.

> **⚠️ Five patterns cover essentially all software built on Tor. Pick the one that matches
> your assurance requirement, not the one that is least work.**
>
> **⚠️ GOTCHA** boxes mark where the obvious approach silently leaks.
>
> **The three ideas that organize this document:**
> 1. **⚠️ `socks5h`, NOT `socks5`** (§13.1). **The `h` makes the *exit* resolve the hostname.
>    Without it you do a local DNS lookup for the destination you are trying to hide — the
>    single most common Tor-integration leak, and it fails silently.**
> 2. **⚠️ STREAM ISOLATION IS A PRODUCT DECISION, NOT A TUNING KNOB** (§13.1). **SOCKS
>    username/password pairs become isolation tokens, so distinct credentials get distinct
>    circuits. That is how you stop two tenants, or two identities, sharing an exit.**
> 3. **⚠️ EPHEMERAL SERVICES BEAT FILESYSTEM KEYS FOR MOST APPS** (§13.2). **`ADD_ONION
>    NEW:ED25519-V3 Flags=DiscardPK` keeps the key in memory only and dies with the process.
>    OnionShare, Ricochet Refresh and Briar all work this way — no key management, no torrc
>    edits, nothing on disk to seize.**

---

## §13. The five patterns

Conceptually, building on Tor falls into five patterns:

1. **SOCKS-integrated apps** — the minimal, safest pattern: point your app at tor's SocksPort
   (127.0.0.1:9050; 9150 for Tor Browser) using `socks5h` so DNS resolves *at the exit*. Add
   stream-isolation credentials per tenant/connection class.
2. **Ephemeral onion services** — your app speaks `ADD_ONION NEW:ED25519-V3` to the control
   port, publishes a one-shot service, and tears it down on exit.
3. **Long-lived onion services** — torrc `HiddenServiceDir`/`HiddenServicePort`, optionally
   client auth, offline master keys, PoW, Onionbalance backends, and Onion-Location/Alt-Svc on
   the clearnet twin.
4. **Embedding Tor** — ship tor/Arti as a library (arti-client crate, Tor.framework,
   IPtProxy/tor-android, onionmasq for VPN-style capture) inside your product.
5. **Network-layer building** — relays, bridges, exits, transparent-proxy gateways, two-box
   isolation. See §13.5 → `tor-running-relays-bridges-and-hardware`.

Building your *own* network — rather than building on Tor — is a different decision tree with
its own three options: §13.6.

---

## §13.1 The SOCKS interface (the boring, correct way)

- C tor default: `127.0.0.1:9050`. Tor Browser: `9150`.
- **Always use `socks5h` / `--socks5-hostname`** so name resolution happens *at the exit* —
  otherwise you resolve DNS locally and leak the destination.

```bash
# Verify egress + get your exit IP (official oracle):
curl --socks5-hostname 127.0.0.1:9050 https://check.torproject.org/api/ip
# → {"IsTor":true,"IP":"<exit-address>"}

# Per-connection stream isolation: SOCKS username/password become isolation tokens
# (IsolateSOCKSAuth is default). Two different credentials → two different circuits.
curl --socks5 127.0.0.1:9050 --proxy-user tenant-a:pw https://example.org
curl --socks5 127.0.0.1:9050 --proxy-user tenant-b:pw https://example.org
```

```python
# Python; needs requests[socks]
import requests
s = requests.Session()
s.proxies = {"http": "socks5h://127.0.0.1:9050", "https": "socks5h://127.0.0.1:9050"}
print(s.get("https://check.torproject.org/api/ip").json())
```

Stream isolation flags you should know (apply per `SocksPort` line):

```
SocksPort 9050 IsolateDestAddr IsolateDestPort   # one circuit per destination host+port
SocksPort 9062                                    # dedicated port for one app = hard isolation
```

### Per-site circuits in your own tooling

Tor Browser isolates streams per first-party domain. Replicate the idea in services: distinct
SOCKS credentials per logical tenant, or `NEWNYM`-driven circuit freshening via the control
port for long batch jobs.

> **⚠️ GOTCHA:** `SIGNAL NEWNYM` is rate-limited to roughly once per 10 seconds, and **it does
> not reset your guards** (by design — see §7.1 → `tor-network-consensus-guards-and-paths`).
> Use isolation credentials when you can; NEWNYM is the blunt instrument.

---

## §13.2 The control port and ephemeral onion services

Enable the controller (Debian/Ubuntu pattern):

```
ControlPort 9051
CookieAuthentication 1
CookieAuthFileGroupReadable 1     # then: sudo usermod -aG debian-tor youruser
```

**Ephemeral onion service** — no torrc edits, keys live only in memory (this is the
OnionShare / Ricochet Refresh pattern). With **stem** (`pip install stem`; unmaintained since
~2020 but still the canonical library — see §12.3 →
`tor-ecosystem-alternatives-and-governance`):

```python
from stem.control import Controller

with Controller.from_port(port=9051) as ctl:
    ctl.authenticate()  # reads the cookie automatically
    svc = ctl.create_ephemeral_hidden_service(
        {80: ("127.0.0.1", 8000)},   # onion :80 -> local 8000
        await_publication=True,
    )
    print(f"http://{svc.service_id}.onion")
    # keep the controller connection open; the service dies when it closes
    input("Serving. Press enter to tear down.\n")
```

Raw protocol equivalent (useful when porting to other languages — spec: `control-spec.txt`):

```
AUTHENTICATE <cookie-hex>
ADD_ONION NEW:ED25519-V3 Flags=DiscardPK Port=80,127.0.0.1:8000
```

`Flags=DiscardPK` tells tor *not* to return the private key (service unrecoverable by design).
Async alternatives: **txtorcon** (Twisted, most battle-tested for services), **aiostem**
(asyncio).

---

## §13.3 Long-lived onion services (torrc)

```
HiddenServiceDir /var/lib/tor/mysvc/
HiddenServiceNumIntroductionPoints 3
HiddenServicePort 80 127.0.0.1:8080        # onion :80 -> local web app
#HiddenServicePort 443 unix:/run/mysvc.sock # unix sockets supported
```

- Address and keys appear under `HiddenServiceDir` (`hostname` file holds the 56-char
  address). Permissions must be `0700`, owned by the tor user.
- **Offline master keys**: generate the `hs_ed25519_secret_key` on an offline machine
  (`tor --keygen` in a scratch datadir), archive the encrypted master, and deploy only the
  signing material — a box compromise then doesn't compromise the address permanently.
- **DoS hardening** (PoW, requires tor built with `--enable-gpl` for Equi-X/HashX):

```
HiddenServicePoWDefensesEnabled 1
HiddenServicePoWQueueRate 250
HiddenServicePoWQueueBurst 2500
MetricsPort 127.0.0.1:9035
MetricsPortPolicy accept 127.0.0.1    # scrape tor_hs_pow_* with Prometheus
```

- **Client authorization v3** (private services): the server keeps an `authorized_clients/`
  directory inside `HiddenServiceDir`, one `<name>.auth` file per client containing
  `descriptor:x25519:<base32-pubkey-no-padding>`; each client adds a `<56chars>.auth_private`
  file (`<addr>.onion:descriptor:x25519:<base32-priv>`) to its `ClientOnionAuthDir`. Generate
  x25519 pairs with any standard crypto library and base32-encode the raw 32-byte keys per
  `rend-spec-v3`.
- **Load balancing**: run `HiddenServiceOnionbalanceInstance 1` on each backend pointing at
  the Onionbalance master.

> **⚠️ GOTCHA (as of 2026): PoW and Onionbalance don't mix.** Choose per threat model — DoS
> resistance on a single instance, or horizontal scale across backends. See §9.2–§9.3 →
> `tor-onion-services-and-hardening`.

---

## §13.4 Advertising the onion from your clearnet site

```nginx
# nginx — Tor users get the ".onion available" pill (Tor Browser ≥ 9.5)
add_header Onion-Location http://<your56>.onion$request_uri;

# transparent variant: Tor-capable clients switch to onion silently
add_header Alt-Svc 'h2="<your56>.onion:443"; ma=86400';
```

Serve these over HTTPS from the clearnet origin only (**never** from the onion itself).

---

## §13.4a Non-SOCKS apps: torsocks and its honest limits

```
torsocks curl https://check.torproject.org/api/ip
```

torsocks is `LD_PRELOAD` shimming: TCP only, breaks on apps using raw syscalls, no UDP, and it
*silently* does nothing for apps that bypass libc (statically linked Go/Rust binaries).

> **⚠️ GOTCHA — this is the dangerous one.** A statically linked binary under `torsocks`
> connects **directly**, with no error and no warning. Rule of thumb: **torsocks for
> convenience, never for high-stakes assurance.** For assurance, use app-native SOCKS or a
> fail-closed network sandbox (§13.5 → `tor-running-relays-bridges-and-hardware`, §4.3–4.4).
> `proxychains` shares the architecture *and* the caveats, with worse defaults.

---

## §13.4b Arti as a library and daemon

Arti (Rust) is the future embedding path: no fork of an external process, memory safety, and —
since 1.8.0 (Dec 2025) — production-grade onion services with native vanguards.

```toml
# ~/.config/arti/arti.toml  (minimal client)
[proxy]
socks_listen = "127.0.0.1:9150"
dns_listen = "127.0.0.1:15354"
```

```rust
// embedding: arti-client = "0..." (API churned through 2.x — pin + read changelog)
use arti_client::{TorClient, TorClientConfig};

let tor = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
let stream = tor.connect(("check.torproject.org", 443)).await?;
```

C-tor → Arti service migration: `arti hsc ctor-migrate` (2.x) ports hidden-service keys. Watch
the `arti hss` tooling and Arti RPC — both are the fast-moving surface in 2026. **onionmasq**
(from the Tor VPN project) gives you a userspace TUN interface over Arti: route whole
applications without them knowing.

---

## §13.4c Developing against a test network: chutney

**Never integration-test against the production network.** Chutney runs a private mini-Tor on
localhost:

```bash
git clone https://gitlab.torproject.org/tpo/core/chutney.git
cd chutney
./chutney configure networks/basic
./chutney start    networks/basic
./chutney verify   networks/basic
./chutney status   networks/basic   # shows per-node SOCKS/Control ports to point tests at
```

---

## §13.6 Building your own private network

"I want a private network" almost always resolves to one of three architectures, separated by
two orders of magnitude of effort. Pick before you build.

| Option | What it is | When it is right |
|---|---|---|
| **A — public Tor + v3 onion services with client authorization** | Your services are onion services on the public network; only holders of a client key can see them | Almost every real case: organizational privacy, private infrastructure, SecureDrop- and OnionShare-style deployments |
| **B — your own Tor network** | Your own directory authorities, relays and clients, isolated from public Tor | Testing, research, or a closed organizational network that must not touch public Tor at all |
| **C — a custom onion routing network** | Tor-like software of your own, with different trade-offs | Research, or a genuinely different threat model (§13.6.3) |

### §13.6.1 Option A — use the public Tor network (the right answer for most cases)

Run a tor client on your server, configure a `HiddenServiceDir` with client authorization
(§13.3), distribute `.auth_private` files to your authorized users, and let them connect via
Tor Browser or a Tor-integrated application. The service is invisible to anyone without a
client key. You get location-anonymous hosting, encryption by construction, authentication of
*both* directions, and the whole public relay set — without operating any of it. Add PoW for
DoS resistance and vanguards for guard-discovery resistance (§9 →
`tor-onion-services-and-hardening`). This is what SecureDrop and OnionShare do.

> **⚠️ GOTCHA:** running your own network *reduces* your anonymity set. On public Tor your
> traffic hides among several million daily users; on a twenty-relay private network,
> "someone used the network" is a much smaller set, and its operator knows who the
> participants are. Isolation from public Tor is an availability and control property, not an
> anonymity upgrade — choose B or C because you need control, never because you want more
> anonymity than A gives you.

### §13.6.2 Option B — run your own Tor network (chutney, and past it)

Chutney is not only a test harness (§13.4c). `networks/basic` is a complete miniature Tor —
**3 directory authorities plus relays and clients** — and a custom network definition is how
you grow one:

```bash
./chutney configure networks/basic   # 3 authorities + relays + clients
# For a larger private network, write a custom network definition with your own
# authorities, relays and exits. Each node gets its own torrc and data directory.
```

For a *production* private network you need: **at least 3 directory authorities**, run on
different infrastructure in different locations; a sufficient number of relays for bandwidth
and redundancy; your own consensus process (your authorities vote hourly exactly as public
Tor's nine do — §6.2 → `tor-network-consensus-guards-and-paths`); and client software
configured to use *your* authorities instead of the public ones. It is a substantial
undertaking, and what it buys is complete control over who participates. Operator mechanics
and the verification checklist: handbook §2 and §5 →
`tor-running-relays-bridges-and-hardware`.

### §13.6.3 Option C — build a custom onion routing network

If you want something Tor-like with different trade-offs — different circuit lengths, guard
strategies, crypto — four core components have to exist; onion services are optional:

1. **Relay software.** Authenticates to neighbours (ed25519 identities), accepts
   circuit-building commands, performs onion encryption/decryption on relay cells (§3 →
   `tor-protocol-circuits-and-cell-cryptography`).
2. **Directory system.** Some mechanism for clients to discover relays — Tor's nine
   hourly-voting authorities, a single trusted directory server, a threshold-signature scheme,
   a DHT, a blockchain. The two properties that matter whatever you pick: **clients must get a
   consistent view of the relay set**, and **an attacker must not be able to inject relays
   cheaply**.
3. **Path selection.** Three relays subject to constraints (no shared operator, no shared
   subnet, exit policy permits the destination), guards pinned for months (§7 →
   `tor-network-consensus-guards-and-paths`). The algorithm *is* the anonymity property.
4. **Client software.** Telescoping circuit construction, guard state, a SOCKS interface,
   stream isolation (§13.1).
5. **Onion services (optional).** Introduction points, descriptor publication to HSDirs,
   rendezvous points, client authorization, and a key-derived self-authenticating address
   (§8 → `tor-onion-services-and-hardening`).

> **⚠️ KEY DESIGN PARAMETERS.** Circuit length (3 is standard; more hops raise latency and
> the attacker's cost together). Guard rotation period (months is standard; shorter raises
> exposure probability). Directory trust model (authorities vs. DHT vs. blockchain). Crypto
> primitives (ntor for the handshake; CGO or an AEAD for cells). Whether to support onion
> services. Whether to support pluggable transports. Whether the network is **open** (anyone
> joins) or **closed** (known participants only). These seven choices determine what your
> network is; everything else is implementation.

Implementation checklist:

- **Use vetted cryptographic libraries** (libsodium, libsecp256k1) — never implement
  primitives yourself.
- **ntor or X25519 for the handshake** (§4.1 → `tor-protocol-circuits-and-cell-cryptography`).
- **An AEAD for cell crypto** (ChaCha20-Poly1305 or AES-GCM). **Do not use CTR mode without
  authentication** — malleability is exactly what enables tagging attacks (§4.2 →
  `tor-protocol-circuits-and-cell-cryptography`). Note that Tor's own CGO is *not* a stock
  AEAD: it needs a rugged PRP because relays must transform cells through a deliberately
  malleable decrypt path. Reach for CGO only if you have that same constraint; otherwise a
  standard AEAD per hop is the safer build.
- **Guard pinning from day one** and **path restrictions (family, subnet) from day one** —
  both are far harder to retrofit than to build in.
- **Test against chutney-style adversarial scenarios** (§13.4c).
- **Have a plan for relay discovery and Sybil resistance** before you have relays.
- **Consider using Arti as a foundation rather than starting from zero** (§12.1 →
  `tor-ecosystem-alternatives-and-governance`).

---

## Where to go next

- Relays, bridges, exits, transparent proxies, hardware builds, verification and abuse
  handling: §13.5 → `tor-running-relays-bridges-and-hardware`.
- What a v3 onion service is actually doing underneath this configuration: §8 →
  `tor-onion-services-and-hardening`.
- Why `socks5h` matters — where the anonymity boundary actually sits: §3.3 →
  `tor-protocol-circuits-and-cell-cryptography`.
- Library and implementation choices: §12 → `tor-ecosystem-alternatives-and-governance`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…