Hidden Onion Service using Tor, nftables and NGINX

Marcus Cvjeticanin
Dev Genius
Published in
5 min readMay 22, 2022

--

Tor offers an extra level of privacy. In this article we are going to go trough the process of setting up a hidden onion service using Tor on your NGINX server.

I’m going to assume that you already know how to setup a GNU/Linux server either on a cloud provider or VPS and know your way around your preferable shell. We will be focusing on installing this on a Debian derived system.

Update system

So what we first need to do is to update the system.

sudo apt update
sudo apt upgrade

Installing a firewall

Now we are going to install nftables. If you never heard about it, it’s basically very similar to iptables (legacy) but a much newer one (since 2014). Advantages of nftables over iptables is less code duplication and easier extension to new protocols.

sudo apt install -y nftables
sudo systemctl enable nftables
sudo systemctl start nftables

We now have nftables installed and we will add a table and a chain that we will append the rules to.

sudo nft add table inet tor_table
sudo nft add chain inet tor_table tor_chain

Creaet a rule to accept all related and established traffic.

sudo nft add rule inet filter tor_chain ct state related,established counter accept

Then we add a rule to accept loopback interface traffic.

sudo nft add rule inet filter tor_chain iif lo counter accept

We also add open access to port 22, which is the SSH port for our VM/VPS.

sudo nft add rule inet filter tor_chain tcp dport 22 counter accept

Drop all other incoming traffic.

sudo nft add rule inet filter tor_chain counter drop

Note that we do not need to open port 80, the HTTP port. This is because of the way onion services communicate with clients via rendezvous points.

Persist the firewall across reboots.

sudo nft list ruleset > /etc/nftables.conf

Install NGINX webserver

Now we are going to install the webserver NGINX so we can handle the web requests.

sudo apt -y install nginx

Edit the main NGINX configuration file.

sudo vim /etc/nginx/nginx.conf

In the main http block, uncomment the line that prevents display of revealing information.

server_tokens off;

Add a line to prevent someone presenting your site’s content in a frame on some other site.

add_header X-Frame-Options "SAMEORIGIN";

Add a line to reduce the possibility of cross-site scripting.

add_header X-XSS-Protection "1; mode=block";

Add lines to limit buffer sizes, thus reducing the potential for buffer overflow attacks.

client_body_buffer_size 1k;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;

Write the NGINX configuration file to disk, and quit the editor.

Edit the default host configuration file.

sudo vim /etc/nginx/sites-available/default

Comment out the lines that make NGINX listen on TCP port 80 in the server block, and add a line that makes NGINX listen on a Unix socket:

#listen 80 default_server;
#listen [::]:80 default_server;
listen unix:/var/run/nginx.sock;

Still within the server block, restrict unnecessary HTTP request types by adding the lines.

if ($request_method !~ ^(GET|HEAD|POST)$ )
{
return 405;
}

Write the default host configuration file to disk, and quit the editor.

Edit the system service file.

sudo vim /lib/systemd/system/nginx.service

In the [Service] block, add a line to contain NGINX within its own private network, with only a loopback interface.

PrivateNetwork=yes

Write the NGINX service file to disk, and quit the editor.

Restart NGINX with the new configuration.

systemctl daemon-reload
systemctl restart nginx
systemctl status nginx

Install Tor

Now we install Tor and create the hidden service.

Install the prerequisite package.

sudo apt install -y apt-transport-https

Add the Tor repositories to your Advanced Packaging Tool (APT) sources list.

sudo vim /etc/apt/sources.list

Add lines at the bottom for the Tor project repositories. This might be different depending on your OS. Note that jammy Ubuntu 22.04 LTS does not have the dependencies available for Tor so you might run into trouble with that.

deb https://deb.torproject.org/torproject.org focal main
deb-src https://deb.torproject.org/torproject.org focal main

Write the file to disk, and quit the editor.

Add the GNU Privacy Guard (GPG) key used to sign the Tor packages.

sudo apt install -y gpg curlcurl https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --importgpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | apt-key add -

Update your package lists:

apt update

Install Tor from the Tor project repository:

sudo apt install -y tor deb.torproject.org-keyring

Edit the main Tor configuration file:

sudo vim /etc/tor/torrc

Completely replace its original contents with the following:

Log notice file /var/log/tor/log
RunAsDaemon 1
DataDirectory /var/lib/tor
HiddenServiceDir /var/lib/tor/hiddenservicename/
HiddenServicePort 80 unix:/var/run/nginx.sock

Instead of literally putting hiddenservicename in the above, you should put a meaningful name of your own choosing.

Write the file to disk, and quit the editor.

Restart Tor for this change.

sudo systemctl restart tor

Check that Tor is up and running.

tail /var/log/tor/log

You should see a message.

Bootstrapped 100% (done): Done

To determine your onion URL, issue the command.

cat /var/lib/tor/hiddenservicename/hostname

Instead of literally putting hiddenservicename, you should put the name you previously chose in the above.

You will get a response containing a domain name of 56 characters, suffixed by .onion. It will look like this:

uvbmrlw3vmbvz3q7cmf3pff777mavz3o4gwtgc6xu7zsvgvfuslcoryd.onion

You should also save the keys somewhere safe, where only you have access to them. The file names are hs_ed25519_public_key and hs_ed25519_secret_key.

Change the server name by editing the default site configuration file:

sudo vim /etc/nginx/sites-available/default

Amend the server_name _; line to read:

server_name uvbmrlw3vmbvz3q7cmf3pff777mavz3o4gwtgc6xu7zsvgvfuslcoryd.onion;

Write the file to disk, and quit the editor.

Restart NGINX.

systemctl stop nginx
rm /var/run/nginx.sock
systemctl start nginx

Test the configuration

You may have to wait ten minutes or so for your hidden service onion address to propagate through the network.

Now, to test your configuration so far, download and install the Tor Browser from the Tor project site at https://www.torproject.org.

In your Tor Browser, visit your onion site with the http protocol and your onion address. For example:

http://uvbmrlw3vmbvz3q7cmf3pff777mavz3o4gwtgc6xu7zsvgvfuslcoryd.onion

You should see the Welcome to Nginx! page. Great!

If you do not see anything and you can’t connect. You might need to change the ownership of the tor service by doing the following.

sudo chown -R root /var/lib/tor
sudo service tor restart

Confirm by starting tor to and to see that everything is up.

tor

Summary

Now you should know how to setup a firewall using nftables and a webserver using NGINX to configure it to handle traffic through Tor network so we can ensure that our privacy is sustained. I hope you found this article useful/interesting. If so, please follow me on Medium for more upcoming articles. Cheers!

References

--

--

Software Engineer. Specialized in backend systems. Writing about Java, Rust, CI/CD & Cloud. Sharing insights on delivering high-quality software efficiently.