# https://tunnels.io/use-cases/ssh

[Home](https://tunnels.io/) / [Use cases](https://tunnels.io/use-cases) / SSH

Use case

# SSH into a machine that has no public IP.

A server behind NAT, a Raspberry Pi at home, a build box on a corporate LAN. Run one command on that machine and its sshd gets a public host and port you can reach from anywhere. Raw TCP tunnels start on Professional at $4 a month.

[Get started →](https://tunnels.io/get-started) [See pricing](https://tunnels.io/pricing)

## What the two ends actually run

On the machine you want to reach, sshd is already listening and the client publishes it. The client dials outward and holds that connection open, so no inbound rule or forwarded port is needed on that network. Raw TCP is a paid protocol: it starts on Professional at $4 a month.

```
# on the machine with no public address
$ tunnels tcp 22
Active Tunnels:
▸ tcp://tunnels.host:41273 → localhost:22  [tcp]
# from a laptop, a phone on cellular, a CI runner
$ ssh -p 41273 user@tunnels.host
```

What you get back is a hostname and a port, not a URL. A raw TCP listener cannot read a name out of a connection the way an HTTPS edge reads SNI, so the port is what identifies your tunnel. Read the line the client prints.

Everything that rides SSH rides this one tunnel: shells, `scp`, `rsync`, `sftp` and git over SSH. Each is its own connection through the same tunnel to port 22.

## Which plan you need

Professional, at $4 a month or $40 a year. That is the first plan with raw TCP, and SSH needs raw TCP. The free Basic plan and the Student plan carry HTTPS only, so neither can publish port 22.

Professional gives five concurrent tunnels, split by protocol: **one raw TCP tunnel** and four HTTPS. One SSH tunnel at a time, so if you also want a database or a game server published you need Gold at $10 a month, which drops the split and allows ten of any kind. Transfer is 128 GB a month, far more than a shell session will use; the figure matters only if you are moving disk images with `rsync`. Gold at $10 a month raises that to ten tunnels and 256 GB. Reserved subdomains shape HTTPS hostnames and do not change a TCP address: a TCP tunnel is always a port on `tunnels.host`.

## How does this compare with port forwarding, a VPN or a jump host?

| Approach | Router access | Static IP | Second machine | Cost | What it exposes |
| --- | --- | --- | --- | --- | --- |
| Router port forwarding | Yes | Yes, or dynamic DNS | No | Free, plus any ISP fee | Your home IP and one open port |
| Self-hosted VPN | Usually | Yes, or dynamic DNS | Often, for the endpoint | Free software, paid host | A network to every enrolled device |
| A jump host you rent | No | Comes with the host | Yes, and you patch it | A monthly VPS bill | What you forward, plus the host |
| TCP tunnel on tunnels.io | No | No | No | $4 a month | One assigned port, to port 22 |

Mesh VPNs sit between the middle two rows: no router changes, but client software on every device that connects. [Our Tailscale comparison](https://tunnels.io/compare/tailscale) covers where a mesh wins, and [what a VPN tunnel attaches you to](https://tunnels.io/learn/what-is-a-vpn-tunnel) explains joining a network versus publishing one port.

## How do you keep it running across a reboot?

Give it a systemd unit. The client already reconnects on its own, with exponential backoff and jitter, and honours a server-directed reconnect delay so a restart on our side does not stampede. What it cannot survive is the process going away: a reboot, a crash, an out-of-memory kill.

```
# /etc/systemd/system/tunnels-ssh.service
[Unit]
Description=tunnels.io TCP tunnel for sshd
After=network-online.target
Wants=network-online.target
[Service]
User=tunnels
ExecStart=/usr/local/bin/tunnels --log stdout tcp 22
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```

The authtoken lives in the config of whoever ran `tunnels config add-authtoken`, so the unit must run as that user or it will start and fail to authenticate. To publish more than one port, name the tunnels in the config file and run `tunnels start-all`. On Professional only one of them may be raw TCP, so a second SSH or database port needs Gold.

## Does the tunnel authenticate anyone?

No, and this is the part people get wrong. The tunnel is transport. Anything that connects to the assigned port is speaking to your sshd, and sshd alone decides who gets a shell. The `--httpauth` flag puts basic auth in front of an HTTPS tunnel at our edge; it does nothing for TCP.

So harden sshd as if a router had published the port. Keys only, with `PasswordAuthentication no` and keyboard-interactive off. An ed25519 key per machine, passphrase-protected, in an agent. `PermitRootLogin no`. An explicit `AllowUsers` list, so a forgotten service account is not a door.

One thing is genuinely new: the host key. You are connecting to a name you have never used, so your client offers a fingerprint to accept blind. Read it off the machine while you still have console access, and compare.

## How fast does a public SSH port get scanned?

Minutes, not days. Scanners sweep routable address space continuously, and anything answering with an SSH banner goes on a list. A high assigned port is quieter than port 22, because much scanning only probes the well-known port, but that is noise reduction, never a control.

There is a real catch with fail2ban. The tunnel client connects to your sshd over loopback, so every attempt is logged as coming from `127.0.0.1` rather than from whoever is knocking. An IP-based jail bans nothing useful, and a badly scoped one bans loopback and cuts off the tunnel. Keep it for the rate limiting, set `MaxAuthTries 3` and a short `LoginGraceTime`, and accept that key-only authentication is doing the real work.

## What happens if the tunnel drops mid-session?

Your shell dies with it, exactly as it would if you unplugged the cable. The client comes back on its own, but the reconnect is a new TCP connection and the old session is not resumed. Run anything that matters under `tmux` so the work outlives the connection, and set `ServerAliveInterval` so a dead session fails fast instead of hanging.

The rule that follows: never start an unattended upgrade in a plain SSH session over a tunnel you are not watching.

## What this does not do

Read this before you put it in front of a production box. If a line here is a dealbreaker, you want a bastion, not a tunnel.

### It is not authentication

The tunnel decides nothing about who may log in. Your sshd config is the whole of your access control, and it faces the internet now.

### No inspection, no recording

We forward bytes. We do not proxy, parse or inspect SSH, so there is no session recording and no command audit.

### No allowlist at the edge

There is no per-IP allowlist, no OAuth and no SSO. The assigned port answers anyone who finds it.

### A drop ends the session

The client reconnects, your shell does not. Keep anything long-running in a multiplexer.

### HTTPS and TCP only

There is no UDP, so Mosh will not work and neither will WireGuard or DNS. There is no SMTP tunnel type, though SMTP is TCP and rides a raw TCP tunnel like any other TCP service. Neither either.

### The port is assigned

You get a port on tunnels.host, and the command line gives you whatever the server assigns. A specific public port can be asked for only with the `remote_port` key on a named tunnel in the config file; there is no flag for it. Custom domains shape HTTPS hostnames only.

## Related reading

[SSH port forwarding flags explained Which end opens the socket, and the sshd settings that decide whether a forward works at all.](https://tunnels.io/learn/what-is-ssh-tunneling) [What is a reverse tunnel? Why a connection dialled outward can carry traffic back in.](https://tunnels.io/learn/what-is-a-reverse-tunnel) [What is a VPN tunnel? Attaching a machine to a network versus publishing one port.](https://tunnels.io/learn/what-is-a-vpn-tunnel) [tunnels.io vs Tailscale A mesh needs a client on both ends. A tunnel needs one on the far end.](https://tunnels.io/compare/tailscale) [Remote desktop over a tunnel The same TCP tunnel pointed at RDP or VNC, and what changes.](https://tunnels.io/use-cases/remote-desktop) [Reach a database from anywhere Postgres and Redis over raw TCP, and who does the authenticating.](https://tunnels.io/use-cases/database)

On hardware at home? See [homelab access](https://tunnels.io/use-cases/homelab), then [pricing](https://tunnels.io/pricing) and [get started](https://tunnels.io/get-started).

## Questions

### Can I SSH into a computer behind a firewall without opening a port?

Yes. The machine you want to reach dials out to our edge and holds that connection open, so nothing inbound has to be permitted on its network. You connect to a host and port we assign, and traffic rides back down the connection the machine already made.

### Do I need a paid plan to tunnel SSH?

Yes. SSH needs a raw TCP tunnel, and TCP starts on Professional at $4 a month or $40 a year. The free Basic plan and the Student plan carry HTTPS only, so they cannot publish port 22.

### Does the tunnel encrypt my SSH traffic?

SSH encrypts its own traffic between your client and the sshd on the far side, and that is the encryption that matters here. The tunnel carries those bytes without reading them. Treat it as a wire, not a security control, and configure sshd as if a router had published the port.

### Will fail2ban still work over the tunnel?

It runs, but its bans stop meaning much. The tunnel client connects to your sshd over loopback, so every attempt is logged as coming from 127.0.0.1 rather than from whoever is knocking. A jail keyed on source address bans nothing useful, or bans the tunnel itself. Rely on key-only authentication instead.

### Does the port stay the same between reconnects?

Usually. The server remembers the port your tunnel held and tries to hand the same one back on reconnect, falling back to a new port if it has been claimed. Treat it as a convenience rather than a reservation, and read the address the client prints.

One command on the far machine, and port 22 has an address.

Professional is $4 a month, includes raw TCP, and cancels whenever you like. Try the client on the free plan first, then upgrade when you need the port.

[Get started →](https://tunnels.io/get-started) [See plans and limits](https://tunnels.io/pricing)
