[$ xmrhost] _

$ xmrhost-cli docs show --topic=run-non-exit-tor-relay

[$ ] doc: run-non-exit-tor-relay

// Run a non-exit Tor relay on a XMRHost VPS — torrc, bandwidth tuning, MyFamily, abuse handling

// published=2026-04-29 · updated=2026-04-29 · diff=advanced · read=22min · tags=[tor, relay, guard, middle, bandwidth]


// ABSTRACT

abstract

Procedure for bringing up a public, non-exit, non-bridge Tor relay on an offshore XMRHost VPS. Covers the upstream-procurement conversation (transit allowance, abuse-handling expectations), the torrc shape for a middle/guard relay, RelayBandwidthRate tuning that stays inside the VPS bandwidth quota, the MyFamily declaration when an operator runs more than one relay, the four-week consensus-weight ramp-up curve, and the post-launch checks that catch the most common misconfigurations (clock skew, ORPort unreachable, descriptor never published).

Scope and assumptions

This is the operational walk-through for running a non-exit Tor relay (middle or guard role, NOT exit, NOT bridge) on a XMRHost VPS. The non-exit role is the operationally cheapest contribution to the Tor network: the relay handles inter-hop traffic only, never originates or terminates traffic toward the public internet, and therefore never appears as the source IP of any user-visible action. Abuse complaints to the upstream are therefore rare to nonexistent, in contrast to exit relays. [Tor Project — Tor relay operator guide, role taxonomy]

Baseline assumptions:

  • Debian 12 (bookworm) on a XMRHost VPS in Iceland, Romania, or Switzerland — these jurisdictions have known operator-friendly precedent for running relays. [Iceland Höfundalög §11; Romania Law 8/1996 — operator-side liability scope]
  • The brand’s hardened-by-default baseline is in place. See harden-sshd and kernel-hardening-checklist.
  • The VPS plan includes ≥ 5 TB/month of egress (10 TB/month preferred). A 2 TB plan is wasted on a Tor relay — it’ll hit the cap in week one and either throttle or get billed for overage.
  • The upstream provider has been told the box will run a non-exit Tor relay. If they say no, do not run one anyway. The procurement conversation is in step 1.

This doc does NOT cover bridge relays (a different config, a different threat model — bridges are kept off the public consensus to be useful to censored users) or exit relays (a different config, a much bigger legal-and-abuse-handling surface — see the elective doc exit-relay-considerations if you’re seriously considering operating one).

Step 1 — the procurement conversation with upstream

Before installing Tor, confirm with the VPS provider in writing that running a relay is acceptable. The acceptable-use policy of every offshore-friendly host known to the brand permits non-exit relays explicitly, but the wording differs and you want a paper trail. The five questions to ask, in plain language:

  1. “Is running a non-exit, non-bridge Tor relay (middle or guard role) acceptable on this VPS?”
  2. “What is the egress bandwidth cap, and at what cap does throttling or overage billing kick in?”
  3. “Does the AUP allow inbound connections on a non-standard port (e.g. 9001 or 443/9050) to the relay’s ORPort?”
  4. “If an abuse complaint arrives at upstream’s NOC referencing the relay’s IP, what is upstream’s intake process — is it forwarded to the customer, or handled by upstream first?”
  5. “Is reverse DNS configurable to a string of the customer’s choice (so the relay can be operationally identified as tor-relay.example.invalid rather than vps-12345.upstream.invalid)?”

XMRHost’s listed offshore providers all answer “yes / generous quota / yes / forwarded to customer / yes” to those five. If the provider you’re using answers differently, reconsider before launch.

Once confirmed, set the reverse DNS via the provider’s panel to a name that resolves the relay back to the operator (the brand convention: tor-relay-<region>-<n>.<your-domain>).

Step 2 — install Tor from the upstream repo

Same upstream-repo install as [provision-tor-hidden-service] step 1, repeated here so this doc is self-contained:

apt update
apt install -y apt-transport-https gnupg ca-certificates wget

wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc \
  | gpg --dearmor > /usr/share/keyrings/tor.gpg

cat > /etc/apt/sources.list.d/tor.list <<'EOF'
deb     [signed-by=/usr/share/keyrings/tor.gpg] https://deb.torproject.org/torproject.org bookworm main
deb-src [signed-by=/usr/share/keyrings/tor.gpg] https://deb.torproject.org/torproject.org bookworm main
EOF

apt update
apt install -y tor deb.torproject.org-keyring tor-geoipdb

Confirm:

tor --version
Tor version 0.4.8.13.

If the version starts with 0.4.7 or earlier, the upstream repo line was misconfigured.

Step 3 — the canonical relay torrc

The relay torrc is materially different from a hidden-service torrc — different sections, mostly different directives. This is the brand’s middle-relay shape; turn one knob (ExitRelay 1) and it becomes an exit relay, do NOT do that without reading the exit-relay considerations doc first.

# /etc/tor/torrc — middle/guard relay (non-exit, non-bridge).
# Replace <YOUR-CONTACT-EMAIL>, <YOUR-NICKNAME>, <YOUR-FAMILY-FP> below.

# ---------- identity / contact ---------------------------------------------
# Nickname: 1-19 alphanumeric chars, displayed in consensus + visualisations.
# Brand convention: `<region><n>cypher` e.g. `is01cypher`, `ro02cypher`.
Nickname                  is01cypher

# Contact email surfaces in the relay descriptor and is therefore PUBLIC. Use
# an address that's monitored for abuse complaints and discoverability —
# do NOT use a personal address. The brand convention is the role-account
# `tor-relay@<your-domain>`.
ContactInfo               <YOUR-CONTACT-EMAIL>

# ---------- relay config ----------------------------------------------------
# ORPort is the relay listener; the inbound connections from other relays
# come here. 9001 is the historical default; 443 confuses some censorship
# blocks (some networks allow 443 outbound but block 9001) but only matters
# for guard relays.
ORPort                    9001
# Optional second ORPort on 443 — useful for guard relays in restrictive
# networks. Only enable if your IPv4 has port 443 free (i.e. no clearnet
# webserver on this box).
# ORPort                  443

# DirPort optional — old clients fetch consensus over DirPort. Modern Tor
# uses tunnelled-over-OR fetches; DirPort is no longer needed for new
# relays per Tor Project guidance, late 2023+.
# DirPort                 9030

# ---------- non-exit, non-bridge -------------------------------------------
ExitRelay                 0
ExitPolicy                reject *:*
BridgeRelay               0
PublishServerDescriptor   1

# ---------- bandwidth tuning ------------------------------------------------
# Tor's bandwidth-rate is byte-per-second NOT bit-per-second. The brand
# default for a 10 TB/month VPS: cap at 12 MB/s sustained, 25 MB/s burst —
# 10 TB / 30 days / 86400 sec ≈ 3.86 MB/s; the 12 MB/s ceiling exists for
# the inbound peaks during consensus ramp-up. RelayBandwidthBurst MUST be
# >= RelayBandwidthRate.
RelayBandwidthRate        12 MB
RelayBandwidthBurst       25 MB

# Daily/monthly accounting. Use this to STOP the relay if it exceeds the
# upstream cap rather than letting upstream throttle / bill you. Format:
# AccountingMax <bytes>; reset on the 1st of each month at midnight UTC.
AccountingMax             9 TB
AccountingStart           month 1 00:00

# ---------- family ----------------------------------------------------------
# If you operate more than one relay (now or in the future), declare them as
# a family so Tor clients don't pick two of yours in the same circuit. The
# value is a comma-separated list of fingerprints (NOT nicknames). Fill this
# in AFTER first start, when the fingerprint of THIS relay is known —
# everything in the family points at everything else, mutually.
# MyFamily               <FP1>,<FP2>,<FP3>

# ---------- protocol -------------------------------------------------------
# Disable the SOCKS port — this box is NOT for the operator's local Tor
# usage. A relay listening for local SOCKS is a footgun.
SocksPort                 0
ClientUseIPv4             0
ClientUseIPv6             0

# ---------- logging --------------------------------------------------------
# notice-level only; the relay is not interesting to debug at INFO+ except
# during the first 24h of bringup, where temporary INFO is justified.
Log                       notice file /var/log/tor/notice.log
DataDirectory             /var/lib/tor

# ---------- safety nets ----------------------------------------------------
DisableDebuggerAttachment 1
HardwareAccel             1
# Cap memory in case a peer floods cells. Tor's cell pool is the dominant
# memory user on a busy relay; 2 GB is a safe ceiling on a 4 GB VPS.
MaxMemInQueues            2048 MB

The RelayBandwidthRate calculation is worth understanding. AccountingMax is the hard ceiling Tor enforces — if the relay hits that monthly cap before the calendar month is over, Tor pauses itself until the reset, which is graceful but produces a 1-day-or-more outage for clients on the relay. Set it 10% below your actual upstream cap so a brief overshoot doesn’t trigger upstream throttling. The 9 TB / 10 TB choice in the example is that 10% safety margin.

RelayBandwidthRate is the sustained-rate limit Tor uses for shaping; the burst rate kicks in for short intervals. Tor’s own bandwidth-self-test publishes a measured-bandwidth value into the consensus that’s used by the bandwidth-authority weighted load balancer; clients then route proportional to consensus weight. [Tor Project — bandwidth scanner v2 spec]

Make sure /var/log/tor/ exists and is owned by debian-tor:

mkdir -p /var/log/tor
chown debian-tor:debian-tor /var/log/tor
chmod 0750 /var/log/tor

Open the firewall for ORPort:

nft add rule inet filter input tcp dport 9001 accept

Restart Tor and tail the journal:

systemctl restart tor
journalctl -u tor@default -f --since '60 seconds ago'

Watch for the four milestone log lines:

  • Configuration was valid — torrc parses
  • Bootstrapped 100% (done) — relay has fetched consensus
  • Self-testing indicates your ORPort <ip>:9001 is reachable from the outside. Excellent. — other relays can reach you on the ORPort
  • Performing bandwidth self-test...done. — Tor has completed its initial bandwidth probe

All four should appear in the first 5-10 minutes after restart. If “ORPort is reachable” doesn’t appear, the firewall or the upstream’s port-blocking is the culprit — check from a third box with nc -z <vps-ip> 9001.

Step 4 — read the relay fingerprint

The relay’s identity fingerprint is the public-key-hash that uniquely identifies it on the Tor network. Read it after the first start:

cat /var/lib/tor/fingerprint
is01cypher 1A2B3C4D5E6F7890ABCDEF1234567890ABCDEF12

The 40-hex-character fingerprint is the value that goes into MyFamily on every other relay you operate, AND is what Tor Metrics and Relay Search show. [Tor Metrics — Relay Search]

If you operate more than one relay, edit /etc/tor/torrc on EACH box, set MyFamily to the comma-separated list of every relay’s fingerprint, and restart each one. Failing to set MyFamily means clients can pick two of your relays in the same circuit, which defeats the load-balancing-by-operator-diversity logic the network depends on.

# Example MyFamily on relay 1 (fingerprint $FP1):
MyFamily 1A2B3C4D5E6F7890...,FEDCBA0987654321...,789ABCDEF0123456...

Step 5 — the four-week ramp-up

A new relay does NOT immediately receive its expected traffic share. The bandwidth-authority’s measurement system has a multi-week ramp:

Period after launchTraffic shareReason
Week 1< 5% of expectedConsensus weight defaults to 0; only a handful of bandwidth scanners route through you.
Week 25-30%First weighted measurements published; clients begin selecting you.
Week 330-70%Bandwidth-authority confidence interval narrows.
Week 4+70-100%Steady state — your relay is now load-balanced at its measured weight.
Month 6++ Stable / Guard flagsOnce the relay has been online consistently for ~14 days uptime in the last 30, the directory authorities issue the Stable flag; the Guard flag follows ~2 months in.

Don’t panic if week one looks slow. The relay is correctly configured if the consensus shows it; the traffic will arrive. [Tor Project — relay lifecycle FAQ]

To see your relay’s status during ramp-up, check Relay Search:

https://metrics.torproject.org/rs.html#search/1A2B3C4D5E6F7890ABCDEF1234567890ABCDEF12

The page shows the consensus weight, the flags currently assigned (Fast, Stable, Running, Valid, V2Dir, eventually Guard), the measured bandwidth, and the historical uptime graph.

Step 6 — abuse handling for the rare non-exit complaint

Non-exit relays receive abuse complaints rarely (the relay is never the source IP of user-visible traffic) but not zero. The two complaint classes worth being prepared for:

  1. “Your IP appeared in our IDS as Tor traffic.” This is true and is the entire point of the relay. Reply with the standard non-exit-relay template — the brand maintains one at /legal/tor-non-exit-template.txt adapted from the Tor Project’s template-bundle. [Tor Project — Tips for running an exit/relay node]

  2. “Connections from your IP are being used to attack our service (e.g. brute-force SSH, web-app scraping).” This is materially the same complaint as the previous one — the brute force is being CONDUCTED via Tor by a user, the user’s exit is some OTHER relay, your relay is one of two intermediate hops in the circuit. Reply with the same template and add a note that your relay is non-exit and therefore did not originate the traffic.

The brand template, abbreviated:

Subject: Re: Abuse report regarding <ip> — non-exit Tor relay

Thank you for the report.

The IP address <ip> hosts a Tor middle-relay (non-exit), nickname <nickname>,
fingerprint <fp>. A middle-relay forwards encrypted traffic between other Tor
relays; it does not originate, terminate, or have visibility into traffic
content. The relay is operated under [Iceland Höfundalög / Romania Law 8/1996 /
Swiss Telecommunications Act §3a] which establishes the operator's neutral-
intermediary status for traffic forwarded in this role.

The activity you observed is being conducted via a Tor circuit; the source
of that traffic is an exit relay (a different operator, a different IP
address) selected by the Tor user. Please direct your complaint to the exit
operator if identifiable, or to the abuse-handling teams of the Tor Project
if it is not.

Operator contact: <CONTACT-EMAIL>
Tor Project resources: https://support.torproject.org/abuse/

If the upstream provider receives the complaint and forwards it to you, reply within 48 hours. Silence is the worst outcome — upstream interprets it as “customer is unresponsive” and may take the box offline preemptively.

Step 7 — four post-launch checks

Check 1 — clock skew

Tor circuits depend on synchronised time. A relay with > 30 seconds of clock skew is rejected from the consensus.

chronyc tracking

Confirm Stratum is ≤ 3 and System time deviation is sub-second. If chronyd is not running, install and enable:

apt install -y chrony
systemctl enable --now chrony

Check 2 — ORPort reachable

journalctl -u tor@default -n 200 --no-pager | grep -E 'ORPort.*reachab'

Expected: one line saying Self-testing indicates your ORPort ... is reachable from the outside. Excellent. If you see not reachable, fix the firewall.

Check 3 — descriptor publication

journalctl -u tor@default -n 500 --no-pager | grep -i 'descriptor' | head

Expected: at least one Tor opening new descriptor and one Successfully uploaded server descriptor per descriptor regeneration interval (every ~18 hours by default).

Check 4 — bandwidth accounting

grep -i 'accounting' /var/log/tor/notice.log | tail

Expected: regular Tor: Accounting period in N days, M hours; bytes read/written so far: X / Y lines. If you see Hibernating! ...wakeup time it means you’ve hit the AccountingMax — relay is correctly self-pausing, but you’ve under-set the cap relative to the upstream allowance.

Closing — what to do next

The relay is operational. Order of next steps:

  1. Subscribe operator email to the tor-relays mailing list — the canonical place where consensus-affecting changes, security advisories, and bandwidth-scanner deployments are announced.
  2. After ~14 days uptime, check the Tor Metrics search page and confirm the Stable flag has been issued.
  3. If you intend to operate more relays, set MyFamily on every relay PROACTIVELY; back-filling family declarations on already-running relays is operationally fine but slightly delays the network from realising the diversity.
  4. Read bgp-resilience-for-tor-relay-operators for the network-resilience pass — single-AS / single-DC relays are a known weakness of the Tor topology that the network is actively trying to spread out.

Don’t run the relay AND a hidden service on the same box. Co-tenancy of those two roles is a documented deanonymisation surface (the relay’s bandwidth-self-test creates a side-channel against the hidden-service circuit). Run the relay on its own VPS, full stop.

// END OF DOC

$ cd /docs # back to the manual