Skip to content

SSH | Linux - Wyatt's Notes

SSH (Secure Shell) protocol version 2 provides encrypted remote login and command execution. The Protocol operates in three layers:

flowchart TD
A["Transport Layer<br />(TCP/IP, encryption, server auth)"] --> B["Authentication Layer<br />(password, key, keyboard-interactive)"]
B --> C["Connection Layer<br />(channels, forwarding, X11, SFTP)"]
  • TCP connection (default port 22)
  • Server presents host key for verification
  • Key exchange (curve25519-sha256, ecdh-sha2-nistp256, diffie-hellman-group14-sha256)
  • Symmetric encryption (chacha20-poly1305, aes256-gcm)
  • MAC / AEAD for integrity
  • Session keys derived from shared secret
  • Password authentication
  • Public key authentication (default preferred method)
  • Keyboard-interactive (PAM, 2FA, OTP)
  • GSSAPI (Kerberos)
  • Host-based authentication
  • Multiplexed channels over a single TCP connection
  • Session channels (shell, exec, subsystem)
  • Port forwarding channels
  • X11 forwarding
  • Agent forwarding
  • SFTP subsystem

The SSH client configuration file supports per-host settings, pattern matching, and conditional Blocks.

## ~/.ssh/config
## Global defaults
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
StrictHostKeyChecking accept-new
UserKnownHostsFile ~/.ssh/known_hosts
# Jump host (bastion)
Host bastion
HostName bastion.example.com
User deploy
Port 2222
IdentityFile ~/.ssh/id_bastion
# Internal servers via jump host
Host 10.0.0.*
ProxyJump bastion
User admin
IdentityFile ~/.ssh/id_internal
# Specific server
Host web-prod
HostName 10.0.0.10
User www
ProxyJump bastion
ForwardAgent yes
# GitHub
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_github
IdentitiesOnly yes
~/.ssh/config
Host *
User admin
# Override for specific hosts
Match host 10.0.0.* exec "ping -c 1 -W 1 %h"
ProxyJump bastion
# Match on original host (useful with ProxyJump)
Match host bastion.example.com
ForwardAgent yes
# Match on local user
Match host * user root
PermitTTY no
ForwardAgent no
# Match on destination port
Match host * port 2222
User jumpuser
HostName # actual hostname (not the alias)
User # login username
Port # SSH port (default 22)
IdentityFile # path to private key file
IdentitiesOnly # only use explicitly specified keys (default no)
ProxyJump # jump host (simpler than ProxyCommand)
ProxyCommand # custom command for connection (more flexible)
ForwardAgent # forward SSH agent (yes/no/ask)
ForwardX11 # forward X11 (yes/no/ask)
LocalForward # local port forwarding (-L)
RemoteForward # remote port forwarding (-R)
DynamicForward # SOCKS proxy (-D)
ServerAliveInterval # send keepalive every N seconds
ServerAliveCountMax # max missed keepalives before disconnect
TCPKeepAlive # enable TCP keepalive (default yes)
Compression # enable compression (yes/no)
ControlMaster # connection multiplexing (yes/no/ask/auto)
ControlPath # socket path for multiplexed connections
ControlPersist # how long to keep master connection open
StrictHostKeyChecking # (yes/no/accept-new/ask)
UserKnownHostsFile # path to known_hosts file
LogLevel # (QUIET/FATAL/ERROR/INFO/VERBOSE/DEBUG)
NumberOfPasswordPrompts # max password prompts (default 3)
# Enable connection sharing in ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
# Create socket directory
mkdir -p ~/.ssh/sockets
# First connection opens a master socket
ssh server.example.com
# Subsequent connections reuse the existing socket (instant!)
ssh server.example.com # reuses existing connection
scp file server.example.com:/tmp/ # also reuses
Terminal window
# Generate Ed25519 key (recommended — small, fast, secure)
ssh-keygen -t ed25519 -C "user@workstation"
ssh-keygen -t ed25519 -a 100 -C "user@workstation" # 100 KDF rounds
# Generate RSA key (4096 bits, for legacy compatibility)
ssh-keygen -t rsa -b 4096 -C "user@workstation"
# Generate ECDSA key
ssh-keygen -t ecdsa -b 521 -C "user@workstation"
# Specify output file
ssh-keygen -t ed25519 -f ~/.ssh/id_github -C "github-key"
# Generate key with no passphrase (for automation — use with caution)
ssh-keygen -t ed25519 -f ~/.ssh/id_deploy -N ""
# Change passphrase on existing key
ssh-keygen -p -f ~/.ssh/id_ed25519
# Generate public key from private key
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub
# Generate fingerprint
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
# Generate visual fingerprint (randomart)
ssh-keygen -lv -f ~/.ssh/id_ed25519.pub
OpenSSH (default):
id_ed25519 — private key (OpenSSH format)
id_ed25519.pub — public key (single line)
PEM (legacy):
id_rsa — "BEGIN RSA PRIVATE KEY" (PEM format)
id_rsa.pub — public key
PKCS8:
Convert with: ssh-keygen -p -f id_rsa -m PEM # to PEM
Convert with: ssh-keygen -p -f id_rsa -m RFC4716 # to RFC4716
Ed25519 keys:
- Best security per bit
- Fastest key operations (sign/verify)
- Smallest key size (64 bytes)
- Recommended for all new keys
RSA keys:
- Minimum 2048 bits (2048 is weak, 3072 is acceptable, 4096 is standard)
- Slower than Ed25519
- Widely compatible with legacy systems
# ~/.ssh/authorized_keys — one public key per line
# Format: [options] key-type base64-key [comment]
# Restrict key to specific command
command="/usr/bin/backup.sh",no-port-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAA... backup@server
# Restrict by source IP
from="10.0.0.0/24" ssh-ed25519 AAAA... admin@office
# Disable specific forwarding
no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... restricted
# Combined restrictions
command="/usr/local/bin/monitor",from="10.0.0.50",no-pty,no-port-forwarding ssh-ed25519 AAAA... monitor
# Restrict to specific environment variables
environment="PATH=/usr/bin:/bin" ssh-ed25519 AAAA... env-user
Terminal window
# Deploy public key to remote server
ssh-copy-id user@server.example.com
# Manual deployment
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# View authorized_keys with restrictions
cat ~/.ssh/authorized_keys
Terminal window
# Generate new key
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_new -C "user@workstation"
# Deploy new key
ssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@server
# Test new key
ssh -i ~/.ssh/id_ed25519_new user@server
# Remove old key from authorized_keys on server
ssh user@server "sed -i "/OLD_KEY_COMMENT/d" ~/.ssh/authorized_keys"
# Update local config
sed -i 's/id_ed25519/id_ed25519_new/' ~/.ssh/config
# Remove old key
rm ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub
/etc/ssh/sshd_config
# Network
Port 22
AddressFamily inet # inet (IPv4 only), inet6, any
ListenAddress 0.0.0.0
ListenAddress ::
# Host keys
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
# Key exchange algorithms (drop weak ones)
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha256
# Ciphers
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
# MACs
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Authentication
PermitRootLogin prohibit-password # yes/no/prohibit-password/forced-commands-only
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM no
# Authorized keys location
AuthorizedKeysFile .ssh/authorized_keys
AuthorizedPrincipalsFile none
# Access control
AllowUsers deploy admin@10.0.0.0/24
# AllowGroups ssh-users
# DenyUsers baduser
# DenyGroups nogroup
# Session
MaxAuthTries 3
MaxSessions 10
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding yes
PermitTunnel no
PermitTTY yes
# Security
StrictModes yes # check file permissions on key files
PermitRootLogin prohibit-password
AllowAgentForwarding no
AllowTcpForwarding no # disable if not needed
# Logging
SyslogFacility AUTH
LogLevel VERBOSE
# Banner
Banner /etc/ssh/banner
# Subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# or for chrooted SFTP:
# Subsystem sftp internal-sftp
Terminal window
# Generate host keys
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key
# Show host key fingerprints
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# Verify server fingerprint from client
ssh-keyscan server.example.com | ssh-keygen -lf -
Terminal window
# Validate configuration before restarting
sshd -t
sshd -T # show effective configuration
# Restart
systemctl restart sshd
# Check status
systemctl status sshd
systemctl is-active sshd
Terminal window
# Start the agent
eval $(ssh-agent)
ssh-agent bash # start a shell with agent
# Add keys to the agent
ssh-add # add default keys
ssh-add ~/.ssh/id_ed25519 # add specific key
ssh-add -l # list keys in agent
ssh-add -L # list public keys
ssh-add -d ~/.ssh/id_ed25519 # remove specific key
ssh-add -D # remove all keys
# Add key with limited lifetime
ssh-add -t 3600 ~/.ssh/id_ed25519 # 1 hour
ssh-add -t 8h ~/.ssh/id_ed25519 # 8 hours
# Lock agent
ssh-add -x # lock with password prompt
Terminal window
# Enable forwarding per-host in ~/.ssh/config
Host server
ForwardAgent yes
# Or via command line
ssh -A user@server
# Or via ProxyJump (forward agent through jump host)
Host internal
ProxyJump bastion
ForwardAgent yes

Processes are programs in execution, each with its own memory space and priority. Systemd manages the lifecycle of services, starting them at boot and restarting them if they fail. Understanding process states (running, sleeping, stopped, zombie) helps you diagnose why a service is not responding. Signals like SIGTERM and SIGKILL provide graceful and forceful ways to control processes.