puddle.town

Tuning Tor on Linux

I used to spend quite a bit of time as a volunteer Tor relay operator. At one point I ran one of the larger relay families. I've moved onto other things, mostly because the bandwidth costs were too expensive, but thought I'd share some of my notes on how I tuned Tor and Linux for performance and kept out certain types of malicious traffic.

Configuring /etc/tor/torrc

torrc is the main config file for a relay. I'm leaving out most of the file here and only showing the relevant portions. Don't forget to include the MyFamily line if you run more than one relay; this is what signals the network that all your relays are associated with one operator, which prevents a user from going through more than one family member for a given circuit. This is an important privacy measure. If you don't include MyFamily, the other operators will eventually find your nodes anyway and exclude them from the network.

SocksPort 0
DirPort 0
ORPort 443
ControlPort 999

RelayBandwidthRate 15 MBytes
RelayBandwidthBurst 20 MBytes

DisableDebuggerAttachment 0
DisableOOSCheck 0
HeartbeatPeriod 24 hours
MaxMemInQueues 512 MB

You typically don't need the SocksPort or DirPort for production relays. You'll want to adjust the bandwidth according to your capacity. The last four lines were helpful for performance tuning on large relays circa 2018; their relevance may have changed over time.

Tuning /etc/sysctl.conf

/etc/sysctl.conf is for tuning the performance of the Linux kernel. Below are the values I used for years on my relays. I won't get into the details of each line, but these values were suggested by other operators and tuned over time as I monitored performance.

fs.file-max=64000
kernel.sysrq=0
net.core.somaxconn=20480
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.default.send_redirects=1
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.icmp_ignore_bogus_error_responses=1
net.ipv4.ip_local_port_range=1025 65530
net.ipv4.tcp_fin_timeout=4
net.ipv4.tcp_keepalive_intvl=10
net.ipv4.tcp_keepalive_probes=3
net.ipv4.tcp_keepalive_time=60
net.ipv4.tcp_max_orphans=262144
net.ipv4.tcp_moderate_rcvbuf=1
net.ipv4.tcp_no_metrics_save=1
net.ipv4.tcp_timestamps=0
net.ipv4.tcp_tw_recycle=1
vm.min_free_kbytes=65536
vm.swappiness=10

Mitigating DDoS with UFW and connlimit

One of the larger problems I ran into over time was a never-ending stream of malicious traffic, often in an attempt to DDoS (Distributed Denial of Service) my nodes and make them less useful.

One of the more common attacks involved malicious actors using modified Tor clients to open as many connections as possible, in an attempt to exhaust resources and prevent real users from using the relay. Here's an example of how I found these bad actors using common Linux tools piped together:

sudo netstat -tupan | grep ESTABLISHED | grep /tor | awk '{print $5}' | awk -F: '{print $1}' | awk -F. '{print $1"."$2"."$3}' | sort | uniq -c | sort -b -n | tail -n 10

A bit of a spaghetti factory, sorry, but the above is essentially looking for open connections and then grouping them by subnet, and sorting the most egregious networks toward the top.

At the time, I found some malicious IPs with 100+ open connections across my relays. None of these IPs were in the Tor consensus, most looked like they were running on VPS (Virtual Private Servers), and legitimate Tor users shouldn't have that many open connections anyway.

Given this information, you can safely block the associated /24 subnet (254 hosts). An example of how you might block a subnet using UFW:

sudo ufw deny from 95.211.95.0/24


Finally, you can use Linux's built-in connlimit tools to further reduce attempts to exhaust connections.

Add the following to /etc/ufw/before.rules to rate limit both the DirPort and ORPort. Note: If you aren't using DirPort, you don't need to worry about the first line obviously.

# Limit to 20 connections on port 80 per /24:
`-A ufw-before-input -p tcp --dport 80 -m connlimit --connlimit-above 20 --connlimit-mask 24 -j REJECT --reject-with tcp-reset`

# Limit to 100 connections on port 443 per /24:
`-A ufw-before-input -p tcp --dport 443 -m connlimit --connlimit-above 100 --connlimit-mask 24 -j REJECT --reject-with tcp-reset`

Other Resources

The Tor Operators mailing list is a great resource if you need help. There's also a Relay Operators FAQ on the community website.

#linux #privacy #tor