Skip to content

SSH Over an Onion Service

Created September 12, 2026 • Last updated September 12, 2026 • 3 min read • 260 views

Joshua

HackIndex Creator

Running SSH over an onion service takes your management port off the public internet entirely. Nothing listens on a routable address, so a scan finds no SSH to attack. This pairs with the anonymous build from the hardened onion service guide. You reach the box only through Tor.

Reach SSH over an onion service

The order matters. Bind sshd to loopback, add a HiddenServicePort for port 22, and confirm you can log in over Tor. Only then close the public port. Follow it in that sequence, or a mistake in the Tor config locks you out of a box with no public SSH.

Bind sshd to loopback

Tell sshd to listen only on loopback. Recent Debian ships an Include line for /etc/ssh/sshd_config.d/ in the main config, so a drop-in file is enough. Create it, then restart the service.

ListenAddress 127.0.0.1
ListenAddress ::1
user@host ~ $ sudo systemctl restart ssh
user@host ~ $ sudo ss -tulpn | grep :22
tcp   LISTEN 0      128    127.0.0.1:22   0.0.0.0:*    users:(("sshd",pid=744,fd=3))
tcp   LISTEN 0      128    [::1]:22       [::]:*       users:(("sshd",pid=744,fd=4))

Add the SSH onion

Give SSH its own service so it has a separate address from the website. Append the block to /etc/tor/torrc and restart Tor. Read the new hostname from the service directory.

HiddenServiceDir /var/lib/tor/ssh/
HiddenServicePort 22 127.0.0.1:22
user@host ~ $ sudo systemctl restart tor
user@host ~ $ sudo cat /var/lib/tor/ssh/hostname
3cb6rnxga23uh2m4qkolmk4wpgw45qmddn4ufhl74jdaimn5mqs7eyid.onion

Restrict this onion to your own key with client authorization, so the SSH service is invisible to anyone else. The setup is the same as the admin onion in running multiple onion services on one host.

Connect from the client

The simplest way wraps ssh with torsocks, which sends the connection through the local Tor SOCKS port. Replace $USER with your login and $ONION_ADDRESS with the SSH onion. Keep sshd on key authentication only, since the onion layer does not replace a login credential.

user@host ~ $ torsocks ssh $USER@$ONION_ADDRESS

For a permanent setup, add a host entry to ~/.ssh/config with a ProxyCommand that speaks SOCKS5 to Tor. ssh does not expand variables in this file, so replace $ONION_ADDRESS and $USER with the real values. The default netcat on Debian is the OpenBSD build, which supports the flags below. If you prefer ncat, install it with apt install ncat, then use ncat --proxy 127.0.0.1:9050 --proxy-type socks5 %h %p.

Host myonion
    HostName $ONION_ADDRESS
    User $USER
    ProxyCommand nc -X 5 -x 127.0.0.1:9050 %h %p
user@host ~ $ ssh myonion

Close the public port last

Only remove the public SSH rule after the onion login works. Capture the host key fingerprint on the server first, so you can compare it against the prompt on the client and trust the first onion connection.

user@host ~ $ sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:uAlsALpkNzr/SacdJDc7Siewkrf7SDzkdZr42rtF/K8 root@host (ED25519)

Now remove the tcp dport 22 accept line from the input chain in the firewall and reapply the ruleset. A scan of the public IP then shows port 22 as filtered, and the box exposes nothing on a public address.

user@host ~ $ sudo nft -f /etc/nftables.conf

This closes the last public port from the hardened onion service build. Give the SSH onion a readable prefix with mkp224o if you like.

References