When people write privacy guides, for the most part they are written from the perspective of the client. Whether you are using HTTPS, blocking tracking cookies or going so far as to browse the internet over Tor, those privacy guides focus on helping end users protect themselves from the potentially malicious and spying web. Since many people who read Linux Journal sit on the other side of that equation—they run the servers that host those privacy-defeating services—system administrators also should step up and do their part to help user privacy. Although part of that just means making sure your services support TLS, in this article, I describe how to go one step further and make it possible for your users to use your services completely anonymously via Tor hidden services.
I'm not going to dive into the details of how Tor itself works so you can use the web anonymously—for those details, check out https://tor.eff.org. Tor hidden services work within the Tor network and allow you to register an internal, Tor-only service that gets its own .onion hostname. When visitors connect to the Tor network, Tor resolves those .onion addresses and directs you to the anonymous service sitting behind that name. Unlike with other services though, hidden services provide two-way anonymity. The server doesn't know the IP of the client, like with any service you access over Tor, but the client also doesn't know the IP of the server. This provides the ultimate in privacy since it's being protected on both sides.
As with setting up a Tor node itself, some planning is involved if you want to set up a Tor hidden service so you don't defeat Tor's anonymity via some operational mistake. There are a lot of rules both from an operational and security standpoint, so I recommend you read this excellent guide to find the latest best practices all in one place.
Without diving into all of those steps, I do want to list a few general-purpose guidelines here. First, you'll want to make sure that whatever service you are hosting is listening only on localhost (127.0.0.1) and isn't viewable via the regular internet. Otherwise, someone may be able to correlate your hidden service with the public one. Next, go through whatever service you are running and try to scrub specific identifying information from it. That means if you are hosting a web service, modify your web server so it doesn't report its software type or version, and if you are running a dynamic site, make sure whatever web applications you use don't report their versions either.
Some services need to talk to the internet to resolve DNS names or download other resources. It's important that you configure your service so that all of those external requests route over Tor. You can do this with iptables rules that force all of your traffic through a local Tor proxy like you would for a client, or if your service has SOCKS proxy support, you can configure it to use the built-in Tor SOCKS proxy.
Finally, although you can run a hidden service and a relay node from the same host, it's considered a best practice to keep them separated so you can't correlate a hidden service with a particular relay node. Plus, this means you can just run a hidden service without worrying about any risks involved in running a relay node.
The first step in configuring a hidden service is to install Tor. Tor should be packaged for most major distributions, so you can just use your package manager to pull down the latest version. If you like to do things the hard way, or want to make absolutely sure to get the latest version, you also could sidestep your package manager and build Tor from sources on https://torproject.org.
You will configure your hidden services the same way whether you use a Red Hat or Debian-based distribution via the /etc/tor/torrc configuration file. As you'll see, the configuration is nice and simple.
For starters, let's assume you want to host a web service. Make sure that you configure your web server so that it's only listening on localhost (127.0.0.1), so as not to leak data that may make it easier to correlate your hidden service with a public service. Next, add the following two lines to your /etc/tor/torrc:
HiddenServiceDir /var/lib/tor/hidden_service/http
HiddenServicePort 80 127.0.0.1:80
Now restart the Tor service (sudo systemctl restart tor
), and your
service will be ready. That wasn't so bad, right? The HiddenServiceDir
option
will tell you where Tor should store information about this service
(including its .onion address). The HiddenServicePort
option tells Tor
on which port it should listen for the hidden service (80 in this case)
and to which address to forward that traffic (127.0.0.1:80 for this example).
Once the service has started, you will notice two different files under /var/lib/tor/hidden_service/http: a "private_key" and a "hostname" file. The private_key file is used to authenticate this particular hidden service. It's important that you protect this file, because anyone who has a copy of it can impersonate your service. The hostname file contains the name for your hidden service:
$ sudo cat /var/lib/tor/hidden_service/http/hostname
o9asojd8aymqqtoa.onion
This .onion hostname is what visitors to your service would enter into their Tor browser to visit you. Note that you're hosting HTTP and not HTTPS here. HTTPS requires you to get a valid certificate for f27sojd8aymqqtwa.onion, which wouldn't be possible. In any case, Tor takes care of authenticating and encrypting your communication to the site, and you can think of that private_key file as acting kind of like a private TLS key.
You can host multiple hidden services from one server, and Tor allows
you to set it up in multiple ways. If you want the same hostname to host
multiple services, simply add extra HiddenServicePort
directives under
the same HiddenServiceDir
. So for instance, if I wanted to add SSH to my
existing HTTP service, I'd do this:
HiddenServiceDir /var/lib/tor/hidden_service/http
HiddenServicePort 80 127.0.0.1:80
HiddenServicePort 22 127.0.0.1:22
In reality though, you probably will want to segregate different services into their own .onion addresses—that way you have the option of splitting them up in the future by copying their particular directory under /var/lib/tor/hidden_service to a new server along with their configuration settings. To do that, give each service its own HiddenServiceDir option:
HiddenServiceDir /var/lib/tor/hidden_service/http
HiddenServicePort 80 127.0.0.1:80
HiddenServiceDir /var/lib/tor/hidden_service/ssh
HiddenServicePort 22 127.0.0.1:22
Now you can look at /var/lib/tor/hidden_service/ssh/hostname to find the new .onion address for your SSH service.
As you can see, configuring Tor hidden services isn't nearly as difficult as you might have originally assumed. Arguably, it will take longer for you to reconfigure your services to listen on localhost than it will to configure Tor itself!