Since I first heard about the Tor network in high school I thought it was the coolest thing ever. A hidden part of the internet that was totally anonymous, and as soon as the Edward Snowden leaks came out I knew it was not only cool but a necessity. It was a way to be protected online, not only from prying state surveillance, but from hyper-capitalists who want to monetize every last search and download.
Now, I’ve used Tor in my daily life for a while, like at work when I need to check if a customer’s website is accessible somewhere else in the world from my desk in Virginia (most of the times it is, and the issue is just DNS propagation. . . it’s always DNS. . . that or WordPress permalinks), and I always thought about maybe setting up my own hidden service. For what? Who knows, maybe I’d mirror my personal site on Tor. Mostly I just wanted to see if I could do it. So I did, and here’s a little guide on how I did it.
Step Zero: Your Platform
If you’re going to run any kind of web service, you need a server to keep running at all times in order to serve the service. This means spinning up (and paying for) a Droplet on DigitalOcean or an instance on AWS (or god forbid, whatever the VMs on Azure are called), but if you have the inclination you can set up a home server to do all of this with. I went with DigitalOcean, since I use it at work and I have a few personal VMs there already. And since I already have a few VMs there, I didn’t need to bother with temporary passwords or anything, because each new Droplet is already set up with my SSH keys.
The Tor Project maintains official packages for a number of Linux distros, including Debian and CentOS/RHEL; the package in the Ubuntu repos is apparently out of date so if you go the Ubuntu route DO NOT use it. I went with CentOS, just because it is the server distro.
Step One: Setting Up
The first thing I did after spinning up the server is the same thing I do with any server, setting up a Subdomain A Record on one of my domains to point to it so I can use a URL instead of an IP when SSH-ing in. By default, I ssh-d in as root, and once I was in I installed all the packages I know I’ll need for setup. In this case, I ran:
yum update -y && yum install -y epel-release && yum install -y fail2ban ufw python3 vim lighttpd tor lynx
These first two commands will update the system and install the Extra Packages for Enterprise Linux, which is a repo of additional packages for enterprise-level linux distros in the Fedora family like CentOS and RHEL, some of which will be needed for setting up a Tor hidden service. The last command installed fail2ban (some anti-bruteforcing software), ufw (a simple firewall), python3 (my preferred scripting language), vim (my preferred text editor), lighttpd (the web server I’ll be using for this), tor (take a guess), and lynx (a command line web browser).
Step Two: Basic Security
Once everything was installed, I needed to make some simple security adjustments. First I set up Fail2Ban using the guide from DigitalOcean, and unless you’re über concerned with security, using this simple
/etc/fail2ban/jail.local file should suffice.
[DEFAULT] # Ban hosts for one hour: bantime = 3600 # Override /etc/fail2ban/jail.d/00-firewalld.conf: banaction = iptables-multiport [sshd] enabled = true
Next, because running everything as root can be dangerous and insecure, I followed this guide from DigitalOcean to create a non-root user with sudo privileges. Here’s the bash one-liner that summarizes the article.
adduser username && passwd username && usermod -aG wheel username
I had to set this new user up with my ssh keys so I could log in. DigitialOcean has some guides about creating ssh keys with OpenSSH, and how to add the public key to your authorized_keys file. However, if you’re running all of this on a DigitalOcean droplet like I am, you can just copy your ssh key from the root user to your newly created user by running:
mkdir /home/username/.ssh && chmod 700 /home/username/.ssh && chown username /home/username/.ssh && chgrp username /home/username/.ssh && cp ~/.ssh/authorized_keys /home/username/.ssh && chmod 600 /home/username/.ssh/authorized_keys && chown username /home/username/.ssh/authorized_keys && chgrp username /home/username/.ssh/authorized_keys
And once there is a non-root user with the proper ssh keys, I disabled both root login via ssh and password login via ssh by making sure
PermitRootLogin are uncommented and say no next to them in
Once ssh has these additional security configurations on it, I set up the firewall to block anything besides ssh connections.
ufw enable && ufw default deny incoming && ufw default allow outgoing && ufw allow ssh
And then, when everything is configured, I made sure all of these services are enabled (I can guarantee sshd is, but it doesn’t hurt to make sure) and then I restarted them. Afterwards, I logged out of the server, and logged back in as the new user.
systemctl enable sshd && systemctl enable fail2ban && systemctl enable ufw && systemctl restart ufw && systemctl restart fail2ban && systemctl restart sshd && exit
Step Three: The Hidden Service
Day-to-day, I mostly deal with the Apache and Litespeed web servers, but for personal projects in the past I’ve mostly used Nginx. However, for a Tor hidden service, I read that Lighttpd was one of recommended web servers since it is fast and lightweight; I don’t have much experience with Lighttpd, but using it for a Tor hidden service gives me the perfect opportunity to explore it more.
First, I had to bind the webserver to localhost and set the port. Both of these are in the Basic Configuration section of
/etc/lighttpd/lighttpd.conf by uncommenting
server.bind = "localhost", changing
server.port to 8080, and setting
server.use-ipv6 to disable . Once that is done, I ran the service and made sure it’s accessible locally through lynx.
sudo systemctl enable lighttpd && sudo systemctl restart lighttpd && lynx localhost:8080
Once that’s done, I had to open up
/etc/tor/torrc and find the “This section is just for location-hidden services” section then add these lines:
HiddenServiceDir /var/lib/tor/hidden_service/ HiddenServicePort 80 localhost:8080
I then enabled and started the Tor service, and once that was up and running grabbed my hostname. Be sure to keep the private key secure, and do not share it with anyone, or else they will be able to spoof your hidden service.
sudo systemctl enable tor && sudo systemctl restart tor && sudo cat /var/lib/tor/hidden_service/hostname
The Tor Project has more in-depth/technical guides on doing all of this, but this guide here should provide someone with enough information on setting up and getting started with a simple Tor Hidden Service.