SSH is the ubiquitous tool for secure remote access, but its true power lies in its ability to act as a secure tunnel for any TCP-based traffic, not just shell sessions.
Let’s see it in action. Imagine you have a database running on a remote server, say db.example.com, listening on port 5432. You want to access it from your local machine, but it’s not exposed to the public internet.
# On your local machine, assuming you have SSH access to a bastion host
# that can reach db.example.com
ssh -L 5432:db.example.com:5432 user@bastion.example.com
This command does something magical. It establishes an SSH connection to bastion.example.com. But the -L flag tells SSH to set up a local port forward. It says: "Listen on my local machine’s port 5432. Whenever any application on my local machine connects to localhost:5432, take that traffic, send it securely through the SSH tunnel to bastion.example.com, and from there, forward it to db.example.com on port 5432."
Now, on your local machine, you can point your PostgreSQL client (or any other client for that service) to localhost:5432, and it will transparently connect to the remote database as if it were running locally.
The fundamental problem SSH solves is the inherent insecurity of plain-text network protocols. Before SSH, tools like Telnet and FTP sent passwords and data in the clear, making them trivial to intercept on any network. SSH, on the other hand, uses strong cryptography to encrypt all communication between the client and server. This includes authentication credentials, commands, and their output.
Internally, an SSH connection is a complex choreography. When you initiate an SSH connection, the client and server first perform a key exchange to agree on symmetric encryption algorithms and session keys. This is crucial because it allows them to encrypt the rest of the communication without needing to trust each other’s public keys for every single packet. After the secure channel is established, authentication happens. This can be done via passwords, but more commonly and securely, using public-key cryptography where your private key on your local machine proves your identity to the server. Once authenticated, you can initiate various "channels" over this secure connection. A shell session is just one type of channel; port forwarding is another.
The sshd_config file on the server (/etc/ssh/sshd_config on most Linux systems) is where you control many aspects of SSH behavior. You can disable password authentication (PasswordAuthentication no), specify allowed users or groups (AllowUsers user1 user2), change the default listening port (from Port 22 to something else, like Port 2222 for added obscurity, though this isn’t true security), or control which subsystems are available. For example, Subsystem sftp /usr/lib/openssh/sftp-server enables the SFTP (SSH File Transfer Protocol) subsystem, allowing secure file transfers.
The magic of SSH tunneling extends beyond simply making remote services accessible. It can also be used to bypass firewalls or to secure traffic from applications that don’t natively support encryption. For instance, if you have an old application that only speaks plain HTTP, you can tunnel its traffic through SSH to a remote server that can then forward it to the actual destination, encrypting the transit over an untrusted network. The command ssh -D 8080 -N -f user@proxy.example.com sets up a SOCKS proxy on your local machine’s port 8080. Applications configured to use localhost:8080 as a SOCKS proxy will have their traffic routed securely through proxy.example.com. The -N flag tells SSH not to execute a remote command, and -f sends it to the background.
A common point of confusion is the difference between local (-L) and remote (-R) port forwarding. While local forwarding makes a remote service available locally, remote forwarding makes a local service available on the remote server. For example, ssh -R 8080:localhost:80 user@remote.example.com would mean that remote.example.com will listen on its port 8080, and any traffic arriving there will be forwarded back through the tunnel to your local machine, then to localhost:80. This is useful for exposing a local web server to the internet via a remote server.
Many users are unaware that SSH can also proxy DNS requests when used with -D, significantly enhancing privacy and bypassing DNS-based restrictions.