Create Tor Onion Service with Nginx

Last modified: 2024-02-13


1. Setup Tor

1. Install Tor

# on Debian/Ubuntu
sudo apt install tor

# on Fedora
sudo dnf install tor

Then enable and start tor service.

sudo systemctl enable tor
sudo systemctl start tor

# Check status
sudo systemctl status tor

2. Configure Tor Onion Service

Edit /etc/tor/torrc for adding the following lines (remove # at the target lines and modify values):

HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 unix:/var/run/tor/hidden_service.sock

3. Restart Tor Service

sudo systemctl restart tor

4. Check Your Onion Domain

Your onion domain is stored at /var/lib/tor/hidden_service/hostname.

cat /var/lib/tor/hidden_service/hostname

2. Setup Nginx

1. Install Nginx

# on Debian/Ubuntu
sudo apt install nginx

# on Fedora
sudo dnf install nginx

2. Create Website Contents

Here we create a directory /var/www/onion and put the contents here.

mkdir -p /var/www/onion
touch /var/www/onion/index.html

Then write contents for index.html such as below:

<!DOCTYPE html>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Hidden Site</title>
		<h1>Welcome to Hidden Site</h1>

After that change permission for allow nginx to read files under /var/www/onion.

chown -R nginx:nginx /var/www/onion

Remember to update permission of /var/www/onion with above command every time you add new files/directories under /var/www/onion.

3. Configure Nginx

Create /etc/nginx/conf.d/onion.conf and add the following directive. Replace <your-onion-address>.onion with your Onion domain stored at /var/lib/tor/hidden_service/hostname.

server {
    listen unix:/var/run/tor/hidden_service.sock;
    server_name <your-onion-address>.onion;
    access_log /var/log/nginx/hidden_service.log;
    index index.html;
    root /var/www/onion;

    location / {
        root /var/www/onion;
        index index.html index.htm;

4. Start Nginx Server

Before starting the Nginx, if the SELinux is activated, temporarily disable the SELinux to give Nginx permission to process UNIX sockets (/var/run/tor/hidden_service.sock).

# 0: Set `Permissive` mode temporarily
setenforce 0

# Check status (the `Permissive` mode is expected)

Then start Nginx.

sudo systemctl enable nginx
sudo systemctl start nginx

# Check status
sudo systemctl status nginx

3. Access To You Onion Service

Using Tor Browser, you can access to the onion service by entering your .onion domain. See the domain in /var/lib/tor/hidden_service/hostname.

To monitor access log, use tail command.

tail -f /var/log/nginx/hidden_service.log

4. Backup HiddenServiceDir

To keep your onion service available for a long time, make a backup copy of the /var/lib/tor/hidden_service directory somewhere.

When starting Hidden Service using this directory, just simply copy it to /var/lib/tor/ as below:

cp -r /path/to/hidden_service /var/lib/tor/

Then modify /etc/tor/torrc and start tor service.

5. (Optional) Get Vanity Address

If you want to use a custom Onion domain with arbitrary prefix such as exampleabcdef....onion, you can generate it using mkp224o.

1. Install Dependencies

# on Debian/Ubuntu
apt install gcc libc6-dev libsodium-dev make autoconf

# on Fedora
sudo dnf install -y gcc
sudo dnf install -y glibc-static
sudo dnf install -y libsodium-devel
sudo dnf install -y make
sudo dnf install -y autoconf

2. Build the mkp224o Project

git clone
cd mkp224o

3. Generate Vanity Address

# -d: Specify output directory
# -n: The number of domains to generate
./mkp224o -d domains -n 5 mysite

# Result examples:

4. Copy the Key Files

After generating, the key files are saved under domains/mysite...onion directory.

ls domains/mysiteabcdef....onion

hostname hs_ed25519_public_key hs_ed25519_secret_key

Choose one domain and copy these files to /var/lib/tor/hidden_service/ .

cd domains/mysiteabcdef....onion
cp domains/mysiteabcdef/* /var/lib/tor/hidden_service/

5. Update the Nginx Config

Replace the original onion domain to our vanity address in /etc/nginx/conf.d/onion.conf

server {
	server_name mysiteabcdef....onion;

6. Restart Tor and Nginx

Now restart Tor and Nginx to apply the domain.

sudo systemctl restart tor
sudo systemctl restart nginx

Access to mysite...onion in Tor Browser.

6. (Optional) Make Your Onion Service To Be More Secure

If you want your onion service to be more secure, add additional configurations.

Hide Nginx Version

Usually the Nginx version is displayed in the HTTP response header such as below:

Server: nginx/1.24.0

You may want to hide the version. To hide it, add the server_tokens off in the /etc/nginx/nginx.conf as follow:

http {

	server_tokens off;



This hide the Nginx version from the Server header such as below:

Server: nginx

Rate Limiting Requests


By rate limiting requests per second (or millisecond), it may prevent DDoS attacks.
Add limit_req_zone and limit_req directives to /etc/nginx/conf.d/onion.conf.

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

Server {

	location / {
		limit_req zone=mylimit burst=20 nodelay;