Protecting Dissent: How to set up a Tor Hidden Service in Ubuntu 16.04


“When you do something you should burn yourself completely, like a good bonfire, leaving no trace of yourself.” ~Shunryu Suzuki



In America, Freedom of Speech is a protected constitutional right. It protects our ability to openly dissent and criticize the government and sitting administration without fear of being silenced or threatened by the strongest authority in the land for the mere act of voicing disagreement. Even with this legal protection, many people in the United States, as well as people all over the world, still feel the need for a safe place to set up shop and showcase their dissent without fear of recrimination. While we won't be exploring the merit of those feelings, it is enough to suggest that safeguards do need to be in place in order to protect dissenting voices from the potential tyranny of those with power.

The American freedom of speech, and even the great separation of church and state, are an acknowledgement that opinions and thought cannot possibly be legislated, and that governance is about the regulation of action, and not inner opinions or belief. As soon as thought police begin making their rounds, innovation and progress are suffocated, and people suffer along with a government that is entangled in unwinnable battles. Protecting these freedoms means not only protecting the individual, but maintaining the integrity of a civil and democratic society. 

Expression is the meeting place between the inner world of opinion and the governable world of activity, and freedom of expression is integral to both healthy individuals, and a healthy democracy. However, causality itself cannot be circumvented, a protected freedom can neither mean a freedom from consequence, nor a total free reign on expression. You cannot escape the consequences of openly expressing mean spirited or bigoted views, or presenting factually incorrect statements as absolute truth. You cannot legally express any kind of intention to assassinate a public official, and on and on. While these examples are non-ambiguous, the fine line between what is acceptable and what needs to be explored is a blurry line at the best of times, and so we need tools in place to help us meet the unavoidable challenges inherent in navigating this meeting of inner and outer worlds.

It is clear that we need to be able to openly discuss all of our deeply held opinions free from the fear of their (un)popularity, and without worrying about undue consequence, in order to reach reasonable conclusions. We should be able to openly and honestly discuss our conclusions, the basis of them, and the logic with which we have reached them without feeling like we have to be clinging to them. If we want peace at home, and a workable civil democracy, then we need to value this evaluative process more than we value pushing our perspective, being right, or winning the fight. Without these principles, democracy becomes lost to authoritarianism, plain and simple. Again, we need safeguards in place in order to protect dissenting voices from the potential tyranny of those with power, or those that crave power. Those safeguards need to reach out beyond mere legal or bureaucratic rhetoric.

One robust solution to this problem is Tor, aka, The Onion Router. Feel free to read through the recently announced Tor Social Contract, wherein they explain why they do what they do (spoiler, it has a lot in common with what I have presented here). In my previous two posts I explored the merit and technical operating principle behind the anonymizing Tor network, explained how to act as a client and connect to it, and demonstrated how to strengthen it by running a relay server. This post will cover how to take advantage of the privacy grating powers of the Tor network as a website or service provider, and gain some protection for your potentially dissenting voice.



Understanding Tor Hidden Services


Before setting up your new Hidden Service in the Tor network, it might be a good idea to understand a little bit about how it works. Regular internet connections between a client and a website only have a couple of small steps. First a site operator sets up their site on some server that physically exists at some IP address, and registers a domain name to that IP address in a records system known as DNS. You enter in the URL, like, into your browser and click to go, a quick DNS lookup happens to match up the URL to the proper IP address, and then your browser connects to that IP address, asking it for website data related to the URL, and if it is a valid request, the server sends the information. This process can be likened to looking up somebody's name in a phone directory to find out their physical address, and then going to their house to ask for some kind of information. If the phone directory (DNS) records are correct, then you can find their house (web server) at the proper address (IP) and ask them for their information. If it is a valid request, they will serve it up, if not... you get a closed door. 

Tor behaves quite differently, since it has to hide the IP address of the server while verifying conencitons to it, allowing it to have a validated and anonymous presence. According to The Tor Project, this is a complex 6 step process, in brief, these 6 steps are as follows, 

  • The website owner, me, joshp, sets up the site to be Tor capable, generating a unique set of keys, makes a few connections to the Tor network, and awaits data transfer 
    • The keys act not only as a way to encrypt and decode messages, but also as a way to verify the identity of a website in an anonymous way
  • I then (optionally) advertise the site, and the public component of the key pair at a distributed Hidden Service database as a new hidden service
    • this step can be left out for stealthy security reasons if desired
  • A potential visitor , you, finds out about the hidden service, gets the unique public key for that site from the database, and sets up a rendezvous point
  • You then send that rendezvous point location and a one time secret to me in a message that is encoded, or encrypted with the public component of the unique key pair. Only someone with the other half of the decoder key can unscramble the message, and that other half is kept private, by me. You have that message delivered to me by the Tor network, which anonymizes the delivery as discussed before regarding clients and relays.
  • I receive your message, decode it, and connect to the rendezvous point via my Tor circuits, as you have connected to it via yours, and I provide the one-time-secret you set up to verify my identity as the actual service that you are attempting to reach
  • We use our Tor circuits to exchange data via the rendezvous point for the duration of our session

At no point does the client, you, actually know the location of the server, me, and since all of the circuits into the network and to the rendezvous point are built using Onion routing, all traffic is encrypted and nobody really knows enough about anybody else to be able to discover them outside of the network. From a client perspective, your connection to a hidden service is even more discrete than using the Tor network as a proxy, since the only thing an observer can see is that someone at your location is using Tor. Your traffic never leaves the network, and this removes a point of vulnerability.

For all of its inventiveness and ingenuity, this is not a foolproof system, however there are even more ways to increase security which we will discuss further on.



Setting up a Tor Hidden Service

With Apache in Ubuntu 16.04


This tutorial is for a working Ubuntu 16.04 installation. While the Tor settings themselves should essentially be the same for any OS that you install it in, there are settings involved with this tutorial that are specific to this OS, and this version of it. Why?

  • Unlike Microsoft Windows, and Mac OS, Linux is open source, which means no backdoors put in by the OS provider (ie., Apple can't open up your OS at the request of anybody), therefore Linux is inherently secure on a level not possible with corporate OS's
  • Ubuntu is the most popular and accessible Linux distribution on the market at this time, meaning that it is well distributed, well established, well maintained, and easy to deploy.
  • 16.04 is the latest long term support release of this OS, and it just came out this year. That means that if you install on this system, you will enjoy 5 years of Ubuntu support and free critical updates before having to upgrade your OS again. 

If you are interested in setting up a Tor Hidden Service on a long term basis, you may want to look into getting your self an inexpensive VPS rather than piggybacking on top of your home system. I have had good luck with LetBox VPS, which comes with free DDoS protection. 

Finally, on top of a machine to run it on, a secure operating system, and Tor itself, we will be using Apache to serve out our Hidden Service website. 

Let's get to work. 


Installing Tor


Installing Tor on Ubuntu is painless and simple. We want to use the Tor project's latest code, and make sure to get updates as new releases come out. The following steps will set this up.

Create the file /etc/apt/sources.list.d/tor with the following contents

deb xenial main

deb-src xenial main


Enter the following two lines in a terminal to get Tor's keys

$ gpg --keyserver --recv 886DDD89

$ gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add -


Install Tor with the following terminal command

$ sudo apt-get update && sudo apt-get install tor


Installing Apache


Getting comfortable with Apache is beyond the scope of this article. In brief, however, to install Apache all by itself, just execute the following command...

$ sudo apt-get install apache2


You should now be able to point your browser to localhost (click on the link) and see the default Ubuntu Apache web page. 

If you want the whole LAMP stack you might want to use the excellent tool Tasksel, which simplifies the installation of complex suits of packages by organizing them into single meta-packages that are tested and pre-configured to work harmoniously together.

$ sudo apt-get install tasksel

$ sudo apt-get install lamp-server


Slightly more detailed information can be found on LAMP stack installation here, but since the only part of the stack that needs to be configured to work with Tor is Apache, we will just continue.


Configuring the Service

One step at a time


We have to give Tor some permissions for the locations that will hold the hidden services data. Open the file /etc/apparmor.d/system_tor and add the following content somewhere before the ending bracket: 

owner /var/lib/tor/** rwk,

owner /var/lib/tor/ r,

owner /var/log/tor/* w,


Restart Apparmor by executing the following command:

$ sudo service apparmor restart


Open /lib/systemd/system/tor@default.service and add the following two lines to the file if they are not present (look around line 32 or so)



Now make the directories and set directory based permissions to accompany the work above. In a terminal enter the following:

$ sudo mkdir /var/lib/tor/site0

$ sudo chown debian-tor:debian-tor /var/lib/tor/site0

$ sudo chmod 700 /var/lib/tor/site0


Now open the Tor configuration file at /etc/tor/torrc


This torrc example has disabled all tor client services and relay functions. While it is possible to run the same tor instance as a hidden service provider, a client, and a relay with or without exit capabilities, it is NOT recommended to run your hidden service on the same machine as your relay. More information about this can be found here, but it is enough to know that it represents a significant security issue. 

The relevant section of the torrc file for our current purpose begins at line 64, the section that begins with the line

############### This section is just for location-hidden services ###


We need to look at line 73, which defines the HiddenServiceDir and line 74, which defines the HiddenServicePort. These define the location of the hidden service data specific to the tor network, the port that the service should be active on over Tor, and the local interface:port combination that we will be committing to the service. More information on this can be found here. It should be noted that the typical loopback address of should never be used for security reasons, so we will use and so on.

In this config there is another site set up, showing how you can work in more than one service per machine, just make sure to create the appropriate additional directories as done above. There is also the addition of line 77, which defines the HiddenServiceAuthorizeClient. This is an extra layer of security that functions like a static user id cookie or secret, like the authentication aspect of a client side SSL certificate, which has been covered here. No user can access any service that has this set without the other half of the secret, which we will come to in a bit.

For now, we want to get our Apache instance ready to go. The place to start is /etc/apache2/ports.conf and add the following two lines:



These are listen rules with the same interface:port combinations as from the torrc configuration.

Open the file /etc/apache2/conf-available/security.conf and check the following settings in order to protect the anonymity of the server:

ServerTokens Prod

ServerSignature Off


Further secure the anonymity of the server by turning off the Apache status module. Entering the following command into a terminal:

$ sudo a2dismod status


More on this security vulnerability can be found here, the more you know, the better off you are. For now, it is ok to restart Apache and Tor so that the settings can take hold, and make note of any errors that might pop up.

$ sudo service tor restart

$ sudo service apache2 restart


Now we should be able to get our .onion address and give it to Apache. Tor generates and saves this for us in /var/lib/tor/site0/hostname as a single line. Note that site1 will have additional data in it due to the security measures. The extra layer of security shows up in site1's same hostname file:

AlsoWillBeRandom.onion anotherandomstringhere # client: user01
AlsoWillBeRandom.onion andanotherrandomstring # client: user02
AlsoWillBeRandom.onion yetanotherrandomstring # client: user03


Here, the 16 character .onion address is followed by an unique authentication string corresponding to each username set up in the torrc file. In order to connect, the users have to add a new line to their own torrc file and restart their own Tor service (remember, you need to be using the Tor proxy software in order to reach an onion address). USER03 would add the following:

HidServAuth AlsoWillBeRandom.onion yetanotherrandomstring


Now feed this information into the Apache configuration. For a quick test, just open the file /etc/apache2/sites-available/000-default, change two lines, and restart apache. The opening VirtualHost tag in 000-deafualt should look like the following:



The servername directive for site0 should be something like so:

ServerName   ThisWillBeRandom.onion


After saving that, restart Apache, get on your Tor browser, enter in the new onion address and if you see the same default Ubuntu Apache page as before, then PRESTO! That's all there is to it, you're configured and good to get hacking away on your new site. Before moving on, enable both of the hidden services in Apache. To do this, create the file /etc/apache2/sites-available/onion.conf and have it look something like the following:


You can see how both are laid out just like a regular Apache VirtualHost but with the unique listening addresses and .onion urls. After saving, enter the following commands to load the site configuration above:

$ sudo a2ensite onion.conf

$ sudo service apache2 restart


It should be noted that you don't have to worry about SSL with a hidden service, as the Tor network is already encrypted end to end.

Remember to look to /var/log/apache2/error.log or /var/log/tor/notices.log for errror information. If something is broken and there is no data, check the permissions on the /var/log/tor folder, uncomment the following line in your torrc file by deleting the #, restart Tor, and check /var/log/tor/debug.log for clues:

#Log debug file /var/log/tor/debug.log


So now you have a platform that you can use to express your potentially dissenting voice without fear of recrimination. If you run into technical problems you can always chekc out the Tor Wiki, or the Tor Stack Exchange community. If you run into any other kind of problem... try a lawyer?


Extra Tips and Tools

coming soon...



Thanks for reading!


with NGINX assuming TOR installed by TOR browser installer

secret's picture
Good instructions but can you explain how to configure the already-installed TOR that comes with the TOR browser for ubuntu, using NGINX (a separate server to keep it away from the apache used for other services)?

When installing the TOR

joshu's picture

When installing the TOR browser under Ubunut, you are just installing a bundled FireFox with the TOR proxy router underneath, so everything on that end is pretty much the same, just edit the /etc/tor/torrc to suit your needs as the above instructions, and the rest is good to go. While this is the easy path to installing TOR, it is reccomended to use the latest release for security reasons, it is also highly reccomended to host your TOR router on a different machine than your regular server, especially if you are running an exit node. Running these two on the same machine poses a security risk and should be avoided.

At any rate, I'm not sure why you would want to run two http servers, if you are running on the same machine, running both under apache should be fine. However...

I am no NGINX wizard, but it seems like somethng like this should work

server {


server_name ThisWillBeRandom.onion;


root /var/www/site1;

index index.html;


Add new comment