Running a Tor relay on OpenBSD

As of December 2014, there were only a few successful Tor relays running on OpenBSD. According to TorStatus, the two highest-throughput OpenBSD relays were moving 2.19 MB/s and 848 KB/s. While there could have been some in hibernation, it’s nonetheless saddening how little Tor traffic is carried by OpenBSD nodes.

OpenBSD, while starker and somewhat slower than other Unices, is fantastically well suited for firewalls, relays, VPNs, and the like. This is why the larger Unix community knows it approximately as “that ultra-secure firewall OS”. While there are certainly other uses for OpenBSD, I’ve found it better suited for Tor relays than any other operating system. It’s bare, elegant simplicity and bulletproof default security feel like they were designed for the job.

I will focus only on what is unique to this aim. OpenBSD support is build around the philosophy of helping yourself – community members will generally be unwilling to offer advice that is already recorded in the project’s thorough and well-written FAQ and man pages, or elsewhere. For basic installation, configuration, and administration advice, look there. By the same token, I’ll deflect specifics to existing guides when possible.

As a separate note of advice, if you’re interested in learning more about how to use OpenBSD, get a copy of Absolute OpenBSD. It’s an awesome book and a great introduction to OpenBSD system administration.

This guide is intended for readers with a fair amount of experience in Unix system administration and Tor relay administration. For example, if I say “reload your torrc” or “change this user’s login group”, you should be able to do that or at least understand what I mean. If that doesn’t sound like you, you should probably start with the Tor Project’s Linux relay tutorial. I’ll elaborate some of the more abstruse aspects of OpenBSD, so those still learning OpenBSD (like me) should be able to comprehend.

If you notice any mistakes, please let me know!

Basic Security

Hopefully, you set up a non-root account with sudo access during installation. If not, do so now. adduser and visudo should get you there.

Be sure to apply all patches before moving on.

Configure public key SSH authentication. Once you’re sure it’s working, disable password authentication:

Use the AllowUsers option in /etc/ssh/sshd_config to restrict access to your non-root username. If you have a subnet or subnets that you always log in from, you can restrict access with a config entry like AllowUsers jimmie@1.2.3.0/24 jimmie@7.8.9.0/24

Be sure to reload sshd with “rcctl reload ssh” when testing config file changes, as they won’t apply otherwise. When doing so, test them in a new SSH session. SSH preserves active sessions when restarting. If you break something on a VM or far-away dedicated server and can’t log back in, you’ll have to ask the on-site admins for support or, if that fails, reinstall.

I used to suggest SSH filters such as SSHGuard and fail2ban. However, they may interfere with Tor traffic. After all, you’re inherently going to get some SSH intrustion attempts from Tor exit nodes. You shouldn’t need an SSH filter if you require public key authentication.

Tor should be the only service running on your relay, and you should be the only person with access to it! You have a responsibility to your users to keep it secure.

Getting Tor

By far the simplest way to install Tor is to install the package (pkg_add tor). Packages are “frozen” along with the OpenBSD base system for each release. This means that the Tor package is only as recent as the OpenBSD release they’re running on, excepting security patches. Because OpenBSD produces a new stable release every six months, the OpenBSD Tor package is often older than the current stable Tor release.

Be sure to periodically update your packages (pkg_add -u) as security patches are backported.

When choosing a package mirror, ensure that you can access it though the Tor browser. A surprising number of mirrors block Tor, and if you’re running an exit relay, that means you. They may even block you as a non-exit relay if they’ve misconfigured their blacklist, so choose a Tor-friendly mirror to be safe.

Alternatively, if you insist on running the newest Tor release, you can build from source like me. To do this, you need to know enough about the OpenBSD ports system to use the Makefile and patches to recreate the build manually. This takes about five minutes for the experienced but is nearly impossible for the uninitiated. Email me if you need help.

Tor Configuration

Your Tor configuration file is in /etc/tor/torrc. Configuring Tor is outside the scope of this guide; see guides for Linux relays if you need help.

Setting HardwareAcceleration 1 is a good idea. AES-NI can greatly reduce the CPU load of crypto-heavy daemons like Tor.

Resource Usage Limits

OpenBSD sets per-user and per-process resource usage limits far stricter than those of other operating systems. This is a great security and stability feature. While a fork bomb, a memory allocation bug, or an unprivileged yet malicious user can take down an unhardened Linux server, OpenBSD will shut them down.

Tor needs a new file descriptor for every connection it makes with Tor relays and (if it allows exit traffic) web servers. This quickly exceeds the hard limit of 1024 file descriptors set in login.conf. The Tor Project suggests allowing for 8192 file descriptors, and exit traffic can consume even more.

We can override these types of limits when necessary. They exist in two places:

The login configuration sets limits based on a user’s login class. By default, the Tor daemon will belong to the generic daemon login class. To raise the open file descriptor limits, we create the tor login class in /etc/login.conf:

tor:\
    :openfiles-cur=13500:\
    :openfiles-max=13500:\
    :tc=daemon:

The last line causes our new login class to inherit the unspecified fields from the daemon login class.

Then, run:

usermod -L tor _tor

to change the _tor user’s login class to tor.

However, the kernel still has a hard global limit on the number of file descriptors that can be open. You can see it by calling sysctl kern.maxfiles. To increase this limit, run sysctl kern.maxfiles=15000. This sysctl will reset when the machine reboots unless you add the line kern.maxfiles=15000 to /etc/sysctl.conf, so do that as well.

Packet Filtering

You are now very close to having a fully functional and very secure Tor relay. The last step will be to configure PF, OpenBSD’s packet filter (also known as a firewall). Many users consider PF the best thing about OpenBSD – it’s powerful and extremely easy to use.

PF is a stateful packet filter. That is, its filtering rules involve transport layer (e.g. TCP) connections, not IP packets. Be sure to understand what that means, or the below rules may confuse you.

Logically, a Tor relay should only get incoming connections from three sources:

Optionally, you may also get incoming HTTP requests for your homepage, which notifies the curious that your server is a Tor exit node. This is enabled by the DirPortFrontPage option in torrc. It’s a good idea, and I highly suggest configuring it to serve the Tor Project’s default notification page.

SSH uses port 22, and HTTP uses port 80. The ports on which Tor requests arrive correspond to the ORPort and DirPort settings in your Tor config file. Mine are 443 and 80, respectively.

In terms of outgoing connections, all bets are off. If you’re an exit, your users can connect to any port other than those that you explicitly reject in your torrc. Additionally, other Tor relays have a very wide array of ORPorts, and you’ll have to connect to all of them. So, we don’t bother restricting outgoing connections.

Below is my PF config file, stored in /etc/pf.conf:

# See pf.conf(5) for syntax and examples.

# increase default state limit from 10,000 states
set limit states 100000

# respond with a TCP packet with the RST flag instead of ignoring
set block-policy return

set skip on lo

# http://openbsd.gr/faq/pf/scrub.html
# you can also optionally include random-id for misbehaving clients
match in all scrub (no-df)

block in all

pass out quick on egress inet keep state

pass in on egress inet proto tcp from any to any port { 22 80 443 }

Note that I also increase the limit on the number of states, a change similar to raising the resource usage limits. 100,000 allowed states might be overkill, but it essentially just means allowing an unlimited number.

These changes will not take effect until you reload your PF ruleset with:

pfctl -f /etc/pf.conf

Anecdotally, pftop is a great tool for monitoring connections, traffic, and which PF rules connections are matching. It’s available as a package.

Logs

In true Unix form, I use syslog for Tor’s logging. This is not necessary, but I find it more convenient.

To do so, begin by adding the following to your torrc and reloading the daemon:

Log notice syslog

Then, create the necessary log file with “touch /var/log/tor”.

Finally, add the following three lines to the top of /etc/syslog.conf:

!!Tor
*.*     /var/log/tor
!*

This causes Tor log messages to be saved in /var/log/tor only. Be sure that the whitespace in the second line is a tab – it will not work otherwise.

You can check the sanity of your log with “rcctl check syslogd”. If your changes are correct, make them effective by reloading syslogd with “rcctl reload syslogd”.

Finally, add Tor’s log to the log rotator config, /etc/newsyslog.conf:

/var/log/tor                640  7     50   *

Starting Tor

Congratulations, You’ve configured a Tor relay! You can start it with “rcctl start tor

Be sure to monitor the logs!