SSH Explained: Keys, Agents, and Tunneling

SSH is the workhorse of remote access. The key model, the authentication flow, tunneling tricks, and the modern defaults you should use in 2026.

SSH Explained: Keys, Agents, and Tunneling

Every developer and sysadmin uses SSH every week. Most rarely think about how it works. SSH (Secure Shell) is the encrypted remote-access protocol that powers git push, server administration, port forwarding, file transfer, and dozens of related workflows.

This post is a practical refresher: how SSH authentication actually works, why keys beat passwords, what ssh-agent does, how tunneling works, and what defaults you should be using in 2026.

The Basic Idea

SSH establishes an encrypted, authenticated channel between two hosts. Once established, you can:

  • Run a remote shell.
  • Execute single commands remotely.
  • Transfer files (via scp or sftp).
  • Forward TCP ports through the tunnel.
  • Tunnel arbitrary applications (X11 forwarding, VPN-like usage).

The protocol runs over TCP port 22 by default. The connection includes:

  1. Key exchange — Establish encryption keys via Diffie-Hellman.
  2. Server authentication — Verify the server’s identity via its host key.
  3. Client authentication — Verify your identity via password, key, or other methods.
  4. Channel — Open the encrypted session for shell/command/file transfer.

Why Keys, Not Passwords

Passwords are bad. Key authentication is good. The reasons:

Brute force resistance

A 12-character password has ~10^21 possible combinations. A 4096-bit RSA key has ~10^1233. Even with all the computing power on Earth, brute-forcing a key is impossible.

Phishing resistance

A password can be intercepted, replayed, or phished. A key never leaves your machine — the SSH protocol uses it to sign a challenge, not transmit the secret.

Revocation

You can remove a public key from ~/.ssh/authorized_keys and immediately revoke that machine’s access without affecting other users or having to change passwords across servers.

Auditability

You know which key was used to authenticate; you can grant access to specific keys for specific purposes.

Automation

SSH keys make automated workflows (CI/CD, deployment, backup) work without storing passwords.

In 2026 there’s essentially no reason to use SSH password authentication. Every modern setup uses keys.

How Key Authentication Works

The flow when you connect:

  1. Client says “I want to authenticate as user X with public key Y.”
  2. Server checks if Y is in ~X/.ssh/authorized_keys. If yes, continue.
  3. Server sends a random challenge encrypted with public key Y.
  4. Client decrypts the challenge with its private key (which the server never sees).
  5. Client signs a known message (the session ID) with its private key and sends the signature.
  6. Server verifies the signature with the public key. If valid, authentication succeeds.

The private key never leaves the client. The server only ever sees signatures, never the key itself. This is what makes SSH key authentication phishing-resistant.

Generating Keys

In 2026, the recommended key types are:

  • Ed25519 — Modern elliptic-curve key. Small (32 bytes), fast, secure. Default choice.
  • ECDSA — Also elliptic-curve. Slightly slower; primarily for compatibility.
  • RSA 4096 — Still widely supported. Use 4096-bit minimum if you choose RSA.
  • DSA, RSA-1024 — Don’t use. Considered weak.

Generate a new Ed25519 key:

ssh-keygen -t ed25519 -C "your_email@example.com"

The output is two files:

  • ~/.ssh/id_ed25519 — Private key. Keep secret. Permissions 0600.
  • ~/.ssh/id_ed25519.pub — Public key. Share freely. Goes in remote authorized_keys.

Add a passphrase for the private key. If your laptop is stolen, the key is useless without it. Combine with ssh-agent and you only enter the passphrase once per session.

SSH Agent

ssh-agent is a background process that holds decrypted private keys in memory. When SSH needs the key, it asks the agent rather than reading from disk.

Benefits:

  • You enter your passphrase once. Subsequent SSH connections use the cached key.
  • The key never appears in environment variables or files in plaintext.
  • Agent forwarding lets you use your local keys on remote servers (ssh -A) — though this has security trade-offs.

Adding a key to the agent:

eval "$(ssh-agent -s)"      # start agent if not running
ssh-add ~/.ssh/id_ed25519   # add key (prompts for passphrase)
ssh-add -l                  # list loaded keys

On macOS, the system keychain integrates with ssh-agent automatically; configure with Host *\n UseKeychain yes\n AddKeysToAgent yes in ~/.ssh/config.

Agent Forwarding (Use Carefully)

ssh -A host enables agent forwarding — your local ssh-agent is accessible from the remote host. This lets you use your local keys to authenticate to other servers from the remote.

The risk: anyone with root on the remote (or who compromises it) can use your forwarded agent to access other servers you have keys for. The forwarding is per-session, but it’s a big trust extension.

Safer alternative: ProxyJump (ssh -J jumphost target). The jump happens through the intermediate host but uses keys locally — the intermediate never sees your agent.

In ~/.ssh/config:

Host target
    HostName target.example.com
    ProxyJump jumphost.example.com

SSH Config

~/.ssh/config is where you set per-host SSH options. Common entries:

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github
    IdentitiesOnly yes

Host prod-*
    User deploy
    IdentityFile ~/.ssh/id_ed25519_prod
    ProxyJump bastion.example.com

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    UseKeychain yes  # macOS only

The IdentitiesOnly yes prevents SSH from trying every key in your agent — useful when you have many.

Port Forwarding

SSH can tunnel arbitrary TCP traffic through the encrypted channel.

Local forwarding (-L)

“Forward my local port X to remote server’s port Y.”

ssh -L 5432:database.internal:5432 bastion.example.com

After this, your local localhost:5432 connects to database.internal:5432 (via the bastion). Useful for accessing internal services without exposing them to the public internet.

Remote forwarding (-R)

“Forward remote server’s port X to my local port Y.”

ssh -R 9000:localhost:3000 jumphost.example.com

Connections to jumphost:9000 come back to your local localhost:3000. Useful for exposing a local dev server to a remote system.

Dynamic forwarding (-D)

“Set up a SOCKS proxy on my local port that tunnels through SSH.”

ssh -D 1080 bastion.example.com

Your local apps configured to use socks5://localhost:1080 will tunnel through SSH to the bastion. Ad-hoc VPN.

Server-Side Hardening

For SSH servers (typical /etc/ssh/sshd_config in 2026):

# Disable password auth - keys only
PasswordAuthentication no
ChallengeResponseAuthentication no

# Disable root login (use sudo from a regular user)
PermitRootLogin no

# Only allow specific users
AllowUsers admin deploy

# Use strong host key algorithms only
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256

# Use modern key exchange
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256

# Modern ciphers only
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com

Restart sshd after changes. Always test from a second session before logging out — locking yourself out is easy.

Fail2ban and Brute Force

Even with key-only auth, SSH brute force attempts saturate logs. Tools to mitigate:

  • fail2ban — Banscan IPs that fail authentication N times.
  • Cloud security groups — Restrict SSH access to known IPs.
  • Move off port 22 — Reduces noise (security through obscurity, but it does cut log volume).
  • VPN-gated SSH — Make SSH unreachable from the public internet entirely. Only reachable via corporate VPN or jump host.

For high-stakes hosts, “VPN + key auth + audit logging” is the production pattern.

SSH Certificates

For organizations managing many users and servers, SSH certificates are an alternative to manually managing authorized_keys files.

You run a small CA that signs SSH user certificates. Users present their cert + private key. Servers trust certs signed by the CA — no need to add individual public keys.

Benefits:

  • Centralized issuance and revocation.
  • Short-lived certs (1-24 hours) eliminate the “stale key” problem.
  • Audit trail of who got what access when.

Tools: HashiCorp Vault SSH secrets engine, Smallstep, Teleport. For small teams, the complexity isn’t worth it. For >50 users, it usually is.

File Transfer

scp

Classic but deprecated in modern OpenSSH (uses unmaintained protocol). Still works for now.

scp file.txt user@host:/path/to/destination/
scp -r local_dir/ user@host:/path/

sftp

Interactive file transfer over SSH. Programmatic API in most languages.

rsync over SSH

The modern recommended option. Incremental, resumable, much better for large transfers.

rsync -avz local_dir/ user@host:/path/

Common Issues

”Permission denied (publickey)”

Server didn’t accept your key. Causes:

  • Wrong username (ssh user@host).
  • Key not in authorized_keys.
  • authorized_keys has wrong permissions (must be 0600).
  • ~/.ssh/ has wrong permissions (must be 0700).

Debug with ssh -vvv user@host to see the full negotiation.

Hangs on connect

Often DNS or reverse DNS issues. SSH does a reverse lookup on connect by default. Set UseDNS no on the server if you don’t need it.

”Host key verification failed”

The server’s host key changed. Either it’s legitimate (server reinstall, new VM) or you’re being MITM’d. Verify out-of-band before accepting.

Slow connection start

GSSAPI authentication trying. Add GSSAPIAuthentication no to client config.

TL;DR

  • SSH is the workhorse of remote access; runs over TCP port 22.
  • Keys, not passwords. Ed25519 is the default in 2026.
  • ssh-agent caches decrypted keys so you enter your passphrase once.
  • ~/.ssh/config is where you set per-host options.
  • Port forwarding (-L, -R, -D) tunnels arbitrary TCP through SSH.
  • Server hardening: key-only auth, no root login, fail2ban, modern algorithms.
  • SSH certificates scale better than authorized_keys for large teams.
  • rsync over SSH is the modern recommended file transfer.

SSH is one of those tools where 90% of users know 10% of the features. Even basic improvements — switching to keys, using ssh-agent, setting up ~/.ssh/config — pay back the learning time many times over. For the broader security/encryption picture, see TLS handshake; for the port-level mechanics, port numbers explained.

Get Started

Convert IPs into accurate location data in milliseconds.

Sign up today and get 1,000 free monthly stored conversions, and discover why developers trust us for fast, reliable, and affordable IP conversions.