How To: Host Your Own Tor Hidden Service with a Custom Onion Address

Host Your Own Tor Hidden Service with a Custom Onion Address

A mention of the deep web can bring to mind images of drugs, hackers, and other criminal activity. Despite the presence of these elements, the Tor network is a valuable tool for preserving privacy and anonymity. And browsing the deep web and any hidden services can be as simple as downloading the Tor Browser.

So what's a hidden service? It's pretty much the same thing as a website on the regular internet, only it uses Tor's technology to stay secure. In some cases, someone who creates a hidden service, also known as an onion service, can remain anonymous. Anyone can create a hidden service and make them accessible via a custom onion address, as you'll soon see.

Step 1: Understand How the Tor Network Works

Accessing the internet directly without a proxy, VPN, or other privacy service relays information in a relatively linear fashion. A device attached to the internet via a router follows a series of lookup requests for a specific URL or IP address and returns the content to the device which requested the information.

The contents of the transmission may be encrypted using HTTPS, SSL, or another form of encryption. However, the requests are still directly connected to IP addresses on each end of the transaction and carried in a way that can be analyzed by an internet service provider. In short, your ISP can see where you go on the web.

Simplified visualization of standard traffic.

While the Tor network doesn't entirely bypass an internet service provider in the way a mesh net could, it does utilize a unique method of obfuscating traffic. Rather than directly requesting a webpage or other data by directly addressing a server by its IP, traffic routed over Tor sends the encrypted details of its requests to an entrance node from a list of retrieved nodes within the Tor network first.

That traffic is then carried over several more hops to different nodes in the Tor network, before either reaching its destination within the Tor network or being sent back into the internet through an exit node.

Visualization of Tor-style routing.

Unfortunately, this entrance back into the internet from the Tor network poses a security and privacy risk. The content passed over the exit node is subject to the trustworthiness of the node itself, as the node has the same level of access to the details of a request as an ISP would. If the data is not encrypted at this point, it is subject to being captured and used maliciously, as demonstrated by Chloe in BADONIONS.

To avoid the danger of using exit nodes, we can instead access or host a website which is accessible only and entirely through the Tor network, in the form of a hidden service. Rather than requesting a URL or IP address, the service will be accessible only through an "onion" address, which can only be discovered by its name within the Tor network.

Step 2: Install the Tor Browser

The Tor Browser is available from the Tor Project's website for Windows, macOS, and Linux/Unix systems. It's even usable on Android devices, but we'll be focusing on the computer versions. Just download and install the version that's right for you. If using Linux, such as Kali, you can install Tor more easily from the terminal using apt:

~$ sudo apt install torbrowser-launcher

[sudo] password for kali:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  tor tor-geoipdb torsocks
Suggested packages:
  mixmaster tor-arm apparmor-utils obfs4proxy
The following NEW packages will be installed:
  tor tor-geoipdb torbrowser-launcher torsocks
0 upgraded, 4 newly installed, 0 to remove and 568 not upgraded.
Need to get 3,566 kB of archives.
After this operation, 14.8 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 kali-rolling/main amd64 tor amd64 [1,943 kB]
Get:2 kali-rolling/main amd64 tor-geoipdb all [1,486 kB]
Get:3 kali-rolling/contrib amd64 torbrowser-launcher amd64 0.3.2-11 [61.1 kB]
Get:4 kali-rolling/main amd64 torsocks amd64 2.3.0-2+b1 [76.3 kB]
Fetched 3,566 kB in 1s (3,181 kB/s)
Selecting previously unselected package tor.
(Reading database ... 376773 files and directories currently installed.)
Preparing to unpack .../tor_0.4.3.5-1_amd64.deb ...
Unpacking tor ( ...
Selecting previously unselected package tor-geoipdb.
Preparing to unpack .../tor-geoipdb_0.4.3.5-1_all.deb ...
Unpacking tor-geoipdb ( ...
Selecting previously unselected package torbrowser-launcher.
Preparing to unpack .../torbrowser-launcher_0.3.2-11_amd64.deb ...
Unpacking torbrowser-launcher (0.3.2-11) ...
Selecting previously unselected package torsocks.
Preparing to unpack .../torsocks_2.3.0-2+b1_amd64.deb ...
Unpacking torsocks (2.3.0-2+b1) ...
Setting up torbrowser-launcher (0.3.2-11) ...
Setting up tor ( ...
Something or somebody made /var/lib/tor disappear.
Creating one for you again.
Something or somebody made /var/log/tor disappear.
Creating one for you again.
update-rc.d: We have no instructions for the tor init script.
update-rc.d: It looks like a network service, we disable it.
Setting up torsocks (2.3.0-2+b1) ...
Setting up tor-geoipdb ( ...
Processing triggers for desktop-file-utils (0.24-1) ...
Processing triggers for mime-support (3.64) ...
Processing triggers for gnome-menus (3.36.0-1) ...
Processing triggers for systemd (245.4-3) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for kali-menu (2020.2.2) ...

Step 3: Browse Hidden Services

After Tor installs, you can open "Tor Browser" from your applications, and it will automatically connect to the Tor network. On your first run, it may ask you to "Connect" to Tor or "Configure" it. Choose the former unless you're using a proxy or are in a region that bans Tor.

Next, try browsing to a hidden service. They're not always easy to find, but we have a list of the top hidden services for Tor. Try out any of those as a test.

We can view our route through the Tor network by clicking the site's name in the URL bar where the (i) button is. On older versions, you can click on the drop-down arrow next to the onion icon in the upper left of the window. In the case of visiting an .onion site, we can only see the last relays and the "Onion site" listed in the circuit information.

If you need more information on using the Tor Browser, you can check out our guide on using Tor to remain anonymous in the dark web.

Step 4: Host a Server

The first step in configuring a Tor server will be setting up a way to serve HTTP content, just the same as a regular web server might. While we might choose to run a conventional web server at so that it becomes accessible to the internet as a whole by its IP, we can bind our local server environment to to ensure that it will be available only locally and through Tor.

On a system where we can call a Python module directly, we might choose to use the http.server module. First, we need to be in the directory that contains the content we would like to host. If you just want to test it out with the bare minimum, create a new directory, and change into it.

~$ mkdir tor_service
~$ cd tor_service

Now, we can run a server directly from the command line. Using Python 3 and http.server, we can use the following string to bind to and launch a server on port 8080.

~/tor_service$ python3 -m http.server --bind 8080

Serving HTTP on port 8080 ( ...

Either of these will serve as enough for a test server, but for any larger or more permanent project a full hosting stack will be more useful. Nginx provides a server backend that can be more suitably hardened and secured against the potential threats against a hidden service, although Apache or other HTTP server software can certainly work. Just be sure that it's bound to to prevent discovery through services such as Shodan.

If you have Fing network scanner, you can confirm this is working by running the following in a new terminal window.

~$ fing -s -o text,console

You should see output like the image below if your server is running. And just like that, a Fing scan shows us our server.

Serving HTTP on port 8080 ( ...

04:19:03 > Service scan on:

04:19:03 > Service scanning started.
04:19:09 > Detected service:  5432 (postgresql)
04:19:09 > Detected service:  8080 (http-proxy)
04:19:11 > Service scan completed in 7.720 seconds.

| Scan result for localhost (                                 |
|  Port | Service         | Description                                 |
|  5432 | postgresql      | PostgreSQL database server                  |
|  8080 | http-proxy      | Common HTTP proxy/second web server port    |

To ensure that our server is functional, we'll want to test our local address ( or "localhost" in a web browser by opening it as an address followed by a port number, as seen below.

  • http://localhost:8080

To make testing the server easier, it may be useful to create an "index.html" file in the directory from which the server is being run. In a new terminal, in your Tor directory, create the file.

~/tor_service$ touch index.hmtl

Next, use nano or another text editor to add some HTML to the file.

~/tor_service$ nano index.html

Something as simple as this will work:

Null Byte

Exit with Control-X, type Y, then Enter to save the file in nano. The result will look like the following image if it's working properly.

With our local server environment configured and available at, we can now start to link our server to the Tor network.

Step 5: Create a Hidden Service

First, we will need to install or confirm that the Tor service/daemon is installed. The standalone Tor service is an active separate of the Tor Browser package. For Linux/Unix, it's available here. On Ubuntu or Debian-based distros with apt package management, the following command should work assuming Tor is in the distro's repositories.

~/tor_service$ sudo apt install tor

[sudo] password for kali:
Reading package lists... Done
Building dependency tree
Reading state information... Done
tor is already the newest version (
tor set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 568 not upgraded.

To confirm the location of our Tor installation and configuration, we can use whereis.

~/tor_service$ whereis tor

tor: /usr/bin/tor /usr/sbin/tor /etc/tor /usr/share/tor /usr/share/man/man1/tor.1.gz

This will show us a few of the directories which Tor uses for configuration. We're looking for our "torrc" file, which is most likely in /etc/tor. We can move to that directory with cd, as we run the command below.

~/tor_service$ cd /etc/tor/

Finally, confirm that "torrc" is present by simply running ls.

~/etc/tor$ ls

torrc  torsocks.conf

If the torrc file is present, we will want to edit it. We can use Vim, emacs, or simply GNU nano to edit the file. To edit the file in nano, simply run the following in the terminal. If you're root, you can skip the sudo.

~/etc/tor$ sudo nano torrc

In the file, we're looking for the section highlighted below. To find it quickly, use Control-W to search for "location-hidden," hit Enter, and you should jump right to it.

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

## Once you have configured a hidden service, you can look at the
## contents of the file ".../hidden_service/hostname" for the address
## to tell people.
## HiddenServicePort x y:z says to redirect requests on port x to the
## address y:z.

#HiddenServiceDir /var/lib/tor/hidden_service/
#HiddenServicePort 80

#HiddenServiceDir /var/lib/tor/other_hidden_service/
#HiddenServicePort 80
#HiddenServicePort 22

To direct Tor to our hidden service, we'll want to un-comment two lines.

#HiddenServiceDir /var/lib/tor/hidden_service/
#HiddenServicePort 80

To do this, we simply remove the "#" symbols at the beginning of those two lines. While we're here, we need to correct the port on which Tor looks for our server. If we're using port 8080, we'll want to correct the line from port 80 to port 8080 for the "#HiddenServicePort" line.

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

## Once you have configured a hidden service, you can look at the
## contents of the file ".../hidden_service/hostname" for the address
## to tell people.
## HiddenServicePort x y:z says to redirect requests on port x to the
## address y:z.

HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80

#HiddenServiceDir /var/lib/tor/other_hidden_service/
#HiddenServicePort 80
#HiddenServicePort 22

Write the changes with Control-X, type Y, then Enter to exit.

Step 6: Test the Tor Service

With the changes written to our torrc file and a server running at, making our server accessible over Tor is as simple as starting the Tor service. We can do this from the command line by typing the following.

~/etc/tor$ sudo tor

Jul 10 19:20:44.992 [notice] Tor running on Linux with Libevent 2.1.11-stable, OpenSSL 1.1.1g, Zlib 1.2.11, Liblzma 5.2.4, and Libzstd 1.4.4.
Jul 10 19:20:44.992 [notice] Tor can't help you if you use it wrong! Learn how to be safe at
Jul 10 19:20:44.992 [notice] Read configuration file "/etc/tor/torrc".
Jul 10 19:20:44.994 [notice] Opening Socks listener on
Jul 10 19:20:44.994 [notice] Opened Socks listener on
Jul 10 19:20:44.000 [notice] Parsing GEOIP IPv4 file /usr/share/tor/geoip.
Jul 10 19:20:45.000 [notice] Parsing GEOIP IPv6 file /usr/share/tor/geoip6.
Jul 10 19:20:45.000 [warn] You are running Tor as root. You don't need to, and you probably shouldn't.
Jul 10 19:20:45.000 [notice] Bootstrapped 0% (starting): Starting
Jul 10 19:20:45.000 [notice] Starting with guard context "default"
Jul 10 19:20:46.000 [notice] Bootstrapped 5% (conn): Connecting to a relay
Jul 10 19:20:46.000 [notice] Bootstrapped 10% (conn_done): Connected to a relay
Jul 10 19:20:46.000 [notice] Bootstrapped 14% (handshake): Handshaking with a relay
Jul 10 19:20:46.000 [notice] Bootstrapped 15% (handshake_done): Handshake with a relay done
Jul 10 19:20:46.000 [notice] Bootstrapped 20% (onehop_create): Establishing an encrypted directory connection
Jul 10 19:20:46.000 [notice] Bootstrapped 25% (requesting_status): Asking for networkstatus consensus
Jul 10 19:20:46.000 [notice] Bootstrapped 30% (loading_status): Loading networkstatus consensus
Jul 10 19:20:47.000 [notice] I learned some more directory information, but not enough to build a circuit: We have no usable consensus.
Jul 10 19:20:47.000 [notice] Bootstrapped 40% (loading_keys): Loading authority key certs
Jul 10 19:20:47.000 [notice] The current consensus has no exit nodes. Tor can only build internal paths, such as paths to onion services.
Jul 10 19:20:47.000 [notice] Bootstrapped 45% (requesting_descriptors): Asking for relay descriptors
Jul 10 19:20:47.000 [notice] I learned some more directory information, but not enough to build a circuit: We need more microdescriptors: we have 0/6477, and can only build 0% of likely paths. (We have 0% of guards bw, 0% of midpoint bw, and 0% of end bw (no exits in consensus, using mid) = 0% of path bw.)
Jul 10 19:20:47.000 [notice] Bootstrapped 50% (loading_descriptors): Loading relay descriptors
Jul 10 19:20:48.000 [notice] The current consensus contains exit nodes. Tor can build exit and internal paths.
Jul 10 19:20:49.000 [notice] Bootstrapped 56% (loading_descriptors): Loading relay descriptors
Jul 10 19:20:50.000 [notice] Bootstrapped 62% (loading_descriptors): Loading relay descriptors
Jul 10 19:20:50.000 [notice] Bootstrapped 67% (loading_descriptors): Loading relay descriptors
Jul 10 19:20:50.000 [notice] Bootstrapped 75% (enough_dirinfo): Loaded enough directory info to build circuits
Jul 10 19:20:50.000 [notice] Bootstrapped 80% (ap_conn): Connecting to a relay to build circuits
Jul 10 19:20:50.000 [notice] Bootstrapped 85% (ap_conn_done): Connected to a relay to build circuits
Jul 10 19:20:50.000 [notice] Bootstrapped 89% (ap_handshake): Finishing handshake with a relay to build circuits
Jul 10 19:20:50.000 [notice] Bootstrapped 90% (ap_handshake_done): Handshake finished with a relay to build circuits
Jul 10 19:20:50.000 [notice] Bootstrapped 95% (circuit_create): Establishing a Tor circuit
Jul 10 19:20:50.000 [notice] Bootstrapped 100% (done): Done

Upon starting Tor for the first time with our new configuration, an .onion address will be generated automatically. This information will be stored in "/var/lib/tor/hidden_service" (or another directory if specified in the torrc file). First, in a new directory, if you're not a root user, get root permissions.

~$ sudo cd /var/lib/tor/hidden_service
[sudo] password for kali:
root@kali:/home/kali# kali

Then, we can move to the directory in a new terminal window with cd.

root@kali:/home/kali# cd /var/lib/tor/hidden_service

Next, run ls to ensure that both the "hostname" and "private_key" files are in the directory

root@kali:/var/lib/tor/hidden_service# ls

hostname  private_key

Then, we can view our newly generated address by running cat.

root@kali:/var/lib/tor/hidden_service# cat hostname


The string ending in .onion is our new hidden service address! While this one was automatically generated, we'll be able to customize it later to our preference.

We can test that our service is accessible by opening it in Tor Browser. If the address resolves to your server, you've successfully hosted a hidden service!

Step 7: Generate a Custom Onion Address

To customize our onion address, we'll need to generate a new private key to match a custom hostname. Due to the nature of Tor addresses being partially hashes, to create a custom address, we'll need to brute-force the address we want.

The more consecutive characters of a word or phrase we'd like to use, the longer it will take to generate. This time concern is somewhat of an exponential function, as the longer the sequence is, the generation time will become longer in folds, rather than in a linear way.

There are several tools available for this task, Eschalot and Scallion being some of the more popular options. Scallion uses GPU-cracking to generate addresses, while Eschalot works using wordlists. For this tutorial, we'll use Eschalot.

Begin by cloning the Eschalot git repository with the following commands in the terminal.

~$ git clone

Cloning into 'eschalot'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 86 (delta 0), reused 1 (delta 0), pack-reused 82
Receiving objects: 100% (86/86), 513.40 KiB | 2.35 MiB/s, done.
Resolving deltas: 100% (37/37), done.

Next, cd into the Eschalot directory, then run make to install Eschalot.

~$ cd eschalot
~/eschalot$ make

cc -std=c99 -O2 -fPIC -finline-functions -Wall -W -Wunused -pedantic -Wpointer-arith -Wreturn-type -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wcast-qual -Wextra -o eschalot eschalot.c -lpthread -lssl -lcrypto
cc -std=c99 -O2 -fPIC -finline-functions -Wall -W -Wunused -pedantic -Wpointer-arith -Wreturn-type -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wcast-qual -Wextra -o worgen worgen.c

To generate a custom address, we can use a command like the one below. In this command, 4 is the number of CPU cores we wish to use, and null is the prefix, or first characters, of the address we're looking for. The program will continue to generate addresses with this prefix and a variety of suffixes. We can stop the program at any time by pressing Control-C.

~/eschalot$ ./eschalot -vct4 -p null

Verbose, continuous, no digits, 4 threads, prefixes 4-4 characters long.
Thread #1 started.
Thread #2 started.
Thread #3 started.
Thread #4 started.
Running, collecting performance data...
Found a key for null (4) - nullb3pxvxj5rpjd.onion

Once the program has generated an address you like, we can use it for our hidden service.

Step 8: Add the Onion Address to the Service

First, we should stop our Tor service from running. We can switch to the window where sudo tor was run and press Control-C.

After that, we'll want to replace our hidden service private key with the one generated by Eschalot. Move back to the /var/lib/tor/hidden_service/ directory using cd as seen below.

~$ sudo cd /var/lib/tor/hidden_service
[sudo] password for kali:

root@kali:/home/kali# cd /var/lib/tor/hidden_service

Within this directory, we'll want to remove the hostname file, as it's going to be replaced by the hostname generated by our custom private key. We can do this using the rm command in the terminal, as follows.

root@kali:/var/lib/tor/hidden_service# rm hostname

Next, copy the RSA Private Key generated by Eschalot, beginning with "-----BEGIN RSA PRIVATE KEY-----" and ending with "-----END RSA PRIVATE KEY-----." This key can replace our automatically generated private key. We can replace it directly using cat with the following command.

root@kali:/var/lib/tor/hidden_service#  cat > private_key

After running this command, right-click and paste the key into the command line window, then press Control-D to write changes to the file. To ensure that the file has the correct private key, we can use cat again to view the file as follows.

root@kali:/var/lib/tor/hidden_service# cat private_key

After updating the private key, we can start Tor again with sudo tor, and check that a new hostname file has been generated by running ls. If a hostname file is in the folder, we can check that it matches our desired address with the following command.

root@kali:/var/lib/tor/hidden_service# ls

hostname  private_key

root@kali:/var/lib/tor/hidden_service# cat hostname


If the hostname matches our desired choice, we can check in Tor Browser to make sure that it resolves to our site. If the new onion address leads to your site, you've successfully hosted a hidden service and configured a custom address!

Now That You Know Tor Hidden Services

This process can be replicated for almost any standard website or service, and the process executed on a VPS, virtual machine, or even a Raspberry Pi.

A proper Tor service should be hardened and supported by more than just Python's server module, but the possibilities when combined with Nginx or other server technologies are as vast as the internet itself, or perhaps even deeper.

Thanks for reading! If you have any questions, you can ask them here in the comments or on Twitter @tahkion.

Just updated your iPhone? You'll find new features for Podcasts, News, Books, and TV, as well as important security improvements and fresh wallpapers. Find out what's new and changed on your iPhone with the iOS 17.5 update.

Cover image and screenshots by TAKHION/Null Byte


Very nice tutorial thank you. If you can do some services for me with a fee just to create this and host a landing page, message me or mail to pivolga at protonmail dot ch

I used LightTPD as the server wonderfully.

Can we use the hidden service on any other port other than 8080???

It's not starting...?

Problem bootstrapping...

I have a problem in step 7. When i type make and execute. It shows like
-$ make

cc -std=c99 -O2 -fPIC -finline-functions -Wall -W -Wunused -pedantic -Wpointer-arith -Wreturn-type -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wcast-qual -Wextra -o eschalot eschalot.c -lpthread -lssl -lcrypto

eschalot.c:66:10: fatal error: openssl/bn.h: No such file or directory
66 | #include <openssl/bn.h>
| ^~~~~~~~~~~~~~
compilation terminated.
make: ** Makefile:45: eschalot Error 1.

After What should I do?

Share Your Thoughts

  • Hot
  • Latest