Building a Hidden Website with Python and Tor

Tor Python

In this post, I will walk through how you can create and host a simple website using Python and serve it as a Tor hidden service — nothing shady, just pure geeky fun.

Let’s begin by installing Tor. If you’re already familiar with the Tor browser, feel free to proceed. But if you’re new to it, you can learn more about the service here.

The Tor browser includes a Tor binary (tor.exe) that can be used to start a service or install it as a Windows service. To locate it, navigate to the folder where Tor is installed. On my system, it’s located at: D:\Programs\Tor Browser\Browser\TorBrowser\Tor.

While the initial part of the path may vary depending on your installation location, the rest of the directory structure remains consistent.

Since we’re hosting a website using Python, there’s no need to launch the Tor Browser. Instead, we’ll start Tor as a service using the tor.exe binary. Normally, launching the Tor Browser automatically starts this service in the background, but when running it manually, we need a runtime configuration file (torrc). Below is a sample configuration file with minimal settings—just enough to get the site up and running. For security reasons we would like to have the Tor control port to be password protected . You can generate the password using the tor.exe with this command.

tor.exe --hash-password Msft#win123

Copy the output of the above command and save it to the torrc file along with other configurations. Here is the final configuration file.

ControlPort 9151
SOCKSPort 9050
HashedControlPassword 16:EA735EE7099CC752600CFC4A4BD2F0CE737BA55864A78711C7672E699C

The port settings mentioned above might differ on your system. If the service fails to start or your web application can’t connect to it, this is likely the cause.

Open command prompt in administrator mode if you are on Windows. Start the tor service by executing the below command.

tor.exe -f 

TOR Service Start

If you do not want to get into a hassle of running this command for starting the service again and again, then you can install tor as a service. To do that use the tor.exe with --service install arguments and pass the torrc file path as a argument to -f flag.

tor.exe --service install -options -f F:\code\torpy\torrc

On Windows, you can place the torrc file at C:\Users\AppData\Roaming\tor, which is the default location used by tor.exe. Once it’s in place, you can run the command as shown below.

tor.exe --service install

If you wish to delete the installed service, use the sc command available on Windows.

sc delete tor

With the Tor service now running, create a new folder — feel free to name it TorWeb or anything you prefer. Inside this folder, set up a Python virtual environment and install the necessary dependencies to enable communication with the Tor service.

pip install stem flask

Here is the entire Python code.

from stem.control import Controller
from flask import Flask, render_template

if __name__ == "__main__":

    app = Flask("TorWeb")
    port = 5000
    host = "127.0.0.1"
    hidden_svc_dir = "e:/web"

    @app.route('/')
    def index():
        return render_template('index.html')
    
    print('* Getting controller')
    controller = Controller.from_port(address="127.0.0.1", port=9151)
    try:
        controller.authenticate(password="Msft#win123")
        controller.set_options([
            ("HiddenServiceDir", hidden_svc_dir),
            ("HiddenServicePort", "80 %s:%s" % (host, str(port)))
        ])
        svc_name = open(hidden_svc_dir + "/hostname", "r").read().strip()
        print("* Created host: ", svc_name)
    except Exception as e:
        print(e)
    app.run()
  • stem.control: Lets you interact with the Tor process via control port.
  • flask : Python web framework. You can use some other light-weight framework of your choice.
  • render_template: Lets you render HTML templates.
controller = Controller.from_port(address="127.0.0.1", port=9151)

Connects to the Tor control port (usually 9051 or 9151 depending on your setup).

controller.set_options([
    ("HiddenServiceDir", hidden_svc_dir),
    ("HiddenServicePort", "80 127.0.0.1:5000")
])

Hidden Service Directory

HiddenServiceDir is a path to the directory where Tor will store hidden service data like hostname, private_key etc. This code tells Tor to create a hidden service and store its config in E:\web folder. HiddenServicePort forwards incoming traffic on port 80 to flask application at 127.0.0.1:5000.

svc_name = open(hidden_svc_dir + "/hostname", "r").read().strip()
print("* Created host: ", svc_name)

This reads the generated .onion address from the hostname file and prints it.

Just to make my first dark web page cool, I asked ChatGPT to render a cool looking HTML page. Copy this HTML page inside a template folder so it can be used with Flask.

Run the app

TOR Web App Start

For enhanced security and greater control, it’s advisable to use a dedicated web server configured with recommended best practices.

You will not be able to open the Tor browser on your system as the Tor service is already running and the browser will not be able to connect to the instance which is already running. Although, Tor browser can connect to the existing Tor service but this is not typical and is not recommended to use.

I am using a different machine to view my application using a Tor browser.

Note that the loading of the page might be slow as it solely depends on the Tor network connectivity. It can take up to several minutes for the page to load.

TOR Web App Start

The souce code along with the torrc file used above can be found in this repo path.

comments powered by Disqus