SSH Commands Reference

Essential SSH commands for key management, certificate authentication, tunneling, and secure access

🔑 SSH Key Generation

Generate Ed25519 key pair (recommended)

ssh-keygen -t ed25519 -C "[email protected]"

Ed25519 is faster, more secure, and uses smaller keys than RSA. Recommended for all new deployments. Not supported on very old systems (OpenSSH < 6.5).

Generate RSA key pair (4096-bit)

ssh-keygen -t rsa -b 4096 -C "[email protected]"

RSA 4096-bit is widely compatible and secure. Use when Ed25519 is not supported by the target system.

Generate ECDSA key pair

ssh-keygen -t ecdsa -b 521 -C "[email protected]"

ECDSA with 521-bit curve (NIST P-521). Valid sizes are 256, 384, and 521. Prefer Ed25519 when possible.

Generate key with custom filename

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github -C "github_key"

Specify output filename with -f. Useful for maintaining separate keys per service.

Generate key without passphrase (automation only)

ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_automation -C "automation_key"

Only use for automation where passphrase prompts are not possible. Restrict key permissions and limit authorized_keys options.

📜 SSH Certificates

Generate an SSH Certificate Authority (CA) key pair

# Create a CA key for signing user certificates
ssh-keygen -t ed25519 -f ~/.ssh/ca_user_key -C "SSH User CA"

# Create a CA key for signing host certificates
ssh-keygen -t ed25519 -f ~/.ssh/ca_host_key -C "SSH Host CA"

SSH certificates use a CA model similar to TLS. The CA key signs user or host public keys to produce short-lived certificates that replace authorized_keys and known_hosts management.

Sign a user public key (issue user certificate)

ssh-keygen -s ~/.ssh/ca_user_key -I "user_jane" -n jane,root \
  -V +52w ~/.ssh/id_ed25519.pub

Signs the user key with the CA. -I sets the key identity (logged on the server), -n specifies allowed principals (usernames), -V sets validity period (here, 52 weeks). Produces id_ed25519-cert.pub.

Sign a host public key (issue host certificate)

ssh-keygen -s ~/.ssh/ca_host_key -I "host_web01" -h \
  -n web01.example.com,web01,10.0.1.5 \
  -V +52w /etc/ssh/ssh_host_ed25519_key.pub

The -h flag creates a host certificate. -n specifies valid hostnames and IPs the certificate covers. Clients trust this host without TOFU if they trust the CA.

View SSH certificate details

ssh-keygen -Lf ~/.ssh/id_ed25519-cert.pub

Displays the certificate type, public key, signing CA, key ID, serial, validity window, principals, and critical options/extensions.

Sign a key with restricted options

ssh-keygen -s ~/.ssh/ca_user_key -I "deploy_bot" -n deploy \
  -V +1d -O no-agent-forwarding -O no-port-forwarding \
  -O no-pty -O no-x11-forwarding \
  -O source-address=10.0.0.0/8 ~/.ssh/id_deploy.pub

Issue a highly restricted certificate: 1-day validity, no agent forwarding, no port forwarding, no PTY, no X11, and source IP restriction. Ideal for CI/CD and automation.

Sign with a serial number

ssh-keygen -s ~/.ssh/ca_user_key -I "user_jane" -n jane \
  -z 1001 -V +30d ~/.ssh/id_ed25519.pub

The -z flag sets a serial number for the certificate. Useful for tracking and revocation via a KRL (Key Revocation List).

Configure server to trust user CA

# On the SSH server, add to /etc/ssh/sshd_config:
TrustedUserCAKeys /etc/ssh/ca_user_key.pub

# Optionally, restrict principals via AuthorizedPrincipalsFile:
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u

Place the CA public key on the server. Any user certificate signed by this CA will be accepted. AuthorizedPrincipalsFile controls which principals can log in as which user.

Configure client to trust host CA

# Add to ~/.ssh/known_hosts or /etc/ssh/ssh_known_hosts:
@cert-authority *.example.com ssh-ed25519 AAAA...CA_PUBLIC_KEY...

Clients that trust this CA will accept any host certificate signed by it for matching hosts, eliminating TOFU (Trust On First Use) warnings.

Configure server to present host certificate

# On the SSH server, add to /etc/ssh/sshd_config:
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub

The server presents its host certificate during the handshake. Clients verify it against their trusted host CA.

Create a Key Revocation List (KRL)

# Revoke by serial number
ssh-keygen -k -f /etc/ssh/revoked_keys -s ~/.ssh/ca_user_key -z 1001

# Revoke by public key
ssh-keygen -k -f /etc/ssh/revoked_keys ~/.ssh/compromised_key.pub

# Update an existing KRL
ssh-keygen -k -u -f /etc/ssh/revoked_keys -z 1002

# Test if a key is revoked
ssh-keygen -Qf /etc/ssh/revoked_keys ~/.ssh/id_ed25519.pub

KRLs provide compact, efficient certificate revocation. Configure on the server with RevokedKeys /etc/ssh/revoked_keys in sshd_config.

🔧 SSH Key Management

Display public key

cat ~/.ssh/id_ed25519.pub

Copy public key to clipboard (macOS)

pbcopy < ~/.ssh/id_ed25519.pub

Copy public key to clipboard (Linux with xclip)

xclip -sel clip < ~/.ssh/id_ed25519.pub

Change key passphrase

ssh-keygen -p -f ~/.ssh/id_ed25519

Show key fingerprint

ssh-keygen -lf ~/.ssh/id_ed25519.pub

Displays the key fingerprint in SHA256 format by default.

Show key fingerprint in MD5 format

ssh-keygen -lf ~/.ssh/id_ed25519.pub -E md5

Show key fingerprint as ASCII art

ssh-keygen -lvf ~/.ssh/id_ed25519.pub

Convert OpenSSH key to PEM format

ssh-keygen -p -m PEM -f ~/.ssh/id_rsa

Converts the private key to PEM format in-place. Useful for compatibility with older tools that do not support the OpenSSH format.

Export public key in RFC 4716 format

ssh-keygen -e -m RFC4716 -f ~/.ssh/id_ed25519.pub

Exports the public key in RFC 4716 (SSH2) format. Other formats: PKCS8, PEM.

Import key from RFC 4716 format

ssh-keygen -i -m RFC4716 -f key_rfc4716.pub

Converts an RFC 4716 public key to OpenSSH format. Also accepts PKCS8 and PEM input formats.

📤 Copying Keys to Servers

Copy public key to server (recommended)

ssh-copy-id [email protected]

Automatically adds your public key to the server's authorized_keys file with correct permissions.

Copy specific key to server

ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

Copy key to server on non-standard port

ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 [email protected]

Manual method (if ssh-copy-id not available)

cat ~/.ssh/id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Set correct permissions on server

ssh [email protected] "chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"

🌐 Connecting to Servers

Basic SSH connection

ssh [email protected]

Connect with specific key

ssh -i ~/.ssh/id_ed25519 [email protected]

Connect to non-standard port

ssh -p 2222 [email protected]

Connect through a jump host (ProxyJump)

# Single jump host
ssh -J bastion.example.com [email protected]

# Multiple jump hosts (chained)
ssh -J bastion1.example.com,bastion2.example.com [email protected]

# Jump host with different user/port
ssh -J jumpuser@bastion:2222 [email protected]

ProxyJump (-J) is the modern replacement for ProxyCommand. Available since OpenSSH 7.3.

Execute single command on remote server

ssh [email protected] "ls -la /var/www"

Connect with verbose output (debugging)

ssh -v [email protected]

Use -vv or -vvv for increasingly verbose output. Shows key negotiation, authentication attempts, and cipher selection.

Connect with X11 forwarding

# Untrusted X11 forwarding (safer, some apps may not work)
ssh -X [email protected]

# Trusted X11 forwarding (full access to local X display)
ssh -Y [email protected]

Forwards graphical applications from the remote server to your local display. Requires an X server on the client.

Connect with compression

ssh -C [email protected]

Enables compression. Beneficial for slow connections; can reduce performance on fast networks.

Force password authentication (skip keys)

ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no [email protected]

Useful for debugging when key-based authentication is failing and you need to connect via password.

Connect without checking host key (use with caution)

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected]

Disables host key verification. Only for ephemeral environments (Docker, CI) -- never for production.

🔀 Port Forwarding and Tunneling

Local port forwarding

ssh -L 8080:localhost:80 [email protected]

Forwards local port 8080 to port 80 on the remote server. Access the remote service at localhost:8080.

Local forwarding to a third-party host via SSH server

ssh -L 5432:internal-db.corp:5432 [email protected]

Access internal-db.corp:5432 through the jump host. The SSH server connects to the target on your behalf.

Remote port forwarding

ssh -R 8080:localhost:3000 [email protected]

Makes your local port 3000 accessible on the remote server's port 8080. Useful for exposing local development servers.

Remote forwarding accessible on all interfaces

ssh -R 0.0.0.0:8080:localhost:3000 [email protected]

By default, remote forwarding binds to 127.0.0.1 only. Binding to 0.0.0.0 requires GatewayPorts yes in the server's sshd_config.

Dynamic port forwarding (SOCKS proxy)

ssh -D 1080 [email protected]

Creates a SOCKS5 proxy on local port 1080. Configure your browser or application to use localhost:1080 as a SOCKS proxy.

Background tunnel (no shell)

ssh -f -N -L 8080:localhost:80 [email protected]

-f backgrounds the SSH process after authentication, -N prevents executing remote commands. Use kill to terminate.

Multiple tunnels in a single connection

ssh -L 8080:localhost:80 -L 8443:localhost:443 \
  -L 5432:db.internal:5432 [email protected]

Chain multiple -L, -R, and -D flags in a single SSH session.

🛡️ SSH Agent and Agent Forwarding

Start SSH agent

eval "$(ssh-agent -s)"

Add key to SSH agent

ssh-add ~/.ssh/id_ed25519

Add key with timeout

ssh-add -t 3600 ~/.ssh/id_ed25519

Key will be removed from agent after 3600 seconds (1 hour). Limits exposure if your agent is compromised.

List keys in agent

ssh-add -l

Remove specific key from agent

ssh-add -d ~/.ssh/id_ed25519

Remove all keys from agent

ssh-add -D

Add key to macOS keychain

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

Stores passphrase in macOS Keychain. Add UseKeychain yes and AddKeysToAgent yes to ~/.ssh/config to persist across reboots.

Connect with agent forwarding

ssh -A [email protected]

Forwards your local SSH agent to the remote host, allowing authentication from there using your local keys. Security warning: a root user on the remote host can use your forwarded agent. Only use with trusted servers. Prefer ProxyJump instead.

⚙️ SSH Configuration (~/.ssh/config)

Basic host configuration

Host myserver
    HostName server.example.com
    User myusername
    IdentityFile ~/.ssh/id_ed25519

Then connect simply with: ssh myserver

Host with non-standard port

Host myserver
    HostName server.example.com
    Port 2222
    User myusername

Jump host (bastion) configuration

Host bastion
    HostName bastion.example.com
    User jump_user

Host internal-server
    HostName 10.0.1.100
    User myusername
    ProxyJump bastion

ProxyJump replaces the older ProxyCommand ssh -W %h:%p bastion method. SCP, SFTP, and rsync also work through ProxyJump automatically.

Connection multiplexing (ControlMaster)

Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

Reuses a single TCP connection for multiple SSH sessions to the same host. The first connection authenticates; subsequent connections are instant. ControlPersist 600 keeps the master open for 10 minutes after the last session exits. Create the directory: mkdir -p ~/.ssh/sockets

Keep connections alive

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Sends keepalive packets every 60 seconds. Disconnects after 3 missed responses (3 minutes of no connectivity).

GitHub SSH configuration

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

IdentitiesOnly yes prevents the SSH client from trying all keys in the agent, using only the specified key.

Wildcard configuration with security defaults

Host *
    IdentitiesOnly yes
    HashKnownHosts yes
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

HashKnownHosts hashes hostnames in known_hosts to prevent disclosure if the file is leaked. AddKeysToAgent automatically loads keys into the agent upon first use.

Certificate-based host configuration

Host *.example.com
    CertificateFile ~/.ssh/id_ed25519-cert.pub
    IdentityFile ~/.ssh/id_ed25519
    User myusername

Explicitly specify the certificate file to present alongside the private key for SSH certificate authentication.

🔍 Known Hosts and Host Key Verification

Scan and display host keys

# Scan all host key types
ssh-keyscan server.example.com

# Scan specific key type
ssh-keyscan -t ed25519 server.example.com

# Scan non-standard port
ssh-keyscan -p 2222 server.example.com

Retrieves public host keys from a server. Useful for pre-populating known_hosts in automated environments.

Add host key to known_hosts

ssh-keyscan -t ed25519 server.example.com >> ~/.ssh/known_hosts

Pre-populate known_hosts to avoid TOFU prompts. Verify the fingerprint through a trusted channel first.

Remove a host from known_hosts

# Remove by hostname
ssh-keygen -R server.example.com

# Remove by IP address
ssh-keygen -R 10.0.1.5

# Remove host on non-standard port
ssh-keygen -R "[server.example.com]:2222"

Required when a server's host key changes legitimately (e.g., after OS reinstallation).

Find a host in known_hosts

ssh-keygen -F server.example.com

Search known_hosts for a specific host. Works even with hashed hostnames.

Hash all hostnames in known_hosts

ssh-keygen -H

Hashes all plaintext hostnames in ~/.ssh/known_hosts. Prevents an attacker from identifying which hosts you connect to if the file is compromised.

Get the fingerprint of a remote host key

ssh-keyscan -t ed25519 server.example.com | ssh-keygen -lf -

Fetches the host key and displays its fingerprint in one step. Compare against a known-good fingerprint to verify server identity.

⌨️ SSH Escape Sequences

Escape sequences (press after newline)

~.     Disconnect (kill hung session)
~^Z    Suspend SSH session (fg to resume)
~#     List forwarded connections
~&     Background SSH when waiting for connections to close
~?     Display list of escape sequences
~C     Open command line to add/remove port forwards
~R     Request rekeying (re-exchange session keys)

Escape sequences must be typed at the start of a new line. ~. is essential for terminating frozen sessions. ~C allows adding port forwards (-L, -R, -D) on the fly without reconnecting.

🔒 Security and Server Hardening

Correct file permissions

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/config

Incorrect permissions are a common cause of SSH authentication failures. SSH refuses to use keys or config files that are world-readable.

Harden sshd_config (server-side)

# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
X11Forwarding no
AllowTcpForwarding no
PermitEmptyPasswords no
ClientAliveInterval 300
ClientAliveCountMax 2

Restart SSH after editing: sudo systemctl restart sshd. Always test from a second terminal before closing your active session.

Restrict ciphers and algorithms (server-side)

# /etc/ssh/sshd_config - Modern secure defaults
KexAlgorithms [email protected],curve25519-sha256,[email protected]
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
HostKeyAlgorithms ssh-ed25519,[email protected]

Restrict to modern, secure algorithms. Removes legacy ciphers like CBC and weak MACs. Test connectivity with ssh -v before applying in production.

Limit SSH access to specific users or groups

# Add to /etc/ssh/sshd_config
AllowUsers user1 user2 user3
# Or restrict by group
AllowGroups ssh-users

Restrict authorized_keys options

# In ~/.ssh/authorized_keys, prefix the key:
from="10.0.0.0/8",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="/usr/local/bin/backup.sh" ssh-ed25519 AAAA...

Restrict a key to specific source IPs, disable forwarding, and force a specific command. Essential for automation keys.

Check which key is being used (debugging)

ssh -v [email protected] 2>&1 | grep "Offering public key"

# Or check which key was accepted
ssh -v [email protected] 2>&1 | grep "Accepted"

Test SSH connection to GitHub

ssh -T [email protected]

Tests SSH authentication to GitHub without opening a shell. GitHub will respond with your username if successful.

💡 Common Use Cases

Set up SSH for GitHub

# Generate key
ssh-keygen -t ed25519 -C "[email protected]"

# Start agent and add key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Copy public key
cat ~/.ssh/id_ed25519.pub
# Add to GitHub Settings > SSH Keys

# Test connection
ssh -T [email protected]

Access remote database through SSH tunnel

# Create tunnel
ssh -L 5432:localhost:5432 [email protected]

# In another terminal, connect to local port
psql -h localhost -p 5432 -U dbuser dbname

Mount remote directory locally (SSHFS)

# Mount
sshfs [email protected]:/remote/path /local/mount/point

# Unmount
fusermount -u /local/mount/point  # Linux
umount /local/mount/point         # macOS

Execute local script on remote server

ssh [email protected] 'bash -s' < local-script.sh

SSH certificate workflow for a new team member

# 1. Team member generates their key pair
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519

# 2. CA admin signs their public key
ssh-keygen -s /secure/ca_user_key -I "user_newdev" \
  -n newdev -V +90d ~/.ssh/id_ed25519.pub

# 3. Team member receives the cert and connects
# (server already has TrustedUserCAKeys configured)
ssh [email protected]

No need to add public keys to every server's authorized_keys. The certificate expires automatically after 90 days.

Keep SSH session alive when closing terminal

# Use tmux or screen
ssh [email protected]
tmux
# Your work here
# Ctrl+b then d to detach
# Later: tmux attach to resume