SSH Secure Shell

SSH cheatsheet — connect to remote servers, set up keys, and tunnel traffic. ssh -i key user@host, ssh-keygen, ssh-copy-id, ssh -L local port forward, ssh config file patterns.

9 min read

What it is

SSH (Secure Shell) is a protocol and a suite of tools for securely connecting to remote servers, executing commands, and transferring files. You reach for it whenever you need to manage a server, access a remote shell, or securely copy data.

Installation

Linux: SSH client and server are usually pre-installed on most Linux distributions. If not:

sudo apt update && sudo apt install openssh-client openssh-server # Debian/Ubuntu
sudo yum update && sudo yum install openssh-clients openssh-server # CentOS/RHEL
sudo dnf update && sudo dnf install openssh-clients openssh-server # Fedora

macOS: SSH client is pre-installed. To install the server:

# Install Homebrew if you don't have it:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install openssh
brew install openssh
# Follow instructions to configure and start the SSH server.

Windows: Windows 10/11 and Server 2019+: The OpenSSH client and server are available as optional features.

  1. Go to Settings > Apps > Optional features.
  2. Click Add a feature.
  3. Find OpenSSH Client and OpenSSH Server in the list, click Install.
  4. To start the server: Open PowerShell as Administrator and run Start-Service sshd.
  5. To set it to start automatically: Set-Service -Name sshd -StartupType 'Automatic'.

Older Windows: Use third-party clients like PuTTY, MobaXterm, or the Windows Subsystem for Linux (WSL).

Core Concepts

  • Client/Server Model: An SSH client connects to an SSH server.
  • Authentication: Verifies the identity of the user and the server. Common methods include password authentication and public-key authentication.
  • Encryption: All communication between client and server is encrypted to prevent eavesdropping.
  • Port Forwarding (Tunneling): Allows you to securely forward network traffic from one machine to another through the SSH connection.

Commands / Usage

Connecting to a Remote Server

Basic Connection:

ssh user@hostname

Connects to hostname as user. You’ll be prompted for a password or use keys.

Connection with Specific Port:

ssh -p 2222 user@hostname

Connects to hostname on port 2222 as user.

Connection with Identity File (Private Key):

ssh -i ~/.ssh/id_rsa_prod user@hostname

Connects using the private key located at ~/.ssh/id_rsa_prod for authentication.

Connection with Verbose Output (Debugging):

ssh -v user@hostname

Shows detailed debugging information about the connection process. Use -vv or -vvv for even more detail.

Connection with KeepAlive:

ssh -o ServerAliveInterval=60 user@hostname

Sends a "keep-alive" message every 60 seconds to prevent the connection from timing out due to inactivity.

Connection with Specific SSH Configuration:

ssh -F ~/.ssh/config_prod user@hostname

Uses the SSH configuration file located at ~/.ssh/config_prod instead of the default ~/.ssh/config.

Executing Commands Remotely

Single Command Execution:

ssh user@hostname 'ls -l /home/user'

Connects to hostname, executes ls -l /home/user, prints the output, and disconnects.

Multiple Commands (using semicolon):

ssh user@hostname 'cd /var/www/html; git pull; systemctl restart apache2'

Executes a sequence of commands on the remote server.

Executing a Local Script Remotely:

ssh user@hostname 'bash -s' < /path/to/local/script.sh

Sends the content of script.sh to the remote server’s standard input and executes it using bash.

File Transfers (SCP - Secure Copy)

Copying a File from Local to Remote:

scp /path/to/local/file.txt user@hostname:/path/to/remote/directory/

Copies file.txt from your local machine to the specified directory on the remote server.

Copying a File from Remote to Local:

scp user@hostname:/path/to/remote/file.txt /path/to/local/directory/

Copies file.txt from the remote server to your local machine.

Copying a Directory Recursively (Local to Remote):

scp -r /path/to/local/directory/ user@hostname:/path/to/remote/parent/

Copies the entire local directory and its contents to the remote server.

Copying a Directory Recursively (Remote to Local):

scp -r user@hostname:/path/to/remote/directory/ /path/to/local/parent/

Copies the entire remote directory and its contents to your local machine.

Copying with Specific Port and Identity File:

scp -P 2222 -i ~/.ssh/id_rsa_prod /path/to/local/file.txt user@hostname:/path/to/remote/

Uses port 2222, the specified private key, and copies the file. Note: -P (uppercase) for port with scp, -p (lowercase) for preserving modification times with scp.

SSH Configuration File (~/.ssh/config)

This file allows you to define aliases and default settings for hosts.

Example ~/.ssh/config:

Host production
    HostName 192.168.1.100
    User deployer
    Port 2200
    IdentityFile ~/.ssh/deploy_key_prod

Host staging
    HostName staging.example.com
    User admin
    ForwardAgent yes

Host github.com
    IdentityFile ~/.ssh/github_id_rsa

Usage with Config:

ssh production
# Connects to 192.168.1.100 as deployer on port 2200 using ~/.ssh/deploy_key_prod

ssh staging
# Connects to staging.example.com as admin, forwarding your local SSH agent

git clone git@github.com:user/repo.git
# Uses ~/.ssh/github_id_rsa for authentication with GitHub

SSH Agent (for key management)

Start the SSH Agent:

eval "$(ssh-agent -s)"

Starts the agent and sets environment variables.

Add a Private Key to the Agent:

ssh-add ~/.ssh/id_rsa_prod

Adds your private key to the running agent. You’ll be prompted for the key’s passphrase if it has one.

List Keys in the Agent:

ssh-add -l

Shows the fingerprints of keys currently loaded in the agent.

Port Forwarding (Tunneling)

Local Port Forwarding (-L): Forward a local port to a remote service accessible from the server.

ssh -L 8080:localhost:80 user@remote-server.com

Connects to remote-server.com. Any traffic sent to your local port 8080 will be forwarded to port 80 on remote-server.com. Useful for accessing web interfaces running on a server that aren’t directly exposed.

Remote Port Forwarding (-R): Forward a port on the remote server to a local service.

ssh -R 9090:localhost:3000 user@remote-server.com

Connects to remote-server.com. Any traffic sent to port 9090 on remote-server.com will be forwarded to port 3000 on your local machine. Useful for exposing a local development server to the outside world via a remote server.

Dynamic Port Forwarding (SOCKS Proxy) (-D): Create a SOCKS proxy on your local machine.

ssh -D 1080 user@remote-server.com

Connects to remote-server.com. Configure your browser or application to use localhost:1080 as a SOCKS proxy. All traffic routed through this proxy will exit from remote-server.com.

SSH Keys Management

Generate SSH Key Pair:

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Creates a new SSH key pair (id_rsa and id_rsa.pub by default). -t specifies the type (e.g., rsa, ed25519), -b specifies the bit size, -C adds a comment.

Copy Public Key to Remote Server:

ssh-copy-id user@hostname

Appends your default public key (~/.ssh/id_rsa.pub) to the remote user’s ~/.ssh/authorized_keys file. You’ll be prompted for the user’s password.

Copy Public Key to Remote Server (Specific Key):

ssh-copy-id -i ~/.ssh/my_other_key.pub user@hostname

Copies the specified public key.

Manually Add Public Key to authorized_keys:

  1. Copy the content of your local ~/.ssh/id_rsa.pub file.
  2. SSH into the remote server using password authentication.
  3. Create the ~/.ssh directory if it doesn’t exist: mkdir -p ~/.ssh
  4. Set correct permissions: chmod 700 ~/.ssh
  5. Append the public key content to ~/.ssh/authorized_keys: echo "ssh-rsa AAAAB3NzaC1yc2E..." >> ~/.ssh/authorized_keys
  6. Set correct permissions: chmod 600 ~/.ssh/authorized_keys

Other Useful Flags

  • -A: Enable agent forwarding. Allows you to use your local SSH keys on intermediate servers without copying them. Use with caution.
  • -X / -Y: Enable X11 forwarding. Allows you to run graphical applications on the remote server and display them on your local machine. -Y is generally preferred for trusted connections.
  • -N: Do not execute a remote command. Useful for just setting up port forwarding.
  • -f: Requests ssh to go to background just before command execution. Useful when used with port forwarding.
  • -t: Force pseudo-terminal allocation. Often needed when running interactive commands or scripts that expect a TTY.

Common Patterns

Transferring a directory using tar and ssh:

tar czf - /path/to/local/directory | ssh user@hostname 'tar xzf - -C /path/to/remote/destination'

Compresses a local directory, pipes it over SSH, and uncompresses it on the remote server. Faster than scp -r for large directories.

Syncing directories using rsync over SSH:

rsync -avz -e "ssh -p 2222 -i ~/.ssh/id_rsa_prod" /path/to/local/source/ user@hostname:/path/to/remote/destination/

Efficiently synchronizes files and directories. -a archive mode, -v verbose, -z compress, -e specifies the remote shell command.

Executing a local script on a remote server and capturing output:

REMOTE_USER="user"
REMOTE_HOST="hostname"
LOCAL_SCRIPT="/path/to/local/script.sh"

ssh ${REMOTE_USER}@${REMOTE_HOST} 'bash -s' < ${LOCAL_SCRIPT} > /tmp/remote_output.log

Setting up a persistent SSH tunnel for database access:

ssh -f -N -L 5432:localhost:5432 user@db-server.com

Runs in the background (-f -N) and forwards local port 5432 (PostgreSQL default) to the remote database port 5432. You can then connect your local DB client to localhost:5432.

Disabling password authentication and enabling key-only auth:

  1. Generate keys and copy the public key to the server (ssh-keygen, ssh-copy-id).
  2. Test key authentication: ssh user@hostname.
  3. Edit the SSH server configuration on the remote machine: sudo nano /etc/ssh/sshd_config.
  4. Set PasswordAuthentication no.
  5. Restart the SSH service: sudo systemctl restart sshd (or sudo service ssh restart).

Gotchas

  • Permissions on ~/.ssh and authorized_keys: Incorrect permissions (e.g., world-writable) on your local ~/.ssh directory, private key files, or the remote ~/.ssh directory and authorized_keys file will cause SSH to refuse authentication. They should typically be 700 for directories and 600 for files.
  • ssh-agent not running or key not added: If you get "Permission denied (publickey)" errors even with keys set up, ensure ssh-agent is running and your key has been added using ssh-add.
  • Firewall issues: Ensure the SSH port (default 22) is open on the server’s firewall and any intermediate network firewalls.
  • Host Key Verification: The first time you connect to a server, SSH will ask you to verify the server’s host key. If this prompt appears unexpectedly later, it might indicate a man-in-the-middle attack or that the server’s IP has been reassigned.
  • Agent Forwarding (-A): While convenient, agent forwarding can be a security risk if the remote host is compromised. An attacker on the remote host could potentially use your forwarded agent connection to access other servers you have access to.
  • scp vs rsync: scp copies files directly. rsync is more efficient for repeated transfers or large files/directories as it only transfers differences.
  • Pseudo-terminal allocation (-t): Some commands or scripts require a TTY (terminal). If a remote command fails unexpectedly, try adding the -t flag (e.g., ssh -t user@host 'sudo apt update').