Agent index (llms.txt) — fetch this first, then the page it names.

Tor: the proxy, onion submission and the Orama Tor network

Every Orama node runs a Tor client. It is client-only: it relays nothing, opens no inbound port and never becomes an exit. Three things use it: the gateway's anonymity routes, the anon_fetch host function, and the relayed fetch relay. The CLI and SDK also use Tor to submit chain transactions.

The node's own Tor client described below is on the public Tor network, because the anonymity proxy needs public exits. Orama also has code for a separate, private Tor network run by its own directory authorities, with relays, opt-in exits and onion services on validators. That code has not been run against a real Tor network yet, and the public launch is switched off. See Orama's own Tor network.

What runs on a node

Daemontor from the Tor Project's apt repository, with the archive key pinned
Unitorama-namespace-tor@index, started by the supervisor
SOCKS127.0.0.1:9050 only
Config/etc/orama/tor/torrc
Data/var/lib/orama-tor

The torrc sets SocksPort 127.0.0.1:9050 IsolateSOCKSAuth, ClientOnly 1, ORPort 0, DirPort 0, ExitRelay 0 and ClientRejectInternalAddresses 1.

The unit is sandboxed (ProtectSystem=strict, MemoryDenyWriteExecute, 1 GB memory limit) and is denied network access to private ranges: 10/8, 172.16/12, 192.168/16, 169.254/16, 100.64/10, fc00::/7, fe80::/10. Tor can never reach the WireGuard mesh.

The installer installs Tor on orama maint node install and every upgrade, masks the distribution's own tor.service, and removes the old Anyone network if an earlier release left it. If Tor cannot be installed, the install fails: without it the anonymity routes would answer 503.

The gateway routes

RouteWhat it doesGateway sees
POST /v1/proxy/anonOne HTTP(S) request per call through Tor. Methods are allow-listed, body at most 10 MB, 60 second timeoutThe whole request and response, because the gateway performs it
GET /v1/proxy/tunnel (WebSocket)An opaque TCP stream to a destination, so TLS runs end to end with the destination. Ports 80 and 443 onlyThe destination host and port, not the content
GET /v1/proxy/relay (WebSocket)Anonymous relay used by relayed fetchSee that page

Both authenticated routes need the proxy grant and a genuine wallet session. An app key alone is refused with USER_JWT_REQUIRED: the point is that a signed-in person asked for it.

What the gateway logs

For POST /v1/proxy/anon the node log has one line per request, on completion or on failure. A completed request logs the method, the status the destination answered, the size of the response and the duration. A failed one logs the method, the duration and a class of failure: timeout, canceled or transport. It never logs the URL, the host, the path, the query string, the headers or the body, and it does not repeat the text of the error, because the error of a failed connection names the destination. The same holds for anon_fetch, which logs only the class of a failure. The per-request log that most gateway routes have (a request_logs row with the caller's address and API key id, and an access-log line) is switched off for /v1/proxy/anon and /v1/proxy/tunnel, as it is for the relay: they are only counted by status in the request metrics.

GET /v1/proxy/tunnel follows the same rule. The gateway sees the destination host and port, because it dials them, but its log has one line when a tunnel opens (no fields), one when it closes (the bytes sent in each direction and the duration) and, for a dial that failed, the class of the failure. It never logs the host, the port or the caller. GET /v1/proxy/relay logs nothing about a stream.

Tunnel limits: 24 tunnels per user, 512 per node, 30 minutes maximum, 256 MiB, 2 minutes idle. Each user gets their own Tor circuit (a distinct SOCKS isolation key). The tunnel is a WebSocket because Caddy does not forward CONNECT and only a few ports are open.

What this does not claim. The tunnel hides your destination from nobody but the destination's network path: the gateway sees the destination host and port. Do not tell your users that it hides the sites they visit from Orama.

Callers:

ts
// TypeScript SDK
const res = await client.network.proxyAnon({ url: "https://example.com/", method: "GET" });

The tunnel has no SDK wrapper; use the WebSocket directly. There is no orama CLI command for either route.

From a serverless function

A WebAssembly function calls the anon_fetch host function to make an outbound request through Tor. The old name anyone_fetch still works as a deprecated alias because shipped functions import it. See Functions.

Health

GET /v1/health reports checks.anon_proxy as ok or unavailable. A Tor outage is deliberately not an error: the node keeps serving and stays in DNS. orama maint inspect --subsystem tor and orama status show Tor state.

Submitting chain transactions over Tor

orama global, orama storage and orama cluster commands that send transactions take --onion <addr.onion[:port]> (or ORAMA_CHAIN_ONION) and --onion-socks <host:port> (or ORAMA_ONION_SOCKS, default 127.0.0.1:9050). The client:

  • +accepts only a v3 onion address (56 base32 characters plus .onion)
  • +talks plain HTTP to it, because Tor already encrypts end to end
  • +has no direct dialer, no environment proxy and no redirects
  • +uses a fresh random isolation credential, so each client gets a fresh circuit
  • +times out after 90 seconds, and on failure says the transaction was not sent and nothing was tried outside Tor

--node together with --onion is a usage error. Commands: orama global register|bond|capacity, the validator transaction commands, orama storage create|grant|prove, and orama cluster register-onchain|retire-onchain.

Reads (orama chain) do not go through Tor yet.

Add --onion-network <tor-network.json> (or ORAMA_ONION_NETWORK) instead of --onion to have the command start a Tor client for the Orama Tor network for that one run, pick one of the file's validator_onions at random and stop the client afterwards. --onion-socks together with --onion-network is a usage error, since they are two Tor clients.

The server side is an onion service on a validator, installed with orama global install --services onion. It forwards to orama maint global txgate, which serves three calls and nothing else of the chain's REST API: read the signer's account, broadcast, and look a transaction up. It logs no request. The wallet's proxy for it must be a client of the Orama Tor network, not the public one, which resolves none of its addresses.

Orama's own Tor network

A separate anonymity network built from unmodified upstream Tor and run by Orama's own directory authorities. It is private: every role and client refuses a network file that is not marked private, and the public VPN launch gate (chain/x/vpnlaunch) is off in every build. Nothing in it has been run against a real Tor network yet.

RoleInstalled withUnit
Directory authorityorama global install --services dirauthorama-global-tor-dirauth.service and an archive timer
Relay--services relayorama-global-tor-relay.service and orama-global-tor-monitor.timer
Exit (opt-in)--services relay,exitthe relay's unit with an exit policy; refused unless the network file allows exits
Validator onion service--services onionorama-global-tor-onion.service and orama-global-txgate.service

A host is an authority or a relay, never both. Each role runs under an account of its own and the global sandbox; none needs the chain except the onion role. The ports are 31020 (ORPort) and 31021 (authorities' DirPort).

One network file. tor-network.json is the only format and one parser reads it, for the install, orama maint vpn up, orama maint vpn check and every --onion-network submission. It carries the network's name, private, the authorities (at least three, on public IPv4 literals, with their identities), the voting schedule, bootstrap, allow_exit, and validator_onions. The file is public. The authorities' keys are made once, on an air-gapped machine, by orama maint global tor ceremony; the authority identity key stays offline. After a validator's onion service starts, its address is added with orama maint global tor onions add --network-file tor-network.json <addr.onion>.

Relay health. orama-global-tor-monitor.timer runs orama maint global tor monitor every five minutes as the relay's own account and writes monitor.json with in_consensus. orama status node shows whether the relay is in the relay set, and the health check global.relay.consensus warns when it is not.

The client. orama maint vpn up --network tor-network.json starts a Tor client on the network and offers a loopback SOCKS5 proxy (default 127.0.0.1:9150). It is a proxy, not a system-wide tunnel: only applications pointed at it use the network. When Tor stops, the port closes and nothing is routed around the network. orama maint vpn check joins the network and reads the all-zero account through each validator's onion service; it passes when at least one answers and fails when Tor cannot bootstrap, none answers or there is nothing to try. See VPN.

Relay pay. The bandwidth reporter on an authority host reports each closed emission epoch to x/relay, which pays registered relays. See Relay rewards. The reporter drops an epoch whose report window has passed or that is already settled instead of retrying it.

The full reference, including the ceremony, exits and the abuse-complaint procedure, is the Tor network operator page.

What is not built

  • +A run on a real network. The Orama Tor network's code and install exist; no tor process was started while writing it, and the first bring-up is the first run.
  • +Independent authorities. Orama runs all of them, so while it holds a majority it could sign a consensus that lists only its own relays. The public launch needs a majority of independent authorities, 100 relays from 40 operators and 15 exits in 5 countries, and the gate is off.
  • +Bandwidth measurement. sbws is not built, so authorities weight relays by what they claim.
  • +Publication of the vote archive, a signed fallback list, and IPv6.
  • +Registering a relay on chain with a command: MsgRegisterRelay is a separate transaction and no orama command sends it. See Relay rewards.
  • +A CLI command for the proxy routes, and an SDK wrapper for the tunnel.

Operating it

  • +Check: sudo orama node status, orama status service, orama maint inspect --subsystem tor.
  • +Logs: sudo orama node logs orama-namespace-tor@index -f.
  • +If /v1/proxy/anon answers 503, Tor is down or not installed on that gateway's node. Restart with sudo orama node restart.