Tor Hidden Services are awesome

Gemini version of this post

I had heard about Tor Hidden Services and even used some a long time ago, but they never really caught my attention, especially since Tor already provides a lot of anonymity and security. It wasn’t until recently that I decided to learn more about them, after reading a post in Jan-Lukas Else’s blog (which I’m subscribed to via RSS and enjoy reading) mentioning the awesomeness of Onion Services and linking to a nice explanation in Tor Project’s official website:

According to Tor Project’s article, the main benefits of onion services are:

What really sold me to onion services, apart from the security, privacy and anonymity aspects, were the NAT punching capabilities built into the protocol. My answer to the question “Is your network filtered and you can’t open ports on your firewall?”, is a huge YES, and I bet most people’s is too. Most ISPs block inbound traffic, don’t allow port forwarding and the public-facing IPs change very often; which makes it almost impossible to run your own internet services and access them from everywhere. Luckily, there are ways to get around this: NAT punching.

Usually, internet connections can only be started from the inside (i.e. LAN) of your home network; everyone trying to reach you from the outside (i.e. WAN) without your request will be rejected. This is a security measure, to avoid unwanted connections or network attacks; but also to prevent the consumer-oriented infrastructure from getting slow because of a random computer geek running high-demand services on it. However, it is important to make it easier for us to run our own internet services, if we want to stop relying on tech megacorps for literally everything. Tor provides us with something free and reliable (albeit slightly slow, by design).

Basically, rendezvous and introduction points are automatically established when the onion service starts (leveraging the same Tor nodes that make up the global Tor network), and descriptors about them are signed by the host and inserted into a DHT. The long sequence of characters before the .onion in the domain (e.g. 4hebgytoglz5paicfhx2ltrrjc7y37tjndk2prrahw3x5df5u4gfogad.onion, which is my onion service) is actually the public key of the onion service, and the private key is obviously kept secret (so that no one can impersonate you or steal your domain). Your onion domain will never change as long as the encryption keys remain the same. You can create as many onion services as you want in the same machine.

I decided to run my own onion service from my little Orange Pi One (Ávalos' Indie Server 1) at home. I followed the official steps on Tor Project’s website:

I wanted to use Apache HTTP Server instead of NGINX this time, because I just felt like it, and also because I forgot how to use it and wanted to explore it again. It is nostalgic because Apache was the first HTTP server I used, back in 2014, when I was still in elementary school. And it is developed by a non-profit, which is nice.

I created a VirtualHost listening in port 8080 and serving a directory, and configured Tor to forward external port 80 to localhost:8080. It was pretty easy, and it worked perfectly fine! I discovered subdomains were supported, so I decided to use the base domain for the Tor mirror of my personal website, and the blog subdomain for a mirror of Ávalos' Indie Blog.

Apache configuration

# /etc/apache2/sites-available/tor-main-website.conf
<VirtualHost *:8080>
	ServerName 4hebgytoglz5paicfhx2ltrrjc7y37tjndk2prrahw3x5df5u4gfogad.onion
	DocumentRoot /media/usb/www/tor_main_website
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	<Directory /media/usb/www/tor_main_website>
		Options FollowSymLinks
		AllowOverride None
		Require all granted
	</Directory>
</VirtualHost>
# /etc/apache2/sites-available/tor-blog-website.conf
<VirtualHost *:8080>
	ServerName blog.4hebgytoglz5paicfhx2ltrrjc7y37tjndk2prrahw3x5df5u4gfogad.onion
	DocumentRoot /media/usb/www/tor_blog_website
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	<Directory /media/usb/www/tor_blog_website>
		Options FollowSymLinks
		AllowOverride None
		Require all granted
	</Directory>
</VirtualHost>

Tor configuration

# /etc/tor/torrc
# ...
HiddenServiceDir /var/lib/tor/main_website # where keys and stuff will be stored
HiddenServicePort 80 127.0.0.1:8080 # external tor port (80) redirects to 127.0.0.1:8080
# ...

The result was perfect after some trial and error with the HiddenServiceDir folder permissions. I think something like chmod -R 700 and chown -R debian-tor:debian-tor did the trick in Armbian Buster.

I also added a header to my website to let Tor Browser (or other Tor browsers) know that there’s an onion service version of the website, so it can automatically redirect to it. I had to add a line to my site’s NGINX configuration:

# /etc/nginx/conf.d/avalos.me.conf
# ...
    location / {
        # ...
        add_header Onion-Location "http://4hebgytoglz5paicfhx2ltrrjc7y37tjndk2prrahw3x5df5u4gfogad.onion$request_uri" always;
        # ...
    }
# ...
# /etc/nginx/conf.d/blog.avalos.me.conf
# ...
  location / {
      # ...
      add_header Onion-Location "http://blog.4hebgytoglz5paicfhx2ltrrjc7y37tjndk2prrahw3x5df5u4gfogad.onion$request_uri" always;
      # ...
# ...

And that’s basically it! I didn’t explain everything, as the Tor Project tutorial I linked is pretty nice and easy to follow. I hope you enjoyed this little guide. I invite you to read more about how Tor and Tor Hidden Services work, very interesting and exciting stuff.