Home How to host a tor hidden service
Post
Cancel

How to host a tor hidden service

You can access this very same blog as a hidden service at http://simonja4fdp3lxdjeis5qjuugqe3wtbstlr2w7gmzsrnhhkpctmbgead.onion

Hosting a website as a hidden service via the tor network is easy. With my setup you can host arbitrary webservices on the tor network just like you would do on the clearnet.

I use docker compose with one service to run tor and nginx proxy manager to easily manage multiple websites.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
services:
  tor:
    image: goldy/tor-hidden-service
    restart: unless-stopped
    environment:
        NPM_TOR_SERVICE_HOSTS: 80:npm:80
        NPM_TOR_SERVICE_VERSION: '3'
        #NPM_TOR_SERVICE_KEY:

  npm:
    image: jc21/nginx-proxy-manager
    restart: unless-stopped
      - 81:81 # access admin locally
    volumes:
      - ./data:/data

  blog:
    image: ghcr.io/simonhaas/blog:main
    restart: unless-stopped

  nginx:
    image: nginx
    restart: unless-stopped
    configs:
      - source: nginx
        target: /usr/share/nginx/html/index.html

configs:
  nginx:
    content: |
      <html>
          <head>
              <title>simonhaas</title>
          </head>
          <body>
              <a href="blog">Blog</a>
          </body>
      </html>

The first time tor runs it generates a .onion address for you.

1
docker compose exec -ti tor cat /var/lib/tor/hidden_service/npm/hostname

There will be two more files:

  • hs_ed25519_public_key
  • hs_ed25519_secret_key

Noticed how the tor service is stateless? It does not use any volumes. To prevent generating a new address everytime the container starts you can export the secret key and add it as the environment variable NPM_TOR_SERVICE_KEY.

1
docker compose exec -ti tor cat /var/lib/tor/hidden_service/npm/hs_ed25519_secret_key | base64

Now you can add Proxy Hosts inside nginx proxy manager just like you would on the clearnet.

  • domain name: your .onion address
  • scheme: http
  • forward host: nginx
  • port: 80

For my blog I use the same proxy host but have added a Custom location

  • location: /blog
  • scheme: http
  • forward host: blog
  • port: 80

vanity addresses

Vanity addresses can be generated with mkp224o

1
docker run --rm -it -v ./keys:/keys ghcr.io/cathugger/mkp224o:master -d /keys simon

This will generate .onion address starting with simon and save them in the ./keys folder. To use a generated address for your hidden service, just convert a secret key to base64 and add it as the respective environment variable to your tor service.

onion-location

If you are visiting this blog on its clearnet address via the tor browser you might have noticed a banner advertising the .onion version.

This post is licensed under CC BY 4.0 by the author.