Getting started with Tor hidden services
Tags: privacy, infrastructure, tor
Published: 2022-03-02 18:47:38

This will be happening more and more frequently in the online world: people get silenced. If you're a ruler, it's tempting to selectively deliver only certain information and let's face it - surface web is perfectly equipped for such scenarios. Providers of services have too much to lose if disobey. This is just how power works. But that's a bit different topic...

Today we're gonna talk about the world without centralised authorities, the world of Tor hidden services.

## Enter the .onion!
In Tor we don't use standard domain names like `cz` or `eu`. We use specialised `.onion` generic name that is resolvable only in Tor network. Compared to standard domain names it has one major difference beyond the scope of the visibility - there's no vendor where you have to purchase a name for you service. 

This is how it works - you create a hidden service, a new keypair is generated and part of the public key is then used as your `.onion` name. You can read more about the mechanism in [this post](https://tor.stackexchange.com/a/1285). 

> Please read previous 2 paragraphs again - there's no authority that's responsible for the allocation of names. And when there's no authority - you can't approach it and make it obey with the force 👊

Then you just point Tor daemon to your webserver and voila - everyone with Tor browser (or alternative configuration with SOCKS5 proxy) can access your hidden service! 

Now let's create our first hidden service. That's gonna be fun.

## Part I: server

We need some server first. It can be anything, you can use tiny Raspberry Pi or you can purchase some VPS from Public Cloud providers. I don't have any specific recommendations here. Server in your homelab is more decentralized, on the other hand VPS is easy to obtain. It's up to you.

I'm gonna use VPS purchased from Digital Ocean pre-installed with the latest LTS Ubuntu.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxati8pp0jf0saga61o5.png)

In a couple of seconds I can connect with ssh there and proceed with the configuration!

## Part II: application

In this tutorial we'll be serving some dummy content from the application written in Go. For the sake of simplicity I'm gonna use some snippets from the [Fiber framework's homepage](https://github.com/gofiber/fiber#%EF%B8%8F-quickstart). So here we go, this is our application.

```go
package main

import "github.com/gofiber/fiber/v2"

func main() {
    app := fiber.New()

    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World 👋!")
    })

    app.Listen(":3000")
}
```

Once again, this is Go but you can write your application in any available tool. And of you want to serve static content - use [Caddy](https://caddyserver.com/) or Nginx. 

So now I'm gonna build and test the app:

```bash
go mod init main
go mod tidy
go build main.go
./main&
curl localhost:3000
```

This is what we get as the output:

```
Hello, World 👋!
```

## Part III: supervision

In the modern operating system we can always use some way how to supervise your applications. This is extremely important and I'm gonna give you one specific example: when your server restarts, you want to make sure that applications starts together with the server. 

In the case we use Ubuntu so systemd service unit needs to configured.

So let's move the application to some well-known path

```
mkdir /opt/app
mv main /opt/app/main
```

and create the systemd service unit in `/etc/systemd/system/app.service` file:

```systemd
[Unit]
Description=App
After=network.target

[Service]
Type=simple
ExecStart=/opt/app/main

[Install]
WantedBy=multi-user.target
```

Now we can enable and start the service with `systemctl` commands:

```bash
systemctl enable app
systemctl start app
```

Status of the service can be verified by invoking `systemctl status app`:

```
● app.service - App
     Loaded: loaded (/etc/systemd/system/app.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-03-02 18:08:29 UTC; 2s ago
   Main PID: 2289 (main)
      Tasks: 4 (limit: 1132)
     Memory: 1.3M
     CGroup: /system.slice/app.service
             └─2289 /opt/app/main
```

## Part IV: Tor daemon

All the stuff we were doing till now was pretty much the same as you'd do for standard surface web app, right? So let's make it special. To do so we need to install Tor daemon first.

In this Ubuntu 20.04 we just need to create a new apt source in `/etc/apt/sources.list.d/tor.list`

```
deb     [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org focal main
deb-src [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org focal main
```

add public key to the keyring

```bash
wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
```

and install the package:

```bash
apt-get update
apt-get install tor -y
```

If you're using different operating system - check out the [official documentation](https://support.torproject.org/rpm/). You know the drill I guess 😁 

As the result we have Tor daemon running!

```
systemctl status tor
● tor.service - Anonymizing overlay network for TCP (multi-instance-master)
     Loaded: loaded (/lib/systemd/system/tor.service; enabled; vendor preset: enabled)
     Active: active (exited) since Wed 2022-03-02 18:16:30 UTC; 1min 28s ago
   Main PID: 2959 (code=exited, status=0/SUCCESS)
      Tasks: 0 (limit: 1132)
     Memory: 0B
     CGroup: /system.slice/tor.service
```

## Part V: pointing Tor to our app

And this is the very last part of this tutorial. Tor just needs to be configured to "advertise" our application to the network. 

Open the main configuration file `/etc/tor/torrc` and add following lines to the respective part of the configuration.

```ini
HiddenServiceDir /var/lib/tor/app/
HiddenServicePort 80 127.0.0.1:3000
```

The second line basically says that incoming traffic on port 80 should be routed to localhost:300. And this is the port where the simple app listens.

Tor daemon needs to be restarted first with `systemctl restart tor` command and whent it's up again we can inspect `/var/lib/tor/app/` directory - the home directory of our hidden service.

```bash
ls /var/lib/tor/app/ -lah
total 24K
drwx--S--- 3 debian-tor debian-tor 4.0K Mar  2 18:22 .
drwx--S--- 4 debian-tor debian-tor 4.0K Mar  2 18:23 ..
drwx--S--- 2 debian-tor debian-tor 4.0K Mar  2 18:22 authorized_clients
-rw------- 1 debian-tor debian-tor   63 Mar  2 18:22 hostname
-rw------- 1 debian-tor debian-tor   64 Mar  2 18:22 hs_ed25519_public_key
-rw------- 1 debian-tor debian-tor   96 Mar  2 18:22 hs_ed25519_secret_key
```

The last 2 lines are interesting, this is the key pair I was talking about. Please note that private key needs to be kept in secret, anyone with access to this key can use your onion name for some nasty s**t! And when we talk about the name, let's just check the contents of the `hostname` file. 

```bash
cat /var/lib/tor/app/hostname
ocig6kqiahyictb5y7o37ympfragi4nlzimuylwsfco76ksi2l5edvyd.onion
```

And this is, ladies and gentlemen, a domain name we can use from Tor browser. Let's do it. 

## Result

Install [Tor browser](https://www.torproject.org/download/) or [Brave](https://brave.com/download/) (Brave needs to be launched in specialised Tor mode) and enter onion name to the address bar.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmlmlpwlizk1dgknm74a.png)

This is the service we were working on! It looks just like any other web application but it has one major feature - putting this down requires much more effort that the surface web equivalent. 

Now you can share your fantastic content even with the folks who lives in less free countries 🔥🔥🔥

-----

*Do you need any help with Tor hidden service? Don't hesitate to contact me. I'm 100% committed to make world a better place through the free speech and better privacy ❤️*

-----

*Title image: https://www.deviantart.com/wuphaz/art/Tor-wallpaper-682786904*