The Censorship Resistant Internet - Part 1: How to Run a Tor Hidden Service

by p4bl0

0x0 - Introduction

This will be a series of four articles explaining how to run censorship resistant services on the Internet.

In this one, I will talk about Tor1 hidden services, you know, the infamous .onion.  The second one will be devoted to I2P2 services, the third one to IPFS3, and the last one to ZeroNet4.

Along the way I will share the setup I created for my personal website, which is available over Tor, I2P, IPFS, and ZeroNet in addition to the classical web.  My setup enables all these versions of my website to be easily kept in sync.

Tor and I2P allow you to use the Internet anonymously (at least given proper use of the tools and some care, of course), and to anonymously host services (basically, anything which runs on top of TCP).  Tor is more focused on the former feature while I2P is more focused on the latter (for example, it is not designed to anonymously browse the classical web).  IPFS is a giant (IP stands for "InterPlanetary") distributed filesystem enabling us to build the "permanent web," and ZeroNet is a decentralized network which uses BitTorrent to host websites in a peer-to-peer fashion.  More on these in their dedicated article.  Now let's get back to Tor hidden services.

To protect its users, Tor uses onion routing.  The principle of onion routing is that instead of connecting directly to a destination server, you instead create a circuit between you and that server, which goes through three randomly chosen nodes (i.e., computers running a Tor relay) on the Tor network:

Cryptography is used to ensure these properties, which in turn ensure that no single computer can link you and the destination server.

Another feature of the Tor network is hidden services.

When a computer runs a hidden service, it builds a few circuits such as the ones we just described.  Each of these circuits connects it to an introduction points.  Then the hidden service assembles its descriptor, which consists in its public key (of which the .onion name is derived) and its list of introduction points.  The descriptor is then signed with the private key of the hidden service, and uploaded (through a Tor circuit) to a distributed hash table.

When a client wants to connect with a hidden service, it first creates a circuit to a random node which is called the rendezvous point, and then queries the distributed hash table (through a Tor circuit, of course) for the descriptor of the hidden service.  After that, it encrypts a message containing the rendezvous point using the hidden service public key (so that only the hidden service can decrypt it, using its private key), and sends it to the hidden service through one of its introduction points.  Now, the hidden service creates a circuit to the rendezvous point and the communication with the client can start.

Tor hidden services can be used for so many things.  For example, they allow you to bypass NATs.  This means you could for instance run a web server or an SSH server on a machine in your local network at home and access it from anywhere on the Internet through Tor, without the need to configure anything on your ISP provided router.  This works because as we just saw, all that can be seen from the local network of the hidden service are outward connections, which are usually not filtered.

0x1 - Where to Run an Hidden Service?

I make the assumption that the hidden service that we want to build is something like a small static website, so we do not need a lot of resource to run it but it is better if it is always online.  This is the perfect use for a low-end VPS.  It is not difficult to find very cheap VPS, something like $10 per year, if you are not too picky.  Those are generally not to be trusted as you main server if you want to self-host your email or run your IRC client for instance, but they are perfect for use as MX backup or to host a small hidden service.

Of course the rest of this tutorial is valid for any machine, this was just a suggestion.  It is important to note that in any case, if you run a hidden service on a machine, that same machine should not be a Tor relay, otherwise the location of the hidden service could be discovered, e.g., by correlating its downtimes with those of the relay.

0x2 - Installations

First things first, we need to install Tor on the machine.  I'm familiar with Debian GNU/Linux so this is what I will cover here.  This procedure should work on all the derived distros (Ubuntu, Mint, etc).  Debian is also virtually always available as a choice of OS when you rent a VPS.  I recommend using the stable version (Jessie, at the time of this writing).

To install Tor, create a new file /etc/apt/sources.list.d/tor.list with this content (you need to be root or to use sudo):

$ deb http://deb.torproject.org/torproject.org jessie main
$ deb-src http://deb.torproject.org/torproject.org jessie main

Save it and then add the GPG key that signs The Tor Project's packages to apt by issuing the following commands:

$ gpg --keyserver keys.gnupg.net --recv A3C4F0F9
$ gpg --export A3C4F0F9 | sudo apt-key add -

The first one will retrieve the key and the second one will add it to apt.

You can now issue the usual sudo apt-get update and it will retrieve the list of packages from the Tor project repository.  Then, install Tor and the Tor project keyring so that the necessary GPG keys will be kept in sync and you don't have to worry about that later:

$ sudo apt-get install tor deb.torproject.org-keyring

That's it.

0x3 - Setting Up Your Hidden Service

Now your machine is running the Tor daemon.

As you will see, configuring Tor to serve a hidden service is quite easy.  Be cautious though, as by default server software running on your machine will see connections coming from the Tor network as local connections, and some server software assume that local connections are to be trusted by default.  There are two ways around this: either configure the server software accordingly, or create a virtual network (like a local VPN) and make Tor connections to your hidden service go through that dummy interface.

This is a bit more advanced and will not be covered in this article, but I could write a tutorial for that too later if 2600 readers ask me to.

Using sudo and your favorite text editor, open the /etc/tor/torrc configuration file.

It is a good idea to read all of it, as the default one usually contains a lot of explanations about the different options.  While going through the file, make sure that your machine is not configured as a relay (the ORPort and related options are commented out).  Normally the default options are quite conservative so everything should be fine.

Then, in the hidden service section, add for example these lines:

HiddenServiceDir /var/lib/tor/foo/
HiddenServicePort 80 localhost:8080
HiddenServicePort 22 localhost:22

This instructs the Tor daemon that the /var/lib/tor/foo/ directory contains the information necessary to serve a .onion:

If the directory does not exists when the Tor daemon is (re)started (which you can do with the usual sudo service tor restart command), Tor will create the directory and will automatically generate a private key and the corresponding hostname.  You can then look in the hostname file for the name of your hidden service.  Those are files that you want to backup, as you will need them if you move your hidden service on another machine, or to restore the service with the same name after a server crash, for example.

The next two lines tells the Tor daemon to listen on port 80 for this service and to forward the connection to the port 8080 on localhost (a web server), and to do the same for port 22 (a SSH server).  This will actually work with any kind of TCP services: HTTP and SSH as shown above, but also SMTP, IMAP, IRC, XMPP, etc.

If you want to serve a minimal static website, you could for example use BusyBox5 httpd.

BusyBox is a Swiss Army knife for GNU/Linux systems, it is a statically linked (i.e., it works even when you've made a mess with your system) executable which can act as many of the standard tools.  You can sudo apt-get install it if it is not already on your system.  Assuming that you are in the directory containing the files for your website you can launch the BusyBox httpd server with this command:

$ busybox httpd -p 127.0.0.1:2680

This will bind the webserver to port 2680 on localhost, which means that it is not accessible from outside.  To make it accessible as a Tor hidden service, you would have the following line after the corresponding HiddenServiceDir declaration in your torrc file:

HiddenServicePort 80 127.0.0.1:2680

Now restart your Tor daemon and visitors can point their Tor Browser to your .onion and they will see your website.

For further explanations, we will run a very simple service which counts the curious 2600 readers who connects to it.

In a persistent Screen session on my cheap VPS, I'm running the following script:

counter=0
while true; do
  counter=$((counter + 1))
  echo "Hi, 2600 reader! Counter: "$counter"." | busybox nc -l -p 2600
done

What this does is to initialize the counter variable at 0 and then for ever do the following loop: increment counter by one, wait for a connection on port 2600, and then answer with a single line saying 'Hi' and displaying the number of connection to this service since it has been (re)started.

Then I add the following lines in my torrc (you can have multiple hidden services):

HiddenServiceDir /var/lib/tor/2600/
HiddenServicePort 23 localhost:2600

(I chose the port 23 as it is the default Telnet port.)

Now if I look into the /var/lib/tor/2600/hostname file, I see that the name is: 6yhl3mvmk7nrnfds.onion

(I will try to keep this running as long as possible, but the counter will be reset when I reboot my VPS).

0x4 - Accessing Your Hidden Service

As already said, if your service is a website, you can just point the Tor Browser to the .onion name and you are good to go.

But how to access my little counter service?  Or an SSH server?

On a local machine where you have Tor installed and running, there is usually a tool called torsocks.

It is a hackish tool which uses the LD_PRELOAD trick in an attempt to make all outgoing connections pass through the Tor SOCKS proxy.  It would work like in this example:

$ torsocks telnet 6yhl3mvmk7nrnfds.onion
Connected to 6yhl3mvmk7nrnfds.onion.
Escape character is '^]'.
Hi, 2600 reader! Counter: 1.
Connection closed by foreign host.

I do not like this approach a lot, as it proved to not be very reliable.

Instead I prefer to use the BSD flavor of Netcat, which you can install as the netcat-openbsd package in Debian based distributions.  It provides a handy nc tool which is more powerful than traditional netcat or than BusyBox nc.

It has two command line options of interest: -X allows to specify the type of proxy used, and -x the address and port of the proxy.

By default Tor create a SOCKS5 proxy on port 9050 (look for the SocksPort option in your torrc file).

So we can use that to connect to my little counter service:

$ nc -X 5 -x 127.0.0.1:9050 6yhl3mvmk7nrnfds.onion 23
Hi, 2600 reader! Counter: 2.

The same tool can be used as a ProxyCommand for SSH.  Simply add this in your ~/.ssh/config file:

Host *.onion
CheckHostIP no
Compression yes
ProxyCommand nc -X 5 -x 127.0.0.1:9050 %h %p

With that, SSH will transparently connect through Tor whenever the hostname ends in .onion.

It also activates the compression, which helps when using Tor as it is slower, and disable the IP check as it will virtually change every time when going through Tor.

0x5 - Customize Your .onion Name

It is possible to customize up to some point your .onion name.

There is a tool called Shallot6 which simply does the brute-force for you.  There is no better way than brute-force, otherwise it would mean that it is possible to derive the private key from the public key and that would be a huge security problem.

You need to compile Shallot to get it, which is quite straightforward (the usual ./configure && make).

Then you can run Shallot with a regexp as argument and it will generate public+private key pairs until it finds one for which the .onion name matches the regexp.

For example I used the command ./shallot ^pablo to find one which starts with my first name, allowing me to have the Onion mirror of my website at: http://pablo6zbxiijn5hd.onion

Running it with hacker as regexp quickly yields:

----------------------------------------------------------------
Found matching domain after 384389 tries: pnyvlhackerizmkd.onion
----------------------------------------------------------------
-----BEGIN RSA PRIVATE KEY-----
<base64 encoded private key spreading on multiple lines>
-----END RSA PRIVATE KEY-----

To use it, you create a new directory, e.g., /var/lib/tor/hacker/, and put inside a hostname file with a single line containing pnyvlhackerizmkd.onion, and a private_key file containing the output of Shallot except the first three lines (the RSA key, including the BEGIN and END lines).

Now you have to give the new directory and its content the proper permissions and owner.  The easier is to clone the good settings generated by Tor itself.

For example copying on the /var/lib/tor/foo/ directory from earlier:

$ cd /var/lib/tor/
$ sudo chown -R --reference=foo hacker
$ sudo chmod --reference=foo hacker
$ sudo chmod --reference=foo/hostname hacker/*
$ ls -lR # check that permissions and owners/groups are identical

Then, you simply need to add the corresponding HiddenServiceDir and the HiddenServicePort you want in the torrc file and restart Tor.

Of course, the longer your regexp is, the more time it will take to find a matching name.  Also, you need to be aware that onion names are actually values encoded in Base32, which means that you can have all 26 letters from 'a' to 'z' but only 6 digits, from '2' to '7', so do not attempt to get a name starting with "2600" for instance as no name will ever match and Shallot will run indefinitely.

0x6 - The Setup for My Website

I manage my website in a Git7 repository.

I have a public/ subdirectory which content is generated by a Makefile8.  So what I do is simply to have a Git remote on the VPS which hosts the onion mirror of my website.  This remote is configured with:

$ git config receive.denyCurrentBranch updateInstead

Running this command inside the remote Git repository makes it automatically update its working directory when I push to it.  Then I have a Git post-receive hook (checkout the documentation about this on Git website, basically it is a shell script in .git/hooks/post-receive) which calls make to update the website with the new content.

This way when I update my website, I simply push it to the different servers that host mirrors of it.

We will see in the subsequent articles that the hooks are a bit more complicated for IPFS and ZeroNet, but it is just as trivial for I2P.

0x7 - Conclusions

I hope you learned something reading this article.

In any case, I hope you will put the freedom and the privacy provided by Tor hidden services to good use rather than evil.

Next time, we'll learn how to do the same kind of things using I2P, the Invisible Internet Project.

0x8 - References

  1. The Tor Project  (www.torproject.org)
  2. I2P  (geti2p.net)
  3. IPFS  (ipfs.io)
  4. ZeroNet  (zeronet.io)
  5. BusyBox  (www.busybox.net)
  6. Shallot  (github.com/katmagic/Shallot)
  7. Git  (git-scm.com)
  8. Make  (www.gnu.org/s/make)
Return to $2600 Index