Set Up an Onion Service on Debian
Table of Contents
Install and Configure tor #
In this article, I’ll show you how to configure Tor with Apache, and Unix Socket on Debian 11 - Bullseye. Each setup will be tested locally. Some months back, I installed tor on Ubuntu Focal. You can use it as a guide to install Tor. Just replace the distribution with the one you’re using. You can find a list of repositories for Debian and Ubuntu here.
Verify Tor Client #
I’ll be using python to test the connection. The required dependencies are requests
, and pysocks
. Install both by running:
pip3 install requests
pip3 install requests[socks]
The script:
import requests as req
proxies = {
"http": "socks5://127.0.0.1:9050",
"https": "socks5://127.0.0.1:9050"
}
ip = req.get('https://ident.me').text
print(f"My IP: {ip}")
torip = req.get("https://ident.me", proxies=proxies).text
print(f"Tor IP: {torip}")
Run it:
root@debian:~# python3 checktorip.py
My IP: 102.112.126.171
Tor IP: 199.195.250.77
Apache #
First, edit /etc/tor/torrc
, look for:
## This section is just for location-hidden services ###
Below, you’ll see HiddenServiceDir
, and HiddenServicePort
. Uncomment both lines. Here’s mine:
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 127.0.0.1:80
-
HiddenServiceDir: Will contain information about your onion service. It could be any directory that the Tor user(debian-tor user on debian) have read/write permission. I’ll stick with the default. Once you restart Tor, the directory will be populated with the required information.
-
HiddenServicePort: The above configuration specifies
80 127.0.0.1:80
. Which says, clients accessing your server on port 80 will be redirected to127.0.0.1:80
(on the localhost side).
Restart Tor, and you should see a list of files, in your HiddenServiceDir
:
root@debian:/var/lib/tor/hidden_service# ls
authorized_clients hostname hs_ed25519_public_key hs_ed25519_secret_key
The one we’re interested in, is hostname
. This file contains your onion service name or domain name:
root@debian:/var/lib/tor/hidden_service# cat hostname
bkg4yzo752uounfarllk4z7ieav3ylv4kd6vstzi2xofu5sm55ov7tyd.onion
I’ll edit the default Apache Webpage configuration, and change the ServerName
to the onion domain:
<VirtualHost *:80>
ServerName bkg4yzo752uounfarllk4z7ieav3ylv4kd6vstzi2xofu5sm55ov7tyd.onion
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
The content of /var/www/html/index.html
:
Tor service is up and running.
Add your server’s IP and onion domain to /etc/hosts
, and browse to http://domain.onion
. To browse on the command-line, run the following script:
import requests
session = requests.session()
session.proxies["http"] = "socks5h://localhost:9050"
#session.proxies["https"] = "socks5h://localhost:9050"
req = session.get("http://bkg4yzo752uounfarllk4z7ieav3ylv4kd6vstzi2xofu5sm55ov7tyd.onion")
print(req.text)
or this one:
import requests
import sys
url = sys.argv[1]
session = requests.session()
session.proxies["http"] = "socks5h://localhost:9050"
session.proxies["https"] = "socks5h://localhost:9050"
req = session.get(url)
print("")
print(req.text)
I’m using socks5h
here, because the server is being resolved by the socks server itself:
root@debian:~# python3 checktorip.py http://bkg4yzo752uounfarllk4z7ieav3ylv4kd6vstzi2xofu5sm55ov7tyd.onion/
Tor Service is up and running.
Multiple Onion Service #
To have multiple onion sites, just add another HiddenServiceDir
, and HiddedServicePort
in /etc/tor/torrc
:
### blog
HiddenServiceDir /var/lib/tor/hidden_service_blog/
HiddenServicePort 80 127.0.0.1:8787
Then restart Tor. Don’t create the directory by yourself, or else you’d have to manually change the owner and give it the required permissions. Once done, add an additional VirtualHost section for apache(am using the same file):
<VirtualHost *:80>
ServerName bkg4yzo752uounfarllk4z7ieav3ylv4kd6vstzi2xofu5sm55ov7tyd.onion
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:8787>
ServerName 5yl4tewyiftvxsgan5mtuxyqtzprl6uwqlwrymknqjkzpsvqg66dqqqd.onion
DocumentRoot /var/www/blog
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Add Listen 8787
in /etc/apache2/ports.conf
:
Listen 80
Listen 8787
Follow the same steps as above, by restarting both Apache and Tor, edit your hosts file, and browse to the domain:
root@debian:~# python3 checktorip.py http://5yl4tewyiftvxsgan5mtuxyqtzprl6uwqlwrymknqjkzpsvqg66dqqqd.onion
Blog is up and running as an onion service.
Unix Socket on Nginx #
According to the documentation of Tor, a unix socket will avoid leaking an onion service to a local network(e.g wireshark/tcpdump). Apache doesn’t support unix socket. You’ll need Nginx. I’m starting from scratch.
My torrc configuration and hostname:
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 unix:/var/run/main-onion-service.sock
Instead of an internal port, specify a unix socket. View the hostname:
qlahjdyjbilvohq5s3ryxcg75qhfjjhbh5ghwxxejhnellpvfvisuoyd.onion
Specify the same socket in your nginx configuration like so:
root@debian:~# cat /etc/nginx/sites-available/tor_services
server {
listen unix:/var/run/main-onion-service.sock;
server_name qlahjdyjbilvohq5s3ryxcg75qhfjjhbh5ghwxxejhnellpvfvisuoyd.onion;
index index.html;
root /var/www/tor/main;
}
Create the root
, and index.html
. Make a symlink in /etc/nginx/site-enabled
:
ln -s /etc/nginx/sites-available/tor_services /etc/nginx/sites-enabled/
Restart both Tor, and Nginx, and browse to the domain:
root@debian:~# python3 checktorip.py http://qlahjdyjbilvohq5s3ryxcg75qhfjjhbh5ghwxxejhnellpvfvisuoyd.onion
Main Tor service is up and running.
Multiple Onion Services Listening on Unix Sockets #
You follow the same steps as above. Add both a HiddenServiceDir and HiddenServicePort:
# Main
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 unix:/var/run/main-onion-service.sock
# Blog
HiddenServiceDir /var/lib/tor/hidden_service_blog/
HiddenServicePort 80 unix:/var/run/blog-onion-service.sock
Restart Tor, and view the domain name:
root@debian:~# cat /var/lib/tor/hidden_service_blog/hostname
ysbwxbknrx5xvmx3slxli42b4ze34pgpjrsdlmjywljskvczxobi6xad.onion
Modify your nginx configuration or create a new one. No symlink is require this time:
server {
listen unix:/var/run/main-onion-service.sock;
server_name qlahjdyjbilvohq5s3ryxcg75qhfjjhbh5ghwxxejhnellpvfvisuoyd.onion;
index index.html;
root /var/www/tor/main;
}
server {
listen unix:/var/run/blog-onion-service.sock;
server_name ysbwxbknrx5xvmx3slxli42b4ze34pgpjrsdlmjywljskvczxobi6xad.onion;
index index.html;
root /var/www/tor/blog;
}
Restart both services, and verify it:
root@debian:~# python3 checktorip.py http://ysbwxbknrx5xvmx3slxli42b4ze34pgpjrsdlmjywljskvczxobi6xad.onion
Blog is up and running as an onion service.
Sometimes Nginx won’t restart because the unix sockets in specified in HiddenServicePort
are still present in /var/run/. A lot of users are facing this issue. You will have to remove them manually and then restart the web server.
“Want to keep Christ in Christmas? Feed the hungry, clothe the naked, forgive the guilty, welcome the unwanted, care for the ill, love your enemies, and do unto others as you would have done unto you.”
― Steve Maraboli