Many websites today feature a responsive design. Users get to see sleek animations, and content loads dynamically. Long gone are the days of HTML frames that required reloading of parts of or of entire web sites. These features require modern technology and components, often loading templates from public resources. When thinking about this in the context of secure, hidden Tor websites, these two just don’t work well together at a first glance. Read on to learn how to set up a Hidden Tor Website with ReactJS and Node.js!
Just because technologies like Tor increase safety and privacy, they shouldn’t reduce convenience. In this article I will show you how to set up your own hidden Tor service. I will then show you how to run a ReactJS + Node.js powered website on it without compromising its privacy. This way you get the best of both worlds: Anonymity and privacy, and modern technology.
If you’re looking to share your website outside of Tor but still want to stay anonymous, check here!
Hidden Tor Services Explained
Tor (or The Onion Router) is a network of relay nodes that obfuscates the route of traffic passing through it. Essentially, it is a mesh of hosts with defined entry and exit nodes.
Your traffic is routed through a Circuit of hosts inside the Tor network. Initially, a path is planned through the network by the Tor proxy software on your computer. This software has knowledge of the Tor network layout. It then assembles layers of route segments for each step. The data is then transmitted through the network:
The origin host has knowledge of the encryption keys of each node on the planned route. The nodes can then decrypt just the information required to send the data to the next node. The resulting path is called the Circuit. It is typically used for one connection context, e.g. a website visit, before it refreshes. It refreshes periodically too, though (the default is every 10 minutes).
Advertising Services on the Tor Network
Through the above Tor network, you can advertise web services. Much like the HTTP domain addresses you know (e.g., https://example.com/) Tor offers a way to reference services advertised, using .onion addresses. These are only accessible via a web browser that understands the Tor network protocol, such as the Tor browser. Tor services can serve regular TCP services on any valid port number, without revealing their real IP address.
If you serve an HTTP service on port 80, you offer a standard HTTP setup which the Tor browser can display. In the next sections, we will set up such a service. You can do this in your home computer or a VPS (for example DigitalOcean). Let’s assume a standard Ubuntu environment that you have sudo access to. In the next chapters, we will:
- Install the Tor service on your Ubuntu system via command line
- Configure a hidden service
- Set up a very basic Node.js + ReactJS website
- Offer this website on your hidden service
- Anonymously browse to that website via the Tor browser
- Bonus: We’re going to create a vanity address for your hidden services!
This will cover the full workflow of offering an anonymous website on Tor. There are many more things one can do on the Tor network. This guide should get you familiar with all the basics and get you started.
Create a Hidden Tor Website Service
Creating a hidden Tor service is not very complicated. We start by setting up the Tor backend service. In Ubuntu, install the tor package:
sudo apt install tor
This will install and set up the basic Tor service that connects your computer to the network. Now to configure a hidden service, you need to edit /etc/tor/torrc. Inside this file, under the location-hidden services section, add these two lines:
HiddenServiceDir /var/lib/tor/my_hidden_service
HiddenServicePort 80 127.0.0.1:3000
This configures Tor to offer your service at port 80 on your onion service and forward it to port 3000 on your local machine (127.0.0.1). This will be the Node.js port we use for serving later on. The source and target port may differ if required for your service. You can define multiple HiddenServicePort lines after the HiddenServiceDir line here. This allows you to forward multiple ports for the same service. Now restart the Tor service:
sudo /etc/init.d/tor restart
After restarting, you can acquire the .onion address assigned to your service with this command:
sudo cat /var/lib/tor/my_hidden_service/hostname
The resulting address will look something like this:
rfk43kvbkmqq6e4pdofm35xlya7lbayvc7l5gu3kqvw5skndojsvfoad.onion
This address contains the public address of a cryptographic key pair. Only the host that holds the private key to this address can interact with connections directed towards the public address. The public and private key belonging to this address are in the same folder and are normally called hs_ed25519_public_key and hs_ed25519_secret_key. Do not share your private (secret) key, since anyone in posession of that key can interfere with connections to your onion address.
Your Tor service is now being served to the Tor network, great! Assuming you don’t have a service running on port 80 on your local machine, there is no-one answering to connection requests to your onion address yet though. In the next step, we will set up the hidden Tor website content with ReactJS and Node.js.
Setting up a Basic Node.js Web Server
Setting up Node.js and ReactJS is straight forward. Ubuntu does offer Node.js in their apt repository, but it may not be the latest version. We will install it from NodeSource instead. First, update your package manager and install curl:
sudo apt update
sudo apt install curl
After that completes, you can run the NodeSource setup (Node.js 20.x LTS is the latest stable version when this article was written; check NodeSource for the latest version info):
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt-get install -y nodejs
You can verify the correct installation and available versions of the core node and npm tools like this:
node -v
npm -v
Creating a ReactJS Project
In order to set up a hidden Tor website with ReactJS, we need to install it. ReactJS has neat setup scripts available for working with Node.js. To create a ReactJS project in Node, first install the create-react-app tools:
sudo npm install -g create-react-app
Now change into a directory that should hold your ReactJS website project. create-react-app will create another subdirectory in the next step under that:
create-react-app my-hidden-react-website
Now change into that new my-hidden-react-website folder that was just created. create-react-app generated various setup files, which we will mostly leave alone for now. Only edit src/App.js, which loosely acts as the entry point for your content. Paste this content into it:
import React from 'react';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Welcome to My Hidden React Website</h1>
<p>I'm very happy to see you here!</p>
</header>
</div>
);
}
export default App;
You can now serve this ReactJS app via npm on the default port 3000 (which we mapped our onion service to):
npm start
That’s it. Overall, as long as the process in the console is alive, your website is served. With a regular browser, you can now go to http://localhost:3000/ and observe the app locally:
When you make changes to the project files, the website will be updated dynamically, which is a neat development feature. Tor now also serves your website through your onion address on port 80. Dynamic website updates upon file changes don’t work on the Tor browser.
Browsing to the Hidden Service via the Tor Browser
Now that the service is configured and npm is running, you can try accessing it via the Tor network. For this purpose, download the Tor browser and navigate to your onion address. At the example above, this would be http://rfk43kvbkmqq6e4pdofm35xlya7lbayvc7l5gu3kqvw5skndojsvfoad.onion/, but it will be different for your service:
Congratulations, you just started serving content privately and anonymously on the Tor network! The browser cannot determine which server the website comes from. Keep in mind that you stay private as long as you don’t give away details about yourself on that website. Keep your software up to date and follow software engineering best practices to stay safe.
Create a Vanity Address for Tor Website Service
The above address rfk43kvbkmqq6e4pdofm35xlya7lbayvc7l5gu3kqvw5skndojsvfoad.onion seems very clunky. Its length and variety in characters adds to Tor’s security though. When setting up a hidden Tor website with modern ReactJS, you might want an address that is a little more memorable and recognizable. For this purpose, you can generate vanity addresses. Vanity addresses are addresses that contain recognizable strings. It’s a bit like the vanity license plates you get in the US, but for onion addresses it would be more like this:
heymomvbkmqq6e4pdofm35xlya7lbayvc7l5gu3kqvw5skndojsvfoad.onion
The address starts with the string “heymom“. This is highly improbable to show up randomly when generating a regular onion address through the Tor service. That’s where vanity address generators come into play. We will be using mkp224o (served on GitHub) for this purpose. Download their latest release (1.7.0 at the time of writing, available for Windows, mac OS, and Linux). The tool accepts filters for what addresses you want, and then tries to generate private keys that result in public addresses matching your filters.
We want the simplest option, start the address with “heymom“:
./mkp224o heymom
For me it took less than 20 seconds for the first address to show up:
filters:
heymom
in total, 1 filter
using 8 threads
heymomdbuwy2fhaqkuaz4tzmgr2ojiqjj4itkmf5ya3mgrvxnjvdthqd.onion
The longer or more complex your filter is, the longer it will take. The Tor project has a nice description of Vanity Addresses, which you should check out.
The mkp224o tool will create one directory per found matching address. That directory will contain three files: hostname, hs_ed25519_secret_key, and hs_ed25519_public_key. Copy these files into your hidden service’s directory (as specified in /etc/tor/torrc) and restart the tor service. Your service will now be available through the new address.
Conclusion
We discussed how to set up a hidden Tor website with ReactJS and Node.js. You learned the basics of what Tor is, how it works, and how to set up your own hidden service on the Tor network. After that, the now configured Node.js + ReactJS website is served on the Tor network. You browsed to your website using the Tor browser, and learned how to create vanity addresses for your service. Even though Tor anonymizes your traffic, you can add another layer of privacy by connecting to the Tor network via VPN. If sharing over Tor does not reach the right audience for you, consider using an anonymous clearnet hoster!
I hope you found this article useful and insightful. There is much more to learn and know about The Onion Router network, so be sure to read up on the linked pages. If you have thoughts on the above or would like to comment on your own experiences, feel free to comment below and get the conversation started!