Setup Tor Hidden Service Onion v3 with nginx on VPS
A properly configured hidden service using onion v3 addressing and a hardened nginx reverse proxy is the foundation for any serious dark web presence. Onion v3 uses ed25519 cryptography for 56-character addresses that provide vastly superior security compared to the deprecated v2 format. This guide walks through every step from VPS provisioning to a production-ready hidden service with proper security hardening, correct network isolation, and key backup procedures that ensure continuity without compromising anonymity.
Need this done for your project?
We implement, you ship. Async, documented, done in days.
Provisioning and Initial Hardening
Start with a clean Debian 12 VPS provisioned with anonymous payment and pseudonymous email. Apply immediate hardening before any service configuration: disable password SSH login, set up key-based authentication only, update all packages, and enable automatic security updates. These baseline hardening steps prevent compromise before the hidden service configuration is complete.
apt update && apt upgrade -y apt install -y unattended-upgrades apt-listchanges dpkg-reconfigure --priority=low unattended-upgrades sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config systemctl restart ssh
Install Tor from the official Tor Project repository rather than Debian default mirrors to ensure you have current security patches:
echo "deb [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org bookworm main" > /etc/apt/sources.list.d/tor.list wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor > /usr/share/keyrings/tor-archive-keyring.gpg apt update && apt install -y tor deb.torproject.org-keyring nginx
Configuring Tor for Hidden Service Operation
Add the hidden service configuration to /etc/tor/torrc. The service listens on port 80 internally and maps to port 80 of the nginx web server running on localhost:
HiddenServiceDir /var/lib/tor/hidden_service/ HiddenServicePort 80 127.0.0.1:8080 HiddenServiceVersion 3
Set correct permissions on the hidden service directory before starting tor: mkdir -p /var/lib/tor/hidden_service && chown debian-tor:debian-tor /var/lib/tor/hidden_service && chmod 700 /var/lib/tor/hidden_service
Start tor and wait for key generation: systemctl start tor. After 30 to 60 seconds, the onion address appears in /var/lib/tor/hidden_service/hostname. Record this address carefully. It is generated from the ed25519 private key in the same directory. The key file hs_ed25519_secret_key is your most critical asset - losing it means losing the onion address permanently.
nginx Configuration for Hidden Services
nginx serves content on the localhost interface only, forwarding through the Tor hidden service. This configuration binds nginx to 127.0.0.1 so it is never accessible directly from the public internet:
server {
listen 127.0.0.1:8080;
server_name _;
# Hide server details
server_tokens off;
# Prevent information leakage
add_header X-Robots-Tag "noindex, nofollow" always;
# Disable ETags (fingerprinting risk)
etag off;
root /var/www/onion;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# Remove Last-Modified header
add_header Last-Modified "" always;
}
The X-Robots-Tag header prevents search engine indexing if a clearnet mirror accidentally links to the onion address. Disabling ETags prevents fingerprinting through consistent file hash responses. The Last-Modified header removal prevents timing-based correlation of file update patterns.
Blocking Clearnet Leakage
The most dangerous operational security mistake for hidden service operators is clearnet leakage - when the application behind the hidden service makes direct connections to the public internet, revealing the server IP. Block all outbound clearnet traffic with iptables:
iptables -P OUTPUT DROP iptables -A OUTPUT -o lo -j ACCEPT iptables -A OUTPUT -m owner --uid-owner debian-tor -j ACCEPT iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ip6tables -P OUTPUT DROP ip6tables -A OUTPUT -o lo -j ACCEPT ip6tables -A OUTPUT -m owner --uid-owner debian-tor -j ACCEPT
These rules allow the tor process to connect outward (to build circuits and contact directory authorities) while blocking all other outbound connections. The nginx process, running as www-data, cannot make outbound connections at all. Any plugin, CMS update check, or external resource request from the web application is silently dropped, preventing inadvertent server IP disclosure through application-level clearnet requests.
Save rules with iptables-save > /etc/iptables/rules.v4 and install iptables-persistent to apply on boot: apt install -y iptables-persistent
Key Backup and Recovery Planning
The hidden service private key (hs_ed25519_secret_key) is the sole source of the onion address. Back it up securely: copy the entire /var/lib/tor/hidden_service/ directory to an encrypted offline medium. Use full disk encryption on the backup medium and store in a location physically separate from the server.
For distributed operations with multiple front nodes under one onion address (OnionBalance), the descriptor key is different from the individual front node keys. Back up all keys: the master descriptor key and each front node key separately. OnionBalance configuration files should also be backed up to enable reconstruction of the entire setup if needed.
Test the recovery procedure before deploying any production content. Provision a second test VPS, copy the key files, start tor, and verify that the same onion address is generated. This confirms the backup is complete and that you understand the restoration process before you need to use it under pressure.
Related Services
Why Anubiz Host
Ready to get started?
Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.