Offer an existing site as an onion service

Posted by Sven Kiljan on in Tor, Linux, Networking

Tor can be used to connect to the onion network. Through this network it is possible to visit normal web sites, but also (web) services within the onion network itself. Visiting the onion network is not that exciting. Just install Tor Browser and be on your merry way.

As with Tor users, services within the network can be offered anonymously. This is a short piece about offering an existing web service within the onion network. You can read a good explanation on how hidden services work on the official Tor Project site.

There are several functional roles that a computer can fulfill inside of the onion network. These roles are:

  • Client. Provides anonimity. A popular protocol is HTTP, and products like Tor Browser allow easy access to the network. From a user's perspective it is as easy as using the normal World Wide Web, with some caveats to stay anonymous.
  • Service. Also referred to as hidden service. Provides anonimity. An onion service concerns a server in the onion network to which clients connect.
  • Relay node. Relays connections between onion clients and services through other relay nodes.
  • Exit node. Similar to a relay node, but also allows access to the regular Internet from inside the network.
  • Bridge. Assists onion clients and services with connecting to the onion network when direct connections to relay nodes are blocked.

Getting access to the onion network as a client is in most cases as simple as downloading and starting Tor Browser. Running an onion service requires a bit more preparation. Compared to regular internet services, onion services have some advantages:

  • Assuming that the service is configured correctly, it is as anonymous as an onion client. Users of your service will not know the IP address or location of your server.
  • An onion service does not need any router configuration, such as port forwarding.
  • There is no need to buy a domain name or use a subdomain. Random hostnames are provided for free. Hostnames with recognizable text have to be computed, though.
  • Running Tor barely takes any resources. It uses around 64 MB of memory in addition to a bit of CPU power whenever a connection is served. It can easily run on a basic computer like a Raspberry Pi.

An overall disadvantage is that clients can only visit them safely through Tor. This aspect also comes with an advantage: clients are also anonymous inside of the Tor network. An onion client and server can communicate with each other without either of them (or anybody else, for that matter) knowing the location of the other.

Generate a host (site) name

Sites in the onion network use the .onion top-level domain (TLD). Each domain name is a base32 string (consisting of characters a-z and 2-7) that represents the public key of an onion service. There are two kinds of domains:

  • A V2 onion service has a domain name of 16 characters. Example (with TLD): kiljanorg7fqhrnl.onion
  • A V3 onion service has a domain name of 56 characters. Example (with TLD): kiljan2obelssdyrdiifv5kkw2ytlwcx7lwzzuekkmgyiixsqv7utxyd.onion

Since the hostname represents a public key it cannot be freely picked. Getting a random hostname is as easy as configuring Tor to offer a v2 and/or v3 service and starting it. Tor will generate suitable hostnames automatically. If a random name suffices, just continue with the next section. Otherwise, read on.

To get a hostname that somewhat resembles something recognizable it is needed to generate random hostnames until a desired one is found. There are several utilities available that can do this. These two are discussed:

  • Scallion, for V2 onion service hostnames. Uses GPUs to accelerate generation.
  • mkp224o, for V3 onion service hostnames. Can only use CPUs.

Desired characteristics of the hostname can be given to each program, so it will only save keys that fulfill the criteria. Note that each additional desired character multiplies the number of required calculations by 32. On a couple of Raspberry Pis generating v3 onion service hostnames, a desired prefix of four letters can be found in less than a minute, while a prefix of nine letters might take years. More computing resources help in finding addresses more quickly. Scaling is easy: just run the programs on multiple computers. Since attempts are random and independent from each other, resources will not be wasted on making the same calculations.

An example of using Scallion for generating v2 hostnames:

scallion kiljanorg[2-7]

In this example, only generated hostnames that start with 'kiljanorg' and a digit between 2 and 7 will be saved. Note that base32 only has digits 2-7.

An example of using mkp224o for generating v3 hostnames:

mkp224o kiljan2 kiljan3 kiljan4 kiljan5 kiljan6 kiljan7

In this example, only generated hostnames that start with 'kiljan' and a digit between 2 and 7 will be saved. mkp224o does not support regular expressions. Multiple prefix filters are used instead.

Read here about the structure of v2 hostnames. Background information on how v3 hostnames are constructed can be found here.

Once a name is generated, save all of the associated files. For v2 hostnames this will be hostname and private_key. For v3 hostnames this will be hostname, hs_ed25519_public_key and hs_ed25519_secret_key. The file hostname contains the hostname associated with the key material in the same directory.

Configure Tor

It is assumed that Tor is used on Linux, and that it only will provide a service on the Tor network. Append to /etc/tor/torrc:

SocksPort 0

HiddenServiceDir /var/lib/tor/hidden_service/v2
HiddenServiceVersion 2
HiddenServicePort 80

HiddenServiceDir /var/lib/tor/hidden_service/v3
HiddenServiceVersion 3
HiddenServicePort 80

And run:

mkdir -p /var/lib/tor/hidden_service/v2
mkdir -p /var/lib/tor/hidden_service/v3

If you have any key material from Scallion or mkp224o, copy it respectively to the v2 or v3 directory before continuing. Then run:

chown -R tor:tor /var/lib/tor/hidden_service/*
chmod 600 /var/lib/tor/hidden_service/v2/*
chmod 600 /var/lib/tor/hidden_service/v3/*

This assumes in your distribution tor is the username under which Tor will be running. This is the default in Arch Linux.

Start Tor at system boot and directly:

systemctl enable tor
systemctl star tor

Configure nginx to forward site traffic

The following is a bare bones example for configuring /etc/nginx/nginx.conf. Adjust to your configuration as needed.

events {}

http {
    include       mime.types;

    server {
        listen default_server;

        server_tokens off;

        location / {
            # See:
            proxy_set_header Proxy "";
            # Enable only if Server Name Indication is needed to access an HTTPS site
            proxy_ssl_server_name on;
            proxy_ssl_name 'domain.example';
            # Set to 'off' if a self signed certificate or a mismatching hostname is used
            proxy_ssl_verify on;
            proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
            # The site to offer as an onion service
            proxy_pass https://domain.example:443;
            # Rewrite scheme and hostname in absolute URLs on web pages
            proxy_set_header Accept-Encoding ""; # Disable any upstream compression
            sub_filter_types 'text/xml'; # Additional MIME types that require rewrite
            sub_filter_once off;
            sub_filter 'https://domain.example' '$scheme://$host';

After creating/modifying nginx's configuration, test the configuration and (re)start nginx:

nginx -t
systemctl enable nginx
systemctl restart nginx

The above nginx configuration listens for HTTP connections on TCP port 81 of the localhost interface. Any connections are forwarded transparently to https://domain.example. Note that a local HTTP interface is offered and not HTTPS. Tor's .onion handshake provides confidentiality and integrity. As earlier discussed, the hostname represents the public key. If the user is certain that a .onion domain name is legitimate, authenticity is an inherent function when visiting it. A third-party does not have to provide authenticity. Read more here for why HTTPS is not necessary for hidden services.

An essential part of the nginx configuration is that absolute (full) URLs on page requests are rewritten by sub_filter. If this would not be done, the hidden service could accidentally link to or try to get resources from its normal site. Such a connection would either use a Tor exit node or a direct connection to the Internet, possibly reducing anonimity. Of course, the forwarded Tor service should avoid getting resources from third-party (normal) sites.

If your copy of nginx has the relevant module included, it is possible to increase downstream bandwidth efficiency for a little bit of CPU cost. Add gzip on; to the location / {} section to (re)compress web pages offered as a onion hidden service. This is mostly useful for large HTML pages, but other content can also be compressed. Just add additional MIME types to compress: gzip_types text/plain application/xml;. More information about nginx's compression functions can be founed here.

Test the connection

Install Tor browser on your computer. Alternatively, install and start Tor, and configure your browser to use a SOCKS v5 proxy on

Now visit the onion service by entering its URL into your browser.

Alternatively it is also possible to visit onion sites directly on the Internet using a Tor2web instance. Do note that client (user) anonimity is lost, as well as confidentiality, integrity and authenticity. The Tor2web operator is effectively a man-in-the-middle, and traffic over the Internet will be plain text unless the Tor2web operator offers HTTPS. The traffic can be seen and modified by Tor2web operators in either case, which they do. Availability is also a weak point, since a Tor2web instance relies on a single party. From all perspsectives using Tor2web is a bad idea, and I would not recommend it.

One final warning

Perfect security does not exist. Neither does perfect anonimity. If you are going to run a high risk onion service, keep up with trends. New attacks and defenses often pop-up. An example of an attack and a possible defense against said attack can be found here.