Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
107 lines (85 sloc) 3.76 KB
# This launches Tor and starts an Onion service using Twisted and
# txtorcon, and then starts a Web server using the aiohttp library.
# This style of interop between asyncio and Twisted requires twisted
# to use the "asyncioreactor" and for code to convert Futures/Tasks to
# Deferreds (most of which is already in Deferred)
# Thanks to Mark Williams for the inspiration, and this code:
# note: if run in Python2, there are SyntaxErrors before we can tell
# the user nicely
import asyncio
from twisted.internet import asyncioreactor
# get our reactor installed as early as possible, in case other
# imports decide to import a reactor and we get the default
from twisted.internet.task import react
from twisted.internet.defer import ensureDeferred, Deferred
from twisted.internet.endpoints import UNIXClientEndpoint
import txtorcon
from aiohttp import web
except ImportError:
raise Exception(
"You need aiohttp to run this example:\n pip install aiohttp"
def as_future(d):
return d.asFuture(asyncio.get_event_loop())
def as_deferred(f):
return Deferred.fromFuture(asyncio.ensure_future(f))
def get_slash(request):
return web.Response(
text="I am an aiohttp Onion service\n",
def create_aio_application():
app = web.Application()
web.get('/', get_slash)
return app
async def _main(reactor):
if False:
print("launching tor")
tor = await txtorcon.launch(reactor, progress_updates=print)
tor = await txtorcon.connect(
UNIXClientEndpoint(reactor, "/var/run/tor/control"),
print("Connected to tor {}".format(tor.version))
# here, we've just chosen 1234 as the port. We have three other
# options:
# - select a random, unused one ourselves
# - put "ports=[80]" below, and find out which port txtorcon
# selected after
# - use a Unix-domain socket
# we create a Tor onion service on a specific local TCP port
print("Creating onion service")
onion = await tor.create_onion_service(
(80, 1234) # 80 is the 'public' port, 1234 is local
version=2, # FIXME use v3; using old tor for now
# we're now listening on some onion service URL and re-directing
# public port 80 requests to local TCP port 1234.
app = create_aio_application()
runner = web.AppRunner(app)
await as_deferred(runner.setup())
site = web.TCPSite(runner, 'localhost', 1234)
await as_deferred(site.start())
# now we're completely set up
print("Onion site on http://{}".format(onion.hostname))
await Deferred()
def main():
return react(
lambda reactor: ensureDeferred(
if __name__ == '__main__':