Every website you have ever built rests on a stack of other people’s permission. A registry leases you the name. A registrar can switch it off. A certificate authority vouches for you. A resolver has to answer honestly, and a port has to sit open on a public address where anyone can find it, fingerprint it and hit it. Each of those is a party that can be leaned on, and a surface that can be attacked.
An onion service removes all of them. There is no registrar, because the address is derived from a key you generated. There is no DNS, because nothing resolves the name. There is no certificate authority, because the address is the public key and the connection authenticates itself against it. And there is no inbound port at all — your server dials out to meet its visitors, so it can sit behind a firewall that drops everything and still be reachable from anywhere on earth.
The setup takes about ten minutes and three lines of configuration. What takes care is the rest of the machine, because the web server behind Tor has no idea it is supposed to be hidden and will cheerfully announce its own hostname, its own IP and its own clearweb twin to anyone who asks the right question. This guide does the ten minutes, then does the part that actually decides whether it worked.
What an onion service takes out of the stack
Start with what is actually different, because it is more than a strange-looking hostname. An ordinary site depends on a chain of external parties, and an onion service simply does not have that chain.
- No registrar and no registry. A v3 onion address is the base32 encoding of an ed25519 public key, plus a checksum and a version byte — fifty-six characters, generated on your own machine in a fraction of a second. Nobody sold it to you, so nobody can take it back, and there is no renewal date. That is the exact opposite of the risk model in our guide to registering a domain privately.
- No DNS. Nothing resolves a .onion name. The client asks the Tor network for a signed descriptor published under that key, so there is no resolver to poison, no zone to leak and no nameserver to take down.
- No certificate authority. The address is the public key, so the client verifies the service against the name it typed. This is what “self-authenticating” means: there is no third party vouching for identity, because identity and address are the same object.
- No inbound port. The service opens outbound circuits to a handful of introduction points and waits there. Your firewall can drop every inbound packet and the site still works. Nothing is listening on a public address, so there is nothing to scan, nothing to fingerprint and nothing to flood directly.
One historical note that still causes confusion: the old sixteen-character addresses are gone. Support for version 2 onion services was removed from Tor in October 2021, the addresses no longer work anywhere, and anything you find describing them is out of date. Everything below is v3, which is the only kind there is.
And be clear about what none of this removes. There is still a physical machine in a datacentre, a host that knows it exists, a bill somebody paid, and an application that can be broken into. Onion services move the address layer out of reach. They do not move the server.
Relay, bridge, exit, onion service: four different jobs
People arrive at Tor wanting to do one of four quite different things, and the risk profiles are not remotely comparable. It is worth knowing which one you are signing up for.
- A middle relay passes encrypted traffic between other relays. It carries other people’s data, but never touches the open internet on their behalf, so it attracts no complaints.
- A bridge is an unlisted entry point for people whose access to Tor is blocked. Same traffic profile as a middle relay, with the address kept out of the public directory.
- An exit relay is where other people’s traffic leaves Tor and reaches the ordinary internet, under your IP address. This is the one that generates abuse mail and legal correspondence, and it needs deliberate handling — our Tor relay guide covers it properly.
- An onion service publishes. It carries no traffic but its own, never contacts the clearweb on anybody’s behalf, and therefore produces no abuse reports against your IP at all. There is no exit, so there is nothing to exit.
That last point is worth sitting with, because it is routinely misunderstood. Running an onion service is operationally the quietest thing you can do on the Tor network. Your server makes outbound connections that look like ordinary Tor client traffic; it never appears as the source of a connection to anyone else’s server; and the thing most people worry about — someone else’s behaviour landing on your IP — is structurally impossible.
You also do not need to run a relay in order to run an onion service, and the two are better kept apart. A relay wants bandwidth, a public ORPort and a published ContactInfo. A service wants none of those. If you want to do both, do them on two servers.
Tor is almost never the thing that leaks
Here is the part the official documentation is thin on, and the part that actually determines whether the exercise was worth doing. Tor, configured as below, is extremely unlikely to be the thing that gives your server away. The software behind it is, because that software was written on the assumption that a web server wants to be found.
These are the channels, in roughly the order they catch people:
- The same content on the public IP. If your web server also listens on
0.0.0.0, anyone who scans the internet sees the identical page on both an IP address and an onion address. Whole-internet scanners index every open port continuously and their results are searchable by body hash and by favicon hash. One query links the two. This is the single most common way an onion service is unmasked, and it is a one-line configuration mistake. - Server banners and default pages. A stock
nginxorapache2install answers unknown hostnames with a default page, prints its version in theServerheader, and often reveals the machine’s real hostname in error output. Every one of those is a correlation handle. - Absolute URLs. Redirects, canonical tags, sitemaps, RSS feeds, Open Graph tags and password-reset emails all love to emit a fully-qualified clearweb URL. One of them inside the onion version of a page is enough.
- Outbound requests the application makes. Analytics, web fonts, CDN assets, avatar services, map tiles, webhooks and update checks all originate from the server’s real IP, and several of them tell a third party which page was being rendered at that moment. A self-hosted site with a font loaded from someone else’s domain has an audit trail it did not intend.
- Mail. Anything the box sends stamps its real IP into the
Receivedheaders. If the service needs to send mail, that is a design problem to solve deliberately — start from our mail server guide, and assume by default that it should send nothing at all. - Reused keys and fingerprints. The same SSH host key answering on both the public IP and an onion address links them permanently. So does the same TLS certificate, the same favicon, the same analytics identifier, or the same distinctive error page across two projects.
- Certificate Transparency. If the same box ever serves a clearweb domain over HTTPS, the certificate for that domain is written into public append-only logs forever. That names the machine, not the onion, but it names the machine.
The common shape of all of these is the same: Tor hid the address, and something else on the server published it. Step eight below is a checklist for finding them before somebody else does.
Decide first: is the location of the server a secret?
Before you install anything, answer one question, because everything downstream depends on it: is the physical location of this server a secret you are trying to keep?
There are three honest answers and they lead to genuinely different builds.
- Yes, the location is the point. Then this box does exactly one job. No clearweb site, no public DNS record pointing at its IP, no mail, no other service listening anywhere. You pay for it in a way that does not attach your name — our Monero walkthrough covers the mechanics and no-KYC accounts mean there is nothing to hand over beyond a delivery address. You keep the full three-hop configuration. Every shortcut below that trades anonymity for speed is closed to you, and that is fine, because you are not optimising for speed.
- No, the server is already public. You run an ordinary site and you want an onion address as well — for readers behind censorship, for people who would rather not resolve your domain, or because you would like to offer it. Nobody is hiding anything, so you can use a single onion service, cut the circuit from six hops to three, and advertise the address from the clearweb site with an
Onion-Locationheader. This is a reachability feature, and it is a completely legitimate reason to be here. - Somewhere in between. This is where most people actually are, and it is the dangerous one, because “somewhat hidden” is not a property a server can have. Pick a side. If the location genuinely matters, build it as if it matters. If it does not, stop paying the latency cost for an anonymity property you are not maintaining.
Write the answer down before you continue. Almost every mistake in this guide’s subject matter comes from building for the first case and operating as if it were the second.
Step-by-step
- Pick the server, and decide what else lives on it
An onion service is cheap to run. Tor itself uses very little CPU when it is not relaying, and the workload is whatever your site would have cost anyway, so size for the application rather than for Tor. A static site or a small self-hosted app is comfortable on 1 vCPU and 2 GB; give it 2 vCPU and 4 GB if a database or a language runtime is involved. On our ladder that is Cub (1 vCPU / 2 GB / 40 GB) at $5/mo or Scout (2 vCPU / 4 GB / 70 GB) at $9/mo, both all-NVMe with unlimited traffic at 1 Gbps.
The decision that matters is not the tier. It is the one from the section above: if the location of this machine is meant to be private, it does one job and only one. No other site on it, no DNS record anywhere pointing at its address, no mail, nothing else listening. The temptation to put “just one more thing” on a box you are already paying for is exactly how the correlation happens.
Pay for it in a way that matches. Accounts here need an email address for delivery and nothing else, and checkout settles on chain — the Monero walkthrough and buying without a card cover it from zero. Start from a minimal Debian or Ubuntu image; every command below assumes Debian 12 or newer as root.
- Install Tor from the Tor Project repository
Use the Tor Project’s own repository rather than the distribution package. The distro build lags, and two of the settings in this guide — the introduction-point rate limiter and the proof-of-work defence — only exist in recent releases.
apt update && apt install -y apt-transport-https curl gpg lsb-release curl -s https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc \ | gpg --dearmor | tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/null echo "deb [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] \ https://deb.torproject.org/torproject.org $(lsb_release -cs) main" \ > /etc/apt/sources.list.d/tor.list apt update && apt install -y tor deb.torproject.org-keyring tor --versionThe
deb.torproject.org-keyringpackage keeps the signing key current, so this is a one-time job rather than something that breaks in a year. Anything from 0.4.8 upwards has every option used below.Do not configure anything yet. Tor is running as a client at this point, which is all you need for the verification step later.
- Put the web server on loopback and nowhere else
This is the step that most often gets skipped and most often ruins the exercise. The web server must be reachable from the machine itself and from nowhere else. Install nginx, then write a virtual host that binds to loopback only:
# /etc/nginx/sites-available/onion server { listen 127.0.0.1:8080; server_name _; server_tokens off; root /var/www/onion; index index.html; access_log off; }server_tokens offremoves the version from theServerheader and from error pages. Turning the access log off is a deliberate choice rather than laziness: every request through Tor arrives from127.0.0.1, so the log records nothing useful about visitors and a great deal that is worth not keeping.Then add a catch-all that answers on the public address and refuses to say anything at all. nginx’s
444closes the connection without a response, which is the quietest possible answer to a scanner:# /etc/nginx/sites-available/deny-direct server { listen 80 default_server; listen [::]:80 default_server; return 444; }Enable both, remove the stock default site, and confirm what is actually listening:
rm -f /etc/nginx/sites-enabled/default ln -s /etc/nginx/sites-available/onion /etc/nginx/sites-enabled/ ln -s /etc/nginx/sites-available/deny-direct /etc/nginx/sites-enabled/ mkdir -p /var/www/onion && echo 'it works' > /var/www/onion/index.html nginx -t && systemctl reload nginx ss -ltnpRead the
ssoutput carefully. The only entry bound to0.0.0.0or::should be the one you meant to keep — SSH, and the444catch-all if you chose to run it. Everything else belongs on127.0.0.1. If the application you are hosting ships its own listener, check it too; plenty of frameworks default to all interfaces and say nothing about it. - Declare the onion service in torrc
Three lines create the service. Add them to
/etc/tor/torrc, along with the two defences that are much easier to enable now than during an incident:# /etc/tor/torrc HiddenServiceDir /var/lib/tor/onion-site/ HiddenServicePort 80 127.0.0.1:8080 # rate-limit floods at the introduction points HiddenServiceEnableIntroDoSDefense 1 # make each connection attempt cost the client a little work HiddenServicePoWDefensesEnabled 1Read the port line carefully, because the two numbers do different jobs. The first is the port visitors will use in the onion URL — keep it at
80so nobody has to type one. The second is where Tor forwards the request locally, which is the loopback listener from the previous step. They do not have to match and it is often clearer when they do not.If you want to remove even the loopback TCP socket, Tor can speak to a unix socket instead, which means nothing at all is listening on a port. Point the service at a socket and configure nginx to listen on it:
HiddenServicePort 80 unix:/run/onion-site.sockDo not create the directory yourself and do not create the key files. Tor generates them on first start with the ownership and permissions it expects, and a directory you made by hand with the wrong mode is a common reason for the service to silently fail to come up.
- Start Tor and read your address
Restart Tor, watch it come up, and collect your address:
systemctl restart tor@default journalctl -u tor@default -n 20 --no-pager cat /var/lib/tor/onion-site/hostnameThat file contains fifty-six base32 characters followed by
.onion, and that is your address — live from the moment Tor logs that it has published its descriptor, usually within a minute. There is nothing to register, nothing to propagate and nothing to wait for.Look at what else Tor created, because two of these files matter more than anything else on the machine:
ls -l /var/lib/tor/onion-site/You should see
hostname,hs_ed25519_public_keyandhs_ed25519_secret_key, in a directory owned bydebian-torwith mode0700. The secret key is not a credential for the address; it is the address. Copy it to another machine and that machine is your service. Delete it without a backup and the address can never be recreated by anyone, including you. Step nine deals with this properly — do not skip it.If the hostname file does not appear, the answer is almost always in the log: a directory Tor cannot own, a permissions mode it refuses to accept, or a typo in the port line.
- Reach it, and prove it is your machine
The obvious test is to open the address in Tor Browser, and you should. The useful test is from the command line, where you can see headers:
apt install -y torsocks torsocks curl -sI http://<your-address>.onion/ torsocks curl -s http://<your-address>.onion/ | headProve it is really your server. An address you typed by hand is fifty-six characters of base32, and a single transposed character can land on somebody else’s service. Write a random token on the server, then fetch that exact path through Tor and compare:
head -c 16 /dev/urandom | base32 | tr -d '=' > /var/www/onion/token.txt cat /var/www/onion/token.txt torsocks curl -s http://<your-address>.onion/token.txtTwo identical strings mean you reached your own machine. Remove the file afterwards.
Know what this test does and does not show. Running it from the server itself proves the service is published and reachable, which is exactly what you wanted to know. It proves nothing about anonymity, since both ends are the same box. For that, test from a completely different network — and if Tor itself is blocked where you are, a bridge is the answer, which our guide to getting past DPI blocking covers.
- Close the ports the service does not need
Now collect the reward. An onion service needs zero inbound ports, so the firewall can be as blunt as it gets: drop everything inbound, allow established connections and whatever you need to administer the box. Our Debian hardening guide has a complete nftables ruleset; apply it, then verify that the only inbound exception left is SSH.
Then consider removing that exception too. SSH is the last public port on an otherwise invisible machine, and it does not have to be. Give it its own onion address:
# /etc/tor/torrc HiddenServiceDir /var/lib/tor/onion-ssh/ HiddenServicePort 22 127.0.0.1:22Restart Tor, read the new hostname, and connect through your local Tor SOCKS port. This goes in
~/.ssh/configon your laptop:Host onionbox HostName <ssh-address>.onion User root ProxyCommand nc -X 5 -x 127.0.0.1:9050 %h %pOnce that works, set
ListenAddress 127.0.0.1insshd_configand drop the inbound rule. The machine now has nothing whatsoever listening on a public address.Two cautions. Test the onion route thoroughly before you close the door behind you, and keep your provider’s console access available so a mistake costs a reboot rather than the server — ours is in the control panel. And do not let the same SSH host key answer on both the public IP and the onion address at any point, because the fingerprint is identical in both places and that is precisely the link you are trying not to create.
- Hunt the leaks before you publish the address
Work through this before you tell anybody the address. It takes five minutes and it is the difference between a hidden service and a service that is merely inconvenient to find.
Nothing unexpected is listening. Every line should be loopback, or a port you consciously decided to leave open:
ss -ltnpThe public IP serves nothing. Ask it directly, both ways, from somewhere else. Empty replies or connection refusals are what you want; your content is what you do not:
curl -sI --max-time 5 http://203.0.113.10/ curl -skI --max-time 5 https://203.0.113.10/No clearweb URL is inside what you serve. Pull the page through Tor and list every absolute link in it. Anything pointing at a domain you control, a CDN, a font host or an analytics endpoint is a leak or a correlation handle:
torsocks curl -s http://<your-address>.onion/ \ | grep -Eo 'https?://[^ "]+' | sort -uHeaders and error pages say nothing. Check a real page and a deliberately missing one, and look for version strings, hostnames, file paths and stack traces:
torsocks curl -sI http://<your-address>.onion/ torsocks curl -s http://<your-address>.onion/nothing-here | head -20The application is not phoning home. This one is not a command, it is a read-through. Disable analytics. Self-host fonts, icons and scripts. Turn off avatar and preview fetching. Remove update checks that call out on a schedule. Point any absolute-URL setting — site URL, canonical host, mail sender domain — at the onion address instead of a clearweb one.
Housekeeping. Set the machine to UTC with
timedatectl set-timezone UTCso timestamps reveal nothing about where it or you might be. Make sure/server-status,/.git, backup files and editor swap files are not reachable. And if this box also serves a clearweb site, go back and read the third section again, because the checklist above cannot save a build whose posture was never decided. - Back up the key, because the key is the address
Say it once more, because it is the failure people do not recover from: the secret key is the address. There is no registrar to appeal to, no recovery email, no support ticket. Lose those bytes and the name is gone from the internet permanently.
Stop Tor so the files are consistent, archive the whole service directory, and encrypt it before it leaves the machine:
systemctl stop tor@default tar -C /var/lib/tor -czf - onion-site \ | gpg -c --cipher-algo AES256 -o onion-site-$(date +%F).tar.gz.gpg systemctl start tor@defaultMove the encrypted archive somewhere that is not this server — the whole point is that it survives the machine. Our encrypted backups guide covers doing this on a schedule to an append-only target in another country, which is the right home for it.
Restoring is the same thing backwards, and the permissions are not optional: Tor refuses to start if the mode is wrong, which is irritating in the moment and exactly the behaviour you want.
gpg -d onion-site-2026-09-14.tar.gz.gpg | tar -C /var/lib/tor -xzf - chown -R debian-tor:debian-tor /var/lib/tor/onion-site chmod 700 /var/lib/tor/onion-site chmod 600 /var/lib/tor/onion-site/hs_ed25519_secret_key systemctl restart tor@default cat /var/lib/tor/onion-site/hostnameThat last line is the test. Same address on a different machine means the backup is real. Rehearse it once, now, on a throwaway server — an untested backup of an irreplaceable key is a story about a key you used to have. The same discipline applies here as in our migration guide: the restore is the thing you are actually buying.
- Publish the address so people can trust it
You now have fifty-six characters that nobody can read, remember, or verify by eye. That is a real usability problem and it is also a security one, because a visitor cannot tell your address from a near-identical fake. Distribution is part of the build, not an afterthought.
Publish it where the reader already trusts you. If you have a clearweb site, put the address in the footer and serve the
Onion-Locationheader from the section below. Otherwise use whatever channel your audience already associates with you — an existing account, a signed message, a printed card. The address inherits exactly as much credibility as the place you published it.Sign it if the stakes justify it. A signature over the address, verifiable against a key people already have, is the only way someone can confirm they have the right one without trusting the channel that carried it.
Do not rely on directories or search engines. Onion indexes exist, they are incomplete, and several have a history of listing phishing copies of popular addresses alongside the real ones. Being findable there is a bonus; it is not a distribution plan.
A vanity prefix helps a little. The tool
mkp224ogrinds keys until one produces an address starting with a string you choose, which makes it recognisable at a glance:apt install -y gcc libc6-dev libsodium-dev make autoconf git clone https://github.com/cathugger/mkp224o && cd mkp224o ./autogen.sh && ./configure && make ./mkp224o -d ./keys -n 1 wolfThe cost grows exponentially with length: a few characters take seconds, seven or eight take real time on real hardware, and anything beyond that is not happening. Be honest about what it buys — an attacker can grind the same prefix and trust a matching first few characters is exactly the habit that makes people click the wrong link. Treat it as branding, not authentication. The generated directory drops straight in as a
HiddenServiceDir: fix the ownership and modes as in the previous step, and generate it somewhere you trust, because whoever runs the tool holds the key.
Running the same site on the clearweb and as an onion
If the server’s location is not a secret, running both is straightforward and genuinely useful — it is how large news organisations, Debian and several search engines offer their sites. Two mechanisms and one trade to understand.
Advertise it with Onion-Location. A single header on the clearweb site makes Tor Browser show a “.onion available” button in the address bar, and offer to switch. The header is only honoured on pages served over HTTPS, and the value must be a valid onion URL:
add_header Onion-Location "http://<your-address>.onion$request_uri" always;There is an HTML equivalent for hosts where you cannot set headers, which has the same HTTPS requirement:
<meta http-equiv="onion-location" content="http://<your-address>.onion">Also put the address somewhere a human can read it, in the footer or on an about page. The header only reaches people already using Tor Browser; the footer reaches everyone else.
Consider a single onion service. A normal onion connection is six hops — three from the client, three from the service — and the service’s three exist purely to hide where it is. If that is not a secret, you can drop them. The latency improvement is large and immediately noticeable. The configuration is blunt on purpose:
# /etc/tor/torrc — these are INSTANCE-WIDE, not per service
HiddenServiceNonAnonymousMode 1
HiddenServiceSingleHopMode 1
SOCKSPort 0Both options are required together, the SOCKS port must be disabled, and they apply to every onion service on that Tor instance — there is no per-service opt-out. Tor will refuse to start if you set one without the others, which is the software doing you a favour. If a single instance hosts one service whose location is public and another whose location is not, run two instances, or better, two servers.
And accept the trade. Publishing both addresses declares that the same operator runs both, and serving identical content from both makes them trivially linkable regardless. That is the deal, and for a public site it costs nothing. Keep the hygiene anyway: no absolute clearweb URLs inside the onion version, cookies scoped per host so a session does not travel between them, and a content security policy that does not pull assets across.
Client authorization: when the address is the credential
By default, anyone who knows your address can reach the service. Client authorization changes that at the network layer rather than the application layer, and the difference matters more than it sounds.
With authorization enabled, the descriptor your service publishes is encrypted to a set of client keys. A visitor without one of those keys cannot decrypt it, cannot learn the introduction points, and therefore cannot connect at all — they do not reach a login page, they do not get a refusal, they get nothing. The service is not unlisted; it is invisible.
Generate an x25519 keypair per client. Every tool here is already on a Debian box:
openssl genpkey -algorithm x25519 -out alice.prv.pem
# private key — goes to the client, never to the server
grep -v 'PRIVATE KEY' alice.prv.pem | base64 -d | tail -c 32 | base32 | tr -d '='
# public key — goes on the server
openssl pkey -in alice.prv.pem -pubout | grep -v 'PUBLIC KEY' \
| base64 -d | tail -c 32 | base32 | tr -d '='On the server, drop the public key into an authorized_clients directory inside the service directory. The filename is arbitrary as long as it ends in .auth, which makes revocation a matter of deleting one file:
mkdir -p /var/lib/tor/onion-site/authorized_clients
echo "descriptor:x25519:<ALICE-PUBLIC-KEY>" \
> /var/lib/tor/onion-site/authorized_clients/alice.auth
chown -R debian-tor:debian-tor /var/lib/tor/onion-site
systemctl reload tor@defaultOn the client, the private key goes in the directory named by ClientOnionAuthDir, in a file ending .auth_private, with the address repeated inside it. Tor Browser has its own directory for these under its data folder, and will prompt for a key if it hits a service that needs one:
# /var/lib/tor/onion-auth/mysite.auth_private
<address-without-the-.onion>:descriptor:x25519:<ALICE-PRIVATE-KEY>This is the right tool for a staging site, an admin panel, a private file drop, or a self-hosted Nextcloud that only you use — anything where the honest answer to “who should be able to see that this exists?” is “nobody but us”. The cost is real and it is administrative: you have to get keys to people over a channel you trust, and you have to remember to remove them afterwards.
Keeping it alive: DoS, clocks and uptime
Onion services fail in their own particular ways, and none of them look like an ordinary outage. Four things are worth setting up before you need them.
Denial of service is the real operational problem. Because there is no IP address to filter, the usual defences do not apply, and a determined flood of introduction requests is cheap to send. Tor has two answers, both set per service in torrc: HiddenServiceEnableIntroDoSDefense 1 rate-limits requests at the introduction points, and HiddenServicePoWDefensesEnabled 1 makes clients solve a small proof-of-work puzzle that gets harder under load, so legitimate visitors wait a moment while a flood becomes expensive. Turn both on from the start; the cost when nothing is attacking you is negligible.
Keep the clock right. Descriptors are published and looked up against time periods derived from a shared network value. A server whose clock has drifted badly publishes to the wrong place and becomes unreachable while appearing perfectly healthy in its own logs. Make sure an NTP client is running, keep the machine on UTC, and check it when a service mysteriously stops resolving.
Monitoring has to go through Tor. No commercial uptime service can probe a .onion address, which means the usual answer is unavailable to you. Run the check yourself from a second machine that is not the one hosting the service — a cron job doing torsocks curl -s --max-time 60 against a known URL, comparing the output to a known string, is enough and costs nothing.
Plan for more than one instance if uptime matters. OnionBalance lets several backend servers share a single onion address: a front-end instance holds the key that owns the address and publishes a descriptor pointing at the introduction points of the backends, so you get load distribution and failover without the address ever changing. It is more moving parts than most sites need, but it is the supported answer, and it is worth knowing that it exists before you have painted yourself into a single box.
One last operational habit: restarting Tor takes the service offline for a few seconds while it republishes, and a reinstall that wipes /var/lib/tor takes it offline forever. Treat that directory the way you would treat a private key, because it is one.
The honest limits
An onion address removes the registrar, the resolver, the certificate authority and the open port. It does not remove anything else, and being precise about the remainder is what separates a useful tool from a false sense of safety.
It does not fix the application. A vulnerable web app behind an onion service is a vulnerable web app; the first thing many attackers do after getting code execution is make an outbound request that reveals the server’s real address. Give the box the ten-minute pass in our Debian hardening guide, keep it patched, and treat it as exposed even though nothing is listening.
It does not hide the server from the people who run it. We know a server exists, when it was deployed, and what its IP address is, because we are the ones who allocated it. That is true of every host, everywhere, and anyone telling you otherwise is selling something. What we can say precisely is what we do with it, which is set out in our honest account of what a crypto-paid VPS hides.
It does not defeat a patient, well-resourced adversary on its own. Traffic volume and timing are visible at the edges of the network, and a service that goes quiet whenever a particular person is asleep is telling you something. Nor does it help if the content identifies you: the same writing style, the same PGP key, the same avatar or the same forum handle as a public identity closes the loop no matter how good the transport is.
On our own side, so you can calibrate: onion services are welcome on every tier and need nothing special from us, because they open no ports and generate no abuse traffic. We run no-KYC accounts that need only an address to deliver credentials to. We treat routine copyright correspondence as an operational matter rather than an automatic takedown, we act on valid court orders in the jurisdiction the server sits in, and the hard floor is absolute and applies here exactly as everywhere else: no CSAM, no terrorism content, no exceptions. Read the acceptable-use policy and how we handle abuse reports before you build something you would be unhappy to move. Our Tor-friendly VPS page has the tier guidance.
Frequently asked questions
Do I need a domain name to run a .onion site?
No, and that is most of the point. The address is generated from a key on your own server in a fraction of a second, so there is no registrar to buy it from, no renewal to miss, no WHOIS record and nobody with the power to suspend it. What you give up is legibility: a .onion address is fifty-six characters nobody can memorise or type, it only opens in Tor Browser or a Tor-aware client, and search engines mostly will not index it. Many people run both for that reason — a domain for reach and an onion address for continuity. Our guide to registering a domain privately covers the other half of that pair.
Do I have to open a port or configure port forwarding?
Neither. This is the structural difference between an onion service and ordinary hosting: the service makes outbound connections to introduction points inside the Tor network and waits for clients there, so no inbound connection ever arrives at your server. A firewall that drops every inbound packet has no effect on it. In practice that means you can end up with a machine that has nothing at all listening on a public address — including SSH, if you give that its own onion address as in step seven — which is a much smaller attack surface than any conventionally hosted site can achieve.
Do I need an HTTPS certificate for a .onion address?
Almost certainly not. The onion address is itself the public key of the service, so the connection is already encrypted and authenticated end-to-end against the name the visitor typed — there is nothing a certificate authority could add to that, and Tor Browser treats .onion origins as secure contexts, so features that require HTTPS work without one. A small number of CAs will issue a certificate for a .onion name, which is occasionally useful if you need an organisation name shown in the address bar or you are mixing onion and clearweb assets. For an ordinary site, plain HTTP on a loopback listener is the correct and normal configuration.
Why is my onion service slow, and can I make it faster?
A standard onion connection runs through six relays, three chosen by the client and three by your service, and that round trip is most of what you feel. Three things help. If the location of your server is not a secret, a single onion service drops your three hops to zero-of-your-own and roughly halves the latency — see the section on running both above, and note the setting is instance-wide and explicitly gives up server location privacy. Second, make the site itself light: no external assets, no fonts or scripts fetched from other hosts, aggressive caching, because every extra request pays the full circuit cost again. Third, check that you are not being flooded; enabling HiddenServicePoWDefensesEnabled keeps a service usable under introduction-point abuse that would otherwise look exactly like poor performance.
Can I run the same site on the clearweb and as an onion service?
Yes, and for a public project it is a good idea — it gives readers behind censorship a route in and does not require them to resolve your domain. Be clear about what it is, though: serving identical content from both makes them trivially linkable, so this is a reachability feature rather than a hiding one. Advertise the address with an Onion-Location header on the HTTPS site and put it in the footer for everyone else. If the location of the server is genuinely meant to be private, do not do this at all; run the onion service on a machine that does nothing else, has no DNS record pointing at it and sends no mail.
What happens if I lose the onion key?
The address is gone, permanently, for everyone. There is no recovery process because there is no authority — the name is derived mathematically from the key in /var/lib/tor/<service>/hs_ed25519_secret_key, and without those bytes nobody can ever republish under it. This is the trade for having no registrar who can take it from you. Back the directory up encrypted and off the server, restore it once on a throwaway machine to confirm the address comes back, and remember that anyone who obtains that file becomes your service, so it deserves the same handling as any other private key.
Can I host an onion service on VPSCrypto?
Yes, on every tier, and it needs nothing special from us: an onion service opens no inbound ports and generates no abuse traffic against your IP, which makes it one of the quietest things you can run. Accounts are no-KYC and need only an address to deliver credentials to, checkout settles on chain with Monero first-class, and a server is live in about a minute. The abuse floor applies exactly as it does everywhere else — no CSAM, no terrorism content, no exceptions — and we act on valid court orders in the server’s jurisdiction. See our Tor-friendly VPS page for tier guidance and the acceptable-use policy for the rest.

