# SSH Over an Onion Service

> Reach SSH over an onion service: bind sshd to loopback, add a HiddenServicePort, and connect with torsocks or an ssh ProxyCommand.

- **URL:** https://hackindex.io/blog/ssh-over-onion
- **Authors:** [Joshua](https://hackindex.io/authors/joshua.md)
- **Published:** 2026-09-12
- **Updated:** 2026-09-12

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](https://hackindex.io/blog/hardened-onion-service-ubuntu) 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
```

```bash
sudo systemctl restart ssh
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
```

```bash
sudo systemctl restart tor
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](https://hackindex.io/blog/multiple-onion-services).

## 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.

```bash
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
```

```bash
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.

> [!WARNING]
> Keep an out-of-band way back in before you drop the public SSH rule. If Tor fails to start or the key is wrong, an onion-only sshd locks you out. A serial or provider console covers that case.

```bash
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](https://hackindex.io/blog/hardened-onion-service-ubuntu) 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.

```bash
sudo nft -f /etc/nftables.conf
```

This closes the last public port from the [hardened onion service](https://hackindex.io/blog/hardened-onion-service-ubuntu) build. Give the SSH onion a readable prefix with [mkp224o](https://hackindex.io/blog/vanity-onion-address-mkp224o) if you like.

## References

- [Tor onion service setup](https://community.torproject.org/onion-services/setup/) - Adding a HiddenServicePort for a service such as sshd.
- [torsocks](https://gitweb.torproject.org/torsocks.git/) - Wrapper that routes a program through the Tor SOCKS port.
