~/blog/"How to host your own website on the darkweb"
In my previous post, I explained how to set up a Raspberry Pi on your home network to act as an I2P router, allowing you to browse anonymous sites (and contribute to the network at the same time).
If you’re not familiar with I2P, or how to set up an I2P router. Please checkout my previous post, as this one starts where the other one left off.
I could give you the whole spiel about the importance of censorship resistant systems, freedom of information, decentralisation of the web, etc. But the truth is: I did it because I was bored, and this was fun. So, why not?
You certainly won’t get as much visibility when compared with a website on the clearnet. But you can always have a copy of your personal website on both the clearnet and I2P. However, be aware that speed that you get on I2P is really slow, so keep it light. Who needs anything more than HTML and CSS anyway?
This is the solution that I found to host it. Do let me know if you think it can be improved!
The first step is to make a website. Log into the Raspberry Pi, and create something simple.
cd ~/ echo "<h1>Hello World!</h1>" >> index.html
Now, you need to make it visible to anyone on your home network. For this part, you’ll want to have both docker and docker-compose installed. Also, make sure that you follow the post-installation steps as well, so that you don’t have to run docker with
sudo, and that docker starts when the Raspberry Pi boots up.
To host the website, you’ll want to use a webserver like
nginx . But to make things easier, you can use it inside a docker container.
Start by creating a directory inside your home called
nginx and go into it (you can give it another name, as long as you keep things consistent).
mkdir ~/nginx cd ~/nginx
Then, create a directory to keep the website in:
mkdir website mv ~/index.html website/
Now that’s in place, you want to create a docker container running
nginx, and tell it where to find your website.
You could just use
docker run for this, but docker-compose also allows you to run multi-container applications. One could argue this is a bit overkill, but there is one little feature which I quite like.
Create a new file named
~/nginx, and paste the following inside:
version: '3' services: app: image: 'nginx:latest' restart: always ports: - '80:80' volumes: - ~/nginx/website:/usr/share/nginx/html watchtower: image: containrrr/watchtower restart: always volumes: - /var/run/docker.sock:/var/run/docker.sock
This will tell docker-compose to launch a multi-container application with 2 containers. The first one (
app), will be a webserver with the following characteristics:
80in the host (the Raspberry Pi), to port
80in the container
~/nginx/websitein the Raspberry Pi, to the the default path used by
nginxto read the website from (
That last point is important. It means that whatever you put inside
~/nginx/website/ will be read by the docker container running
nginx, and will be served as your website. Therefore, if you want to update it, you just need to change the files inside
OK that’s pretty obvious, but what’s watchtower?
This is neat little solution that automatically updates
app every time a new version of
nginx:latest is pushed to Docker Hub. In other words, if a newer version is available, watchtower pulls the latest version, shuts-down the currently running container (i.e.
app), and launches a new one running the latest version. Have a look at the documentation for more details.
docker-compose.yml file is saved, all you have to do is launch it:
cd ~/nginx/ docker compose up -d
You can now open a browser from another machine on your network, and give it the internal IP address of the Raspberry Pi.
You should be able to see your website. If this does not work, something went wrong with the webserver. Try to pinpoint the problem before proceeding.
Wait, how do I find this address?
From your Raspberry Pi, you can run the command below to get the address of the interfaces (e.g. if the Raspberry Pi is using the wifi, look at the
inet field under the
If you want to find it from the machine where you’re opening the browser, you can scan your network to find it:
sudo nmap -sn 192.168.1.0/24
I won’t go into detail on how
nmap works, as it’s outside of the scope of this tutorial.
As mentioned in the introduction, at this point, you should have
i2pd configured in the same way as described in my previous post. I’m assuming that’s the case for you.
Now that you can see the site from a different machine on your network, it’s time to make it visible on i2p. For that, you’re going to need to change the
tunnels.conf file. It’s usually on
~/.i2pd/tunnels.conf , but that might not be the case for you.
If you access the i2pd webconsole (
http://127.0.0.1:7070/), you should see a
Data path field on the main page (in my case, it says
/var/lib/i2pd). That’s the directory where you can find the
tunnels.conf file. Open that file (you might need to use
sudo), and add the following to the bottom:
[anon-website] type = http host = 127.0.0.1 port = 80 keys = anon-website.dat
sudo systemctl restart i2pd.service
Open the webconsole, and go to the tunnels page (
http://127.0.0.1:7070/?page=i2p_tunnels), you should see a subheading saying
anon-website followed by a long string with
*.b32.i2p:80 at the end. That’s the address to the website (you should be able to open it in the browser after a while).
Congratulations! You are now hosting your own website on the darkweb.
But that long string is rather ugly, wouldn’t it be nice to have a nice human-readable address?
To do that, go into the webconsole > I2P tunnels > anon-website. On this page, click on “Address registration line” and fill out which domain you’d like. If the generation is successful, it should take you to another page, asking to add a small description. Submit it, and wait a bit until the new address works (it could be a couple of days, so don’t stand there refreshing in despair).
You shouldn’t need anything else. But if at any point you need to generate an authentication string, you’ll need to use i2pd-tools, in particular readdr:
./regaddr anon-website.dat <your-domain>.i2p > auth_string.txt cat auth_string.txt
anon-website.dat file can be found in the same directory as the
tunnels.conf file. Follow the instructions on the project’s repo on how to compile i2pd-tools.
After a few days, you should be able to see the website being announced on
And that’s it! Enjoy your own piece of virtual real estate on the darkweb.