{"id":6162,"date":"2026-09-05T00:41:51","date_gmt":"2026-09-04T15:41:51","guid":{"rendered":"https:\/\/eternalsphere.net\/echoes\/?p=6162"},"modified":"2026-09-12T14:03:07","modified_gmt":"2026-09-12T05:03:07","slug":"s2zd7txcqw1153t","status":"publish","type":"post","link":"https:\/\/blog.eternalsphere.net\/index.php\/2026\/09\/05\/s2zd7txcqw1153t\/","title":{"rendered":"Building a Safe Non-Exit Tor Relay on a Small Server"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Running a Tor relay does not require a dedicated datacenter server. A modest Linux machine behind a correctly configured router can operate as a useful public non-exit relay.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The key is to keep the design simple, explicitly disable exit functionality, limit resource consumption, and expose only the relay port that is actually required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The following architecture is representative:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Internet\n   \u2193\nEdge Router\n   \u2193\nTCP port forward\n   \u2193\nLinux Server\n   \u2193\nTor Non-Exit Relay<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">All names, addresses, usernames, domains, and ports below are intentionally generic.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Use a dedicated non-exit configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A minimal relay configuration might resemble:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Nickname relay-node\nContactInfo relay-contact@example.net\n\nORPort &lt;RELAY_PORT&gt; IPv4Only\n\nSocksPort 0\nExitRelay 0\n\nRelayBandwidthRate &lt;RATE_MBITS&gt; MBits\nRelayBandwidthBurst &lt;RATE_MBITS&gt; MBits\n\nMaxMemInQueues 1 GBytes<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The most important lines are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SocksPort 0\nExitRelay 0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>SocksPort 0<\/code> prevents the relay daemon from acting as a local Tor proxy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>ExitRelay 0<\/code> prevents it from operating as an Exit Relay.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This creates a relay whose primary function is carrying encrypted Tor traffic between other Tor relays.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Understand the bandwidth unit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tor configuration supports explicit bit-based units.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>RelayBandwidthRate 30 MBits<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">means approximately:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>30 megabits per second\n\u2248 3.75 megabytes per second<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It does not mean 30 MB\/s.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The distinction matters because:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>30 MB\/s\n=\n240 Mbit\/s<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Accidentally confusing the two could configure a relay for eight times the intended throughput.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Set a sustainable rate<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The best relay bandwidth is not necessarily the fastest possible value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A sustainable value should leave enough capacity for ordinary household or server traffic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A sensible approach is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>start conservatively\n       \u2193\nobserve CPU \/ RAM \/ router load\n       \u2193\nobserve real network usage\n       \u2193\nincrease gradually<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Long-term uptime is usually more valuable than short periods of excessive throughput followed by instability.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Limit queue memory explicitly on shared servers<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tor can automatically calculate <code>MaxMemInQueues<\/code> from system RAM.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On machines with large amounts of memory, the resulting automatic value may be several gigabytes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That can be acceptable for a dedicated high-capacity relay, but a shared server may also host databases, web applications, file storage, or containers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Explicitly configuring:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MaxMemInQueues 1 GBytes<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can therefore provide a useful safety boundary for a moderate-bandwidth relay.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This setting should not be misunderstood as a hard 1 GiB process memory limit. It controls Tor\u2019s internal memory accounting for several network queues and buffering structures.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Actual process RSS may remain much lower.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Router configuration should be narrow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The edge router only needs to forward the chosen Tor ORPort.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Conceptually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WAN TCP\/&lt;RELAY_PORT&gt;\n        \u2193\nLAN &lt;RELAY_HOST&gt;:&lt;RELAY_PORT&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do not forward unrelated Tor ports such as SOCKS or TCP control interfaces.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The router rule should be restricted to TCP unless a future Tor configuration explicitly requires something else.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A representative nftables result might resemble:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tcp dport &lt;RELAY_PORT&gt;\ndnat ip to &lt;LAN_ADDRESS&gt;:&lt;RELAY_PORT&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The exact numbers should vary from deployment to deployment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Keep the Tor Control interface local<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tor monitoring tools need access to its control protocol.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A Unix socket is often preferable to a public TCP ControlPort:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/run\/tor\/control<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This keeps administrative communication local to the server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The socket should have restrictive ownership and permissions so ordinary users cannot control the Tor daemon.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run Tor under a dedicated service account<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Linux distribution packages normally run Tor under a dedicated unprivileged system account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The design should look like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemd\n   \u2193\nTor daemon\n   \u2193\ndedicated service identity<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">rather than:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root\n   \u2193\nTor permanently running as root<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The service identity owns the Tor state directory and identity keys while remaining isolated from unrelated application data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preserve relay identity<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A Tor relay\u2019s long-term identity is derived from cryptographic keys stored in its Tor data directory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Backups should therefore preserve the relay state if maintaining the same identity after system recovery is important.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For virtual machines, full-system backups generally already include these files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Only one live instance should use a given relay identity at a time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Validate before applying changes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before restarting or reloading Tor:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tor --verify-config \\\n  --defaults-torrc \/path\/to\/service-defaults \\\n  -f \/etc\/tor\/torrc<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A successful validation should end with a message equivalent to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Configuration was valid<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For ordinary configuration changes that support runtime reload, a reload is preferable to a complete daemon restart.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A restart is still perfectly acceptable for package upgrades or changes that require full process initialization.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Final objective<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A good small Tor relay is intentionally boring:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>one public ORPort\n+\nno Exit traffic\n+\nno public SOCKS proxy\n+\nno public ControlPort\n+\nlimited resource use\n+\nstable identity\n+\nlong uptime<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That simplicity reduces operational risk and makes long-term maintenance significantly easier.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Running a Tor relay does not require a dedicated datacenter server. A modest Linux machine behind a correctly configured router can operate as a useful public non-exit relay. The key is to keep the design simple, explicitly disable exit functionality, limit resource consumption, and expose only the relay port that &hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[120],"tags":[245],"class_list":["post-6162","post","type-post","status-publish","format-standard","hentry","category-1s3b6h7r2zay02x","tag-tor"],"_links":{"self":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts\/6162","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/comments?post=6162"}],"version-history":[{"count":1,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts\/6162\/revisions"}],"predecessor-version":[{"id":6163,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/posts\/6162\/revisions\/6163"}],"wp:attachment":[{"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/media?parent=6162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/categories?post=6162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.eternalsphere.net\/index.php\/wp-json\/wp\/v2\/tags?post=6162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}