SSH Basics - Secure Shell Complete Guide

Status: Active
Last Updated: 2026-01-30
Session: Infrastructure KB Expansion - Basics Series
Tags: beginner, ssh, security, remote-access, authentication, keys

Summary

Comprehensive guide to SSH (Secure Shell) - the secure protocol for remote server access. Covers SSH fundamentals, key generation, configuration, tunneling, security best practices, and troubleshooting. Assumes basic Linux knowledge but explains SSH concepts from the ground up.

🎯 What You'll Learn

By the end of this guide, you'll understand:

Prerequisites: kb/basics/linux-fundamentals - Basic Linux knowledge
Time Investment: 2-3 hours to read, weeks of practice to master
Recommended Setup: Access to two Linux systems (local + remote, or VM)


Table of Contents

  1. What is SSH and Why It Matters
  2. How SSH Works
  3. Installing SSH
  4. Generating SSH Keys
  5. Connecting to Remote Servers
  6. SSH Configuration File
  7. Copying SSH Keys to Servers
  8. SSH Agent - Managing Keys
  9. SSH Tunneling and Port Forwarding
  10. Security Best Practices
  11. Troubleshooting Common Issues
  12. SSH Escape Codes
  13. Next Steps

What is SSH and Why It Matters

SSH (Secure Shell) is a cryptographic network protocol for securely accessing and managing remote computers over an insecure network (like the Internet). It replaced older, insecure protocols like Telnet, rlogin, and FTP.

Why SSH is Everywhere

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    SSH    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Your Laptop β”‚ ========> β”‚ Remote Serverβ”‚
β”‚  (Client)   β”‚ Encrypted β”‚   (Host)     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     
Everything sent between them is encrypted:
β€’ Commands you type
β€’ Output you receive  
β€’ Files you transfer
β€’ Passwords and keys

Critical Uses:

Without SSH: Managing infrastructure at scale would be impossible. You'd need physical or console access to every server.

SSH vs Other Protocols

Protocol Security Use Case Status
SSH Encrypted Remote shell, file transfer βœ… Modern standard
Telnet Plain text! Remote shell ❌ Obsolete (insecure)
FTP Plain text! File transfer ❌ Obsolete (insecure)
SFTP Encrypted (uses SSH) File transfer βœ… Recommended
SCP Encrypted (uses SSH) File transfer βœ… Recommended

How SSH Works

Understanding SSH's security model helps you use it confidently and troubleshoot issues.

Client-Server Architecture

CLIENT (Your Computer)          SERVER (Remote Host)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  SSH Client      β”‚            β”‚   SSH Daemon      β”‚
β”‚  (ssh command)   β”‚            β”‚   (sshd service)  β”‚
β”‚                  β”‚            β”‚                   β”‚
β”‚  Port: Random    │◄─────────►│   Port: 22        β”‚
β”‚                  β”‚  Encrypted β”‚                   β”‚
β”‚  ~/.ssh/         β”‚  Tunnel    β”‚   ~/.ssh/         β”‚
β”‚    config        β”‚            β”‚     authorized_   β”‚
β”‚    id_rsa        β”‚            β”‚     keys          β”‚
β”‚    known_hosts   β”‚            β”‚   /etc/ssh/       β”‚
β”‚                  β”‚            β”‚     sshd_config   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Authentication Methods

SSH supports multiple authentication methods (tried in order):

1. Public Key Authentication (Recommended - Most Secure)

You have:  Private key (~/.ssh/id_rsa) - NEVER share!
Server has: Public key (~/.ssh/authorized_keys) - Safe to share

Server challenges you β†’ Prove you have private key β†’ Access granted
No password needed!

2. Password Authentication (Simple but Less Secure)

Server asks for password β†’ You type password β†’ Server checks β†’ Access granted

3. Other Methods (Advanced)

Why Public Keys are Better

Password Auth Public Key Auth
Vulnerable to brute force Mathematically infeasible to guess
Can be phished/typed wrong Key never leaves your computer
Humans choose weak passwords 2048+ bit keys = strong by default
Manual typing required Automatic authentication
One password compromised = breach Revoke one key, others still work

Installing SSH

Most Linux systems come with SSH pre-installed, but here's how to ensure it's ready.

Check if SSH is Installed

Check SSH Client (your computer):

$ ssh -V
OpenSSH_9.0p1, OpenSSL 3.0.2 15 Mar 2022

Check SSH Server (remote hosts you manage):

# Check if sshd is running
$ systemctl status sshd
# or on older systems:
$ systemctl status ssh

# Check if sshd is installed
$ which sshd
/usr/sbin/sshd

Installing SSH

Ubuntu/Debian:

# Client (usually pre-installed)
$ sudo apt update
$ sudo apt install openssh-client

# Server (if setting up a server for others to connect to)
$ sudo apt install openssh-server
$ sudo systemctl enable ssh
$ sudo systemctl start ssh

RHEL/Rocky/Fedora:

# Client
$ sudo dnf install openssh-clients

# Server
$ sudo dnf install openssh-server
$ sudo systemctl enable sshd
$ sudo systemctl start sshd

# Allow SSH through firewall
$ sudo firewall-cmd --permanent --add-service=ssh
$ sudo firewall-cmd --reload

Windows:

Check if available:

PS> ssh -V

macOS:


Generating SSH Keys

SSH keys are the foundation of secure, password-less authentication.

Creating Your First SSH Key Pair

Basic Key Generation:

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/yourname/.ssh/id_rsa): [Press ENTER]
Enter passphrase (empty for no passphrase): [Type passphrase or press ENTER]
Enter same passphrase again: [Repeat]

Your identification has been saved in /home/yourname/.ssh/id_rsa
Your public key has been saved in /home/yourname/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 yourname@yourlaptop
The key's randomart image is:
+---[RSA 3072]----+
|        .o+*=    |
|       . o*o+.   |
|        o.=+..   |
|       . +.+o    |
|        S +..    |
|         =.o     |
|        . B.     |
|         = E     |
|        . o      |
+----[SHA256]-----+

What Just Happened?

Two files were created in ~/.ssh/:

$ ls -l ~/.ssh/
-rw-------  1 yourname yourname 2602 Jan 30 10:00 id_rsa       # Private key
-rw-r--r--  1 yourname yourname  571 Jan 30 10:00 id_rsa.pub   # Public key

CRITICAL:

Stronger Key Generation

Recommended for 2026+ (stronger key):

# 4096-bit RSA key (more secure)
$ ssh-keygen -t rsa -b 4096 -C "yourname@yourdomain.com"

# ED25519 key (modern, smaller, faster)
$ ssh-keygen -t ed25519 -C "yourname@yourdomain.com"

Key Type Comparison:

Type Bits Speed Security Use Case
RSA 2048 2048 Good Good Default, widely compatible
RSA 4096 4096 Slower Better Maximum compatibility + security
ED25519 256 Fast Excellent Modern (2013+), recommended

Recommendation: Use ED25519 for new keys unless you need compatibility with very old systems.

Adding a Passphrase

Should you use a passphrase?

Passphrase = Password that encrypts your private key

WITH passphrase:
βœ… Even if someone steals id_rsa, they can't use it
βœ… Extra security layer
❌ Must type passphrase when using key (can be cached with ssh-agent)

WITHOUT passphrase:
βœ… Fully automatic authentication
❌ Stolen key = instant access to your servers

Best Practice: Always use a passphrase for production servers, optionally skip for local dev/testing.

Managing Multiple Keys

Different keys for different purposes:

# Personal GitHub
$ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github -C "personal@email.com"

# Work servers
$ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work -C "work@company.com"

# Specific project
$ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_project -C "project@client.com"

You'll configure which key to use in ~/.ssh/config (covered later).

Viewing Your Public Key

$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC... yourname@yourlaptop

# Or for ED25519:
$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... yourname@yourlaptop

This is what you'll copy to servers and Git services.

Viewing Key Fingerprint

$ ssh-keygen -lf ~/.ssh/id_rsa.pub
3072 SHA256:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 yourname@yourlaptop (RSA)

Fingerprints help verify you're using the right key.


Connecting to Remote Servers

Now let's actually connect to a remote server!

Basic Connection

Simplest form (if username matches):

$ ssh hostname
# Example:
$ ssh myserver.example.com

Specify username:

$ ssh username@hostname
# Example:
$ ssh alice@192.168.1.100
$ ssh deploy@myserver.example.com

First connection - You'll see this warning:

$ ssh alice@newserver.example.com
The authenticity of host 'newserver.example.com (192.168.1.100)' can't be established.
ED25519 key fingerprint is SHA256:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'newserver.example.com' (ED25519) to the list of known hosts.
alice@newserver.example.com's password:

What's happening?

  1. Your client doesn't recognize the server yet
  2. Server presents its host key fingerprint
  3. You verify it's the right server (check with admin/documentation)
  4. Type yes to accept and remember this server
  5. Server's key is saved to ~/.ssh/known_hosts
  6. Future connections won't ask again (unless key changes)

Connection with Password

$ ssh alice@myserver.example.com
alice@myserver.example.com's password: [type password]

# Now you have a shell on the remote server:
alice@myserver:~$ whoami
alice
alice@myserver:~$ pwd
/home/alice
alice@myserver:~$ logout
Connection to myserver.example.com closed.

# Back on your local machine
$

Running Single Commands

Instead of opening a shell session, execute one command and return:

# Check server uptime
$ ssh alice@myserver.example.com uptime
 10:23:45 up 42 days, 3:14, 2 users, load average: 0.15, 0.22, 0.18

# Check disk space
$ ssh alice@myserver.example.com df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   20G   28G  42% /

# Run multiple commands (quote them)
$ ssh alice@myserver.example.com "cd /var/log && tail -n 20 syslog"

Specifying Port

Default SSH port is 22. If your server uses a different port:

$ ssh -p 2222 alice@myserver.example.com

Using a Specific Key

$ ssh -i ~/.ssh/id_ed25519_work alice@workserver.com

SSH Configuration File

Typing full connection details every time is tedious. The SSH config file lets you create shortcuts.

Creating/Editing SSH Config

$ mkdir -p ~/.ssh
$ chmod 700 ~/.ssh
$ nano ~/.ssh/config

Basic Configuration Example

# Personal server
Host myserver
    HostName myserver.example.com
    User alice
    Port 22
    IdentityFile ~/.ssh/id_ed25519

# Work server with custom port
Host workserver
    HostName work.company.com
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_work

# Development VM
Host devvm
    HostName 192.168.1.100
    User developer
    ForwardAgent yes

# Wildcard for all company servers
Host *.company.com
    User alice
    IdentityFile ~/.ssh/id_ed25519_work
    ServerAliveInterval 60
    ServerAliveCountMax 3

Now connect simply:

$ ssh myserver       # Instead of: ssh -i ~/.ssh/id_ed25519 alice@myserver.example.com
$ ssh workserver     # Instead of: ssh -p 2222 -i ~/.ssh/id_ed25519_work deploy@work.company.com
$ ssh devvm          # Instead of: ssh developer@192.168.1.100

Useful Configuration Options

Host *
    # Keep connection alive (prevent timeouts)
    ServerAliveInterval 60
    ServerAliveCountMax 3
    
    # Reuse connections (faster subsequent connections)
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h:%p
    ControlPersist 600
    
    # Security settings
    StrictHostKeyChecking ask
    HashKnownHosts yes
    
    # Prefer public key auth
    PreferredAuthentications publickey,password
    
    # Compression for slow connections
    Compression yes

Create socket directory for ControlMaster:

$ mkdir -p ~/.ssh/sockets

Per-Host Advanced Config

Host jumpbox
    HostName jumpbox.example.com
    User bastion
    ForwardAgent yes

# Connect through jump host
Host internal-server
    HostName 10.0.1.50
    User admin
    ProxyJump jumpbox

# Multiple jump hosts
Host deep-server
    HostName 10.0.2.100
    User admin
    ProxyJump jumpbox,gateway

Copying SSH Keys to Servers

To use key-based authentication, your public key must be on the server in ~/.ssh/authorized_keys.

Method 1: Using ssh-copy-id (Easiest)

$ ssh-copy-id username@hostname

# Example:
$ ssh-copy-id alice@myserver.example.com
/usr/bin/ssh-copy-id: INFO: attempting to log in...
alice@myserver.example.com's password: [type password]

Number of key(s) added: 1

Now try logging into the machine with "ssh 'alice@myserver.example.com'"
and check to make sure that only the key(s) you wanted were added.

Specify which key:

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@myserver.example.com

Test it works:

$ ssh alice@myserver.example.com
# Should NOT ask for password!

Method 2: Manual Copy (if ssh-copy-id unavailable)

One-liner using cat and ssh:

$ cat ~/.ssh/id_ed25519.pub | ssh alice@myserver.example.com "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Breakdown:

  1. cat ~/.ssh/id_ed25519.pub - Read your public key
  2. ssh alice@myserver.example.com - Connect to server
  3. mkdir -p ~/.ssh - Ensure .ssh directory exists
  4. chmod 700 ~/.ssh - Set correct permissions on directory
  5. cat >> ~/.ssh/authorized_keys - Append key to authorized_keys
  6. chmod 600 ~/.ssh/authorized_keys - Set correct permissions on file

Method 3: Fully Manual (console/web panel access)

If you have console or physical access to the server:

On your local machine, display your public key:

$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAbCdEfGhIjKlMnOpQrStUvWxYz yourname@laptop

On the remote server, create file and paste:

$ mkdir -p ~/.ssh
$ chmod 700 ~/.ssh
$ nano ~/.ssh/authorized_keys
# Paste your public key (one per line)
# Save and exit

$ chmod 600 ~/.ssh/authorized_keys

Verifying Authorized Keys

On server, check what keys are authorized:

$ cat ~/.ssh/authorized_keys

Test from local machine:

$ ssh -v alice@myserver.example.com
# Look for lines like:
# debug1: Offering public key: /home/yourname/.ssh/id_ed25519 ED25519 SHA256:...
# debug1: Server accepts key: /home/yourname/.ssh/id_ed25519 ED25519 SHA256:...
# debug1: Authentication succeeded (publickey).

SSH Agent - Managing Keys

SSH Agent caches your decrypted private keys so you only enter passphrases once per session.

Why Use SSH Agent?

Without Agent:

$ ssh server1
Enter passphrase for key '/home/you/.ssh/id_ed25519': [type passphrase]
$ ssh server2  
Enter passphrase for key '/home/you/.ssh/id_ed25519': [type passphrase again!]
$ ssh server3
Enter passphrase for key '/home/you/.ssh/id_ed25519': [type passphrase again!]

With Agent:

$ ssh-add
Enter passphrase for key '/home/you/.ssh/id_ed25519': [type ONCE]
$ ssh server1     # No passphrase!
$ ssh server2     # No passphrase!
$ ssh server3     # No passphrase!

Starting SSH Agent

Most Linux desktops start agent automatically. Check if running:

$ echo $SSH_AUTH_SOCK
/run/user/1000/keyring/ssh
# If you see a path, agent is running

$ ssh-add -l
2048 SHA256:a1b2c3d4... yourname@laptop (RSA)
# Shows loaded keys

If agent not running, start it:

$ eval $(ssh-agent)
Agent pid 12345

Add this to ~/.bashrc or ~/.zshrc to auto-start:

if [ -z "$SSH_AUTH_SOCK" ]; then
    eval $(ssh-agent -s) > /dev/null
    ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi

Adding Keys to Agent

# Add default key
$ ssh-add
Enter passphrase for /home/you/.ssh/id_rsa: [type passphrase]
Identity added: /home/you/.ssh/id_rsa

# Add specific key
$ ssh-add ~/.ssh/id_ed25519_work
Enter passphrase for /home/you/.ssh/id_ed25519_work: [type passphrase]
Identity added: /home/you/.ssh/id_ed25519_work

# Add all keys in ~/.ssh
$ ssh-add ~/.ssh/id_*

Managing Loaded Keys

# List loaded keys
$ ssh-add -l
3072 SHA256:a1b2c3d4e5f6... yourname@laptop (RSA)
256 SHA256:x9y8z7w6v5u4... yourname@laptop (ED25519)

# Remove specific key
$ ssh-add -d ~/.ssh/id_rsa.pub

# Remove all keys
$ ssh-add -D

Agent Forwarding

Agent forwarding lets you use your local keys on a remote server without copying them:

Your Laptop β†’ Server A β†’ Server B
   (keys)   (no keys)  (no keys)
   
Agent forwarding = Server A can use YOUR keys to connect to Server B

Enable per-connection:

$ ssh -A alice@servera.example.com
alice@servera:~$ ssh bob@serverb.example.com  # Uses YOUR keys!

Enable in SSH config:

Host jumpbox
    HostName jumpbox.example.com
    ForwardAgent yes

⚠️ Security Warning: Only use agent forwarding on servers you trust. A compromised server could use your keys while you're connected.


SSH Tunneling and Port Forwarding

SSH can create encrypted tunnels for other services. Incredibly powerful for security and accessing restricted networks.

Local Port Forwarding

Access a remote service as if it's local:

Your Laptop:8080 ──SSH Tunnel──> Remote:80

Web browser β†’ localhost:8080 β†’ (encrypted tunnel) β†’ remote-server:80

Example - Access remote web server:

$ ssh -L 8080:localhost:80 alice@remote-server.com
# Now open http://localhost:8080 in your browser
# You're accessing remote-server.com:80 through encrypted tunnel

General syntax:

ssh -L local_port:destination:destination_port user@ssh-server

Real-world examples:

# Access remote database
$ ssh -L 5432:localhost:5432 alice@dbserver.com
# Connect to localhost:5432 with your database tool

# Access remote admin panel (only accessible from server)
$ ssh -L 8080:localhost:8080 alice@server.com
# Open http://localhost:8080

# Access service on private network through jump host
$ ssh -L 3000:10.0.1.50:3000 alice@jumphost.com
# Access private server 10.0.1.50:3000 via jumphost

Run in background:

$ ssh -f -N -L 8080:localhost:80 alice@server.com
# -f = background
# -N = don't execute commands (just forward)

Remote Port Forwarding

Expose your local service to remote server:

Remote:8080 ──SSH Tunnel──> Your Laptop:3000

Remote users β†’ remote-server:8080 β†’ (encrypted tunnel) β†’ localhost:3000

Example - Share local development server:

# You're running app on localhost:3000
$ ssh -R 8080:localhost:3000 alice@publicserver.com
# Now publicserver.com:8080 β†’ your localhost:3000

General syntax:

ssh -R remote_port:local_host:local_port user@ssh-server

Use case: Demonstrate local dev work to remote client without deploying.

Dynamic Port Forwarding (SOCKS Proxy)

Turn SSH connection into a SOCKS proxy:

$ ssh -D 8080 alice@server.com
# Your laptop now has SOCKS proxy on localhost:8080

Configure browser to use SOCKS proxy localhost:8080:

Firefox configuration:

Preferences β†’ Network Settings β†’ Manual Proxy Configuration
SOCKS Host: localhost
Port: 8080
SOCKS v5: Yes

Security Best Practices

SSH is secure by default, but proper configuration makes it bulletproof.

Server-Side Security (sshd_config)

Edit SSH daemon config:

$ sudo nano /etc/ssh/sshd_config

Essential security settings:

# Disable password authentication (keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no

# Disable root login
PermitRootLogin no

# Only allow specific users
AllowUsers alice bob charlie

# Or only allow specific groups
AllowGroups sshusers

# Limit authentication attempts
MaxAuthTries 3

# Use strong encryption only
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Change default port (security through obscurity, but helps reduce bot attacks)
Port 2222

# Protocol 2 only (never use protocol 1)
Protocol 2

After changes, restart SSH:

$ sudo systemctl restart sshd   # RHEL/Rocky/Fedora
$ sudo systemctl restart ssh    # Ubuntu/Debian

⚠️ Before disabling password auth: Make sure key-based auth works! Test in a separate session or you'll lock yourself out.

Client-Side Security

Protect your private keys:

# Correct permissions
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/id_*
$ chmod 644 ~/.ssh/id_*.pub
$ chmod 600 ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/config

Check permissions:

$ ls -la ~/.ssh/
drwx------   2 alice alice 4096 Jan 30 10:00 .
drwxr-xr-x  25 alice alice 4096 Jan 30 09:00 ..
-rw-------   1 alice alice 3401 Jan 30 10:00 id_ed25519
-rw-r--r--   1 alice alice  751 Jan 30 10:00 id_ed25519.pub
-rw-------   1 alice alice 1234 Jan 30 09:50 authorized_keys
-rw-------   1 alice alice 2345 Jan 30 09:45 config
-rw-r--r--   1 alice alice 5678 Jan 30 09:40 known_hosts

Key Management Best Practices

  1. Use passphrases on private keys (especially for production)
  2. Separate keys for different purposes (work, personal, specific projects)
  3. Rotate keys periodically (annually or when team members leave)
  4. Backup keys securely (encrypted backup, password manager)
  5. Never commit private keys to Git (add id_* to .gitignore)
  6. Remove old keys from authorized_keys when no longer needed
  7. Monitor SSH logins (check /var/log/auth.log regularly)

Fail2Ban - Automated Ban for Brute Force

Install Fail2Ban to automatically block IPs after failed login attempts:

# Ubuntu/Debian
$ sudo apt install fail2ban

# RHEL/Rocky/Fedora
$ sudo dnf install fail2ban

# Enable and start
$ sudo systemctl enable fail2ban
$ sudo systemctl start fail2ban

# Check status
$ sudo fail2ban-client status sshd

Default config usually works well: Ban after 5 failed attempts for 10 minutes.


Troubleshooting Common Issues

Connection Refused

Error:

ssh: connect to host myserver.example.com port 22: Connection refused

Causes & Fixes:

# 1. SSH server not running
$ sudo systemctl status sshd
$ sudo systemctl start sshd

# 2. Wrong port
$ ssh -p 2222 user@host

# 3. Firewall blocking
$ sudo firewall-cmd --list-all
$ sudo firewall-cmd --permanent --add-service=ssh
$ sudo firewall-cmd --reload

# 4. Network issue - test connectivity
$ ping myserver.example.com
$ telnet myserver.example.com 22

Permission Denied (publickey)

Error:

Permission denied (publickey).

Debugging steps:

# 1. Verbose output to see what's happening
$ ssh -v user@host
# Look for lines about key offers and server responses

# 2. Verify key is offered
debug1: Offering public key: /home/you/.ssh/id_ed25519
debug1: Server accepts key: /home/you/.ssh/id_ed25519
# If "Server accepts key" missing, server doesn't have your public key

# 3. Check permissions on client
$ ls -la ~/.ssh/
# id_rsa should be 600 (rw-------)

# 4. Check authorized_keys on server
$ ssh user@host "cat ~/.ssh/authorized_keys"
# Your public key should be there

# 5. Check permissions on server
$ ssh user@host "ls -la ~/.ssh/"
# .ssh should be 700, authorized_keys should be 600

# 6. Check SELinux (RHEL/Rocky/Fedora)
$ sudo restorecon -Rv ~/.ssh

Host Key Verification Failed

Error:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

Causes:

  1. Server was rebuilt/reinstalled (new host keys generated)
  2. IP address reassigned to different server
  3. Man-in-the-middle attack (rare but serious!)

If you KNOW it's legitimate (server rebuilt):

$ ssh-keygen -R hostname
# or
$ ssh-keygen -R 192.168.1.100

# Then connect again
$ ssh user@hostname

If unexpected: Investigate! Contact server admin. Don't ignore this warning.

Timeout Issues

Error:

ssh: connect to host myserver.example.com port 22: Connection timed out

Add keepalive to config:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Too Many Authentication Failures

Error:

Received disconnect from host: 2: Too many authentication failures

Cause: Too many keys in ssh-agent

Fix:

# Remove all keys from agent
$ ssh-add -D

# Add only the key you need
$ ssh-add ~/.ssh/id_ed25519

# Or specify key explicitly
$ ssh -i ~/.ssh/id_ed25519 user@host

SSH Escape Codes

Control SSH sessions from within using escape codes (start with ~).

Must be first thing on new line (press Enter first):

# Force disconnect (stuck session)
[ENTER]
~.
# Connection closed

# List forwarded connections
[ENTER]
~#

# Background SSH session
[ENTER]
~[CTRL-Z]
[1]+  Stopped                 ssh user@host
$ fg  # Return to session

# SSH command line (add/remove port forwards)
[ENTER]
~C
ssh> -L 8080:localhost:80
Forwarding port.
ssh> -KL 8080
Canceled forwarding.

# List all escape codes
[ENTER]
~?

Useful for:


Resource Requirements

SSH Client:

SSH Server (sshd):

SSH Tunneling:

Learning Curve:


Next Steps

After Mastering SSH Basics

Immediate Next Steps:

  1. kb/security/ssh-hardening - Advanced security configurations
  2. kb/basics/bash-scripting - Automate SSH tasks
  3. kb/infrastructure/ansible-basics - Use SSH for automation at scale

Infrastructure Path: 4. kb/cicd/forgejo-setup - Set up self-hosted Git with SSH 5. kb/infrastructure/server-provisioning - Set up new servers 6. kb/security/zero-trust-homelab - Build secure infrastructure

Advanced SSH Topics:


Community Resources

πŸ“š Official Documentation (Type β†’ Skill Level)

Beginner:

Intermediate:

Advanced:

πŸŽ“ Tutorials (Type β†’ Skill Level)

Beginner:

Intermediate:

Advanced:

πŸŽ₯ Video Courses (Type β†’ Skill Level)

Beginner:

Intermediate:

πŸ“– Books (Type β†’ Skill Level)

Beginner to Intermediate:

πŸ’¬ Community Help (Type)

Q&A:

Forums:

πŸ”§ Tools & Utilities (Type)

SSH Clients:

Key Management:

Configuration Generators:

πŸ“œ Cheat Sheets (Type)


Related KB Articles

Prerequisites for This Article:

This Article is a Prerequisite For:

Related Topics:


Change Log

2026-01-30 - Initial Creation


πŸ” Remember: SSH is your lifeline to remote infrastructure. Master it well, protect your keys zealously, and you'll have a secure, convenient way to manage servers anywhere in the world!

Choose Theme

Your selection is saved locally.

Neural Cacophony
Aperture v2
Flux v1
Mosaic Chaos
Nexus v1
Nexus Zest
Prism v2
Synapse