TorRunner is a Python package designed to facilitate the deployment of Tor hidden services. It simplifies the process by allowing you to set up and run a hidden service that listens on a specified port. This package automates the installation and configuration of the Tor software, removing the need for manual setup and making it easier to get started.
This project uses the Vanguards implementation of mikeperry-tor at mikeperry-tor/vanguards under MIT license found here, the socks implementation of Anorov at Anorov/PySocks under BSD License found here and the win_inet_pton implementation of hickeroar at hickeroar/win_inet_pton under Public Domain License found here.
- Vanguards
- Auto Bridge Updates
- Multi Threads
- Tor version check & auto update
- Proxy mode [only for urllib implemented]
❌ (not feasible) Tor preinstalled
Make sure you have the latest version of Python and Pip installed.
- Create an virtual env with
python3 -m venv .venv
andsource .venv/bin/activate
- Install TorRunner with pip
pip install tor-runner
or manually viagit clone https://github.com/tn3w/TorRunner
or download the zip here. - If you installed it manually, run
pip install .
in the downloaded and extracted folder. - [Optional] Install stem with
pip install stem
if you want to use Vanguards.
Quick command (Linux / macOS):
python -m venv .venv; source .venv/bin/activate; pip install tor-runner
Quick command (Windows):
python -m venv .venv; .venv/Scripts/activate.bat; pip install tor-runner
TorRunner has the ability to route your urllib requests through Tor.
Example:
import time
import urllib.request
import urllib.error
from tor_runner import TorProxy
proxy = TorProxy()
proxy.start()
print("SocksPort running on 127.0.0.1:" + str(proxy.socks_port))
with proxy.urllib():
start_time = time.time()
url = "https://check.torproject.org/?lang=en_US"
try:
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
if "Congratulations" in content:
print("Connected to Tor!")
elif "Sorry" in content:
print("Not connected to Tor")
except urllib.error.URLError as e:
print(f"Error connecting to {url}: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
first_byte_time = time.time() - start_time
print(f"Time to first byte: {first_byte_time:.4f} seconds")
tor_runner --help
Output:
usage: tor_runner [-h] [-p PORT] [-l [LISTENER ...]] [-t THREADS] [-d [HIDDEN_SERVICE_DIRS ...]] [-b [BRIDGES ...]] [-s SOCKS_PORT] [-v [VANGUARDS]] [--bridge-quantity BRIDGE_QUANTITY]
[--default-bridge-type DEFAULT_BRIDGE_TYPE] [--direct] [--delete] [--quiet]
Run as a Tor hidden service, allowing configuration of listeners, hidden service directories, and bridges.
options:
-h, --help show this help message and exit
-p PORT, --port PORT HTTP port for the hidden service to listen on.
-l [LISTENER ...], --listener [LISTENER ...]
List of listeners in the format 'tor_port,listen_port'.
-t THREADS, --threads THREADS
How many times Tor should start. (default: 1)
-d [HIDDEN_SERVICE_DIRS ...], --hidden-service-dirs [HIDDEN_SERVICE_DIRS ...]
Directories for storing hidden service keys and hostname files.
-b [BRIDGES ...], --bridges [BRIDGES ...]
List of bridges to use for connecting to the Tor network.
-s SOCKS_PORT, --socks-port SOCKS_PORT
SOCKS port for Tor connections.
-v [VANGUARDS], --vanguards [VANGUARDS]
Enables Vanguards with an optional thread count to protect against guard discovery and related traffic analysis attacks.
--bridge-quantity BRIDGE_QUANTITY
Number of bridges to use for connecting to the Tor network.
--default-bridge-type DEFAULT_BRIDGE_TYPE
Default bridge type to use when connecting to Tor.
--direct Executes your command directly via Tor.
--delete Delete all data associated with tor_runner.
--quiet Run the script in quiet mode with no output.
from tor_runner import TorRunner
# Uses 11 default obfs4 bridges to connect
runner = TorRunner(
hs_dirs = ["/path/to/hs"], bridges = [],
default_bridge_type = "obfs4", bridge_quantity = 11
)
if __name__ == '__main__':
# Forwards 5000 -> 80 and 22 -> 22
runner.run([(5000, 80), (22, 22)], socks_port = 9050, quite = False, wait = True)
from flask import Flask
from tor_runner import TorRunner
app = Flask(__name__)
# Uses 11 default obfs4 bridges to connect
runner = TorRunner(default_bridge_type = "obfs4", bridge_quantity = 11)
@app.route('/')
def index():
"""
Route accessible via the Tor network
"""
return 'Hello, Anonymous!🖐️'
if __name__ == '__main__':
runner.flask_run(app, host = '127.0.0.1', port = 9000)
from sanic import Sanic, HTTPResponse
from sanic.response import text
from tor_runner import TorRunner
app = Sanic(__name__)
# Uses 11 default obfs4 bridges to connect
runner = TorRunner(default_bridge_type = "obfs4", bridge_quantity = 11)
@app.route('/')
async def index(request) -> HTTPResponse:
"""
Route accessible via the Tor network
"""
return text('Hello, Anonymous!🖐️')
if __name__ == '__main__':
runner.sanic_run(app, host = '127.0.0.1', port = 8000, workers = 16)