This is a practical Tor setup guide for Debian-based servers.
It covers four common modes:
- onion service (hidden service)
- relay (non-exit)
- obfs4 bridge
- exit relay (high-risk)
Base install
sudo apt update
sudo apt install -y apt-transport-https curl gnupg
curl -fsSL https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc \
| gpg --dearmor \
| sudo tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/tor.list
sudo apt update
sudo apt install -y tor deb.torproject.org-keyring
sudo systemctl enable --now tor
Open firewall ports only for the mode you run.
Onion service (website)
Minimal torrc block:
HiddenServiceDir /var/lib/tor/example-site/
HiddenServicePort 80 127.0.0.1:8080
Reload Tor:
sudo systemctl restart tor
Read generated hostname:
sudo cat /var/lib/tor/example-site/hostname
If using nginx locally on 127.0.0.1:8080, keep the server bound to localhost:
server {
listen 127.0.0.1:8080;
server_name _;
root /var/www/example;
index index.html;
}
Optional on clearnet vhost:
add_header Onion-Location http://YOUR_ONION_ADDRESS.onion$request_uri;
Relay (non-exit)
Use this if you want to contribute bandwidth without exit traffic liability.
Router port forward + firewall: open your ORPort (example 9001).
Note: 9001 is commonly associated with Tor relays. Use another reachable port if you want lower fingerprinting by basic scans.
Add to torrc:
Nickname myRelay
ContactInfo you@example.org
ORPort 9001
ExitRelay 0
SocksPort 0
Restart and check:
sudo systemctl restart tor
sudo journalctl -u tor -u tor@default -f
obfs4 bridge
Install transport:
sudo apt install -y obfs4proxy
Add to torrc:
Nickname myBridge
ContactInfo you@example.org
ORPort 9001
BridgeRelay 1
ServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy
ServerTransportListenAddr obfs4 0.0.0.0:9020
ExtORPort auto
SocksPort 0
Open/forward ports 9001 and 9020, then restart Tor:
sudo systemctl restart tor
Get bridge line:
sudo cat /var/lib/tor/pt_state/obfs4_bridgeline.txt
Use that line in Tor Browser manual bridge settings.
Exit relay
Exit relays require clear policy decisions and provider approval.
Do not run an exit relay on a home line unless you are prepared for complaints/abuse handling.
Minimum config delta from non-exit relay:
ExitRelay 1
In practice you should also define explicit ExitPolicy, abuse contact, DNS resolver setup, and incident handling before enabling exits.
Optional: vanity onion addresses
If you want a custom prefix, use mkp224o and place generated keys into your HiddenServiceDir.
sudo apt install -y gcc libc6-dev libsodium-dev make autoconf
git clone https://github.com/cathugger/mkp224o
cd mkp224o
./autogen.sh && ./configure && make -j"$(nproc)"
./mkp224o -n 1 prefix
Copy generated keys, fix ownership, restart Tor:
sudo cp *.onion/* /var/lib/tor/example-site/
sudo chown -R debian-tor:debian-tor /var/lib/tor/example-site
sudo chmod 700 /var/lib/tor/example-site
sudo systemctl restart tor
Quick checks
sudo systemctl status tor
sudo ss -tulpen | grep -E '9001|9020|9050|9051'
sudo journalctl -u tor --since "10 minutes ago"
Keep one role per host where possible (especially for exits).