SSH
SSH Protocol Overview
Section titled “SSH Protocol Overview”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)"]Transport Layer
Section titled “Transport Layer”- 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
Authentication Layer
Section titled “Authentication Layer”- Password authentication
- Public key authentication (default preferred method)
- Keyboard-interactive (PAM, 2FA, OTP)
- GSSAPI (Kerberos)
- Host-based authentication
Connection Layer
Section titled “Connection Layer”- Multiplexed channels over a single TCP connection
- Session channels (shell, exec, subsystem)
- Port forwarding channels
- X11 forwarding
- Agent forwarding
- SFTP subsystem
Client Configuration
Section titled “Client Configuration”~/.ssh/config
Section titled “~/.ssh/config”The SSH client configuration file supports per-host settings, pattern matching, and conditional Blocks.
# Global defaultsHost * 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 hostHost 10.0.0.* ProxyJump bastion User admin IdentityFile ~/.ssh/id_internal
# Specific serverHost web-prod HostName 10.0.0.10 User www ProxyJump bastion ForwardAgent yes
# GitHubHost github.com HostName github.com User git IdentityFile ~/.ssh/id_github IdentitiesOnly yesMatch Blocks (Conditional Configuration)
Section titled “Match Blocks (Conditional Configuration)”Host * User admin
# Override for specific hostsMatch 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 userMatch host * user root PermitTTY no ForwardAgent no
# Match on destination portMatch host * port 2222 User jumpuserCommon Client Options
Section titled “Common Client Options”HostName # actual hostname (not the alias)User # login usernamePort # SSH port (default 22)IdentityFile # path to private key fileIdentitiesOnly # 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 secondsServerAliveCountMax # max missed keepalives before disconnectTCPKeepAlive # enable TCP keepalive (default yes)Compression # enable compression (yes/no)ControlMaster # connection multiplexing (yes/no/ask/auto)ControlPath # socket path for multiplexed connectionsControlPersist # how long to keep master connection openStrictHostKeyChecking # (yes/no/accept-new/ask)UserKnownHostsFile # path to known_hosts fileLogLevel # (QUIET/FATAL/ERROR/INFO/VERBOSE/DEBUG)NumberOfPasswordPrompts # max password prompts (default 3)Connection Multiplexing
Section titled “Connection Multiplexing”# Enable connection sharing in ~/.ssh/configHost * ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 600
# Create socket directorymkdir -p ~/.ssh/sockets
# First connection opens a master socketssh server.example.com
# Subsequent connections reuse the existing socket (instant!)ssh server.example.com # reuses existing connectionscp file server.example.com:/tmp/ # also reusesKey Management
Section titled “Key Management”ssh-keygen
Section titled “ssh-keygen”# 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 keyssh-keygen -t ecdsa -b 521 -C "user@workstation"
# Specify output filessh-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 keyssh-keygen -p -f ~/.ssh/id_ed25519
# Generate public key from private keyssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub
# Generate fingerprintssh-keygen -l -f ~/.ssh/id_ed25519.pub
# Generate visual fingerprint (randomart)ssh-keygen -lv -f ~/.ssh/id_ed25519.pubKey Formats
Section titled “Key Formats”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 systemsauthorized_keys
Section titled “authorized_keys”# ~/.ssh/authorized_keys — one public key per line# Format: [options] key-type base64-key [comment]
# Restrict key to specific commandcommand="/usr/bin/backup.sh",no-port-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAA... backup@server
# Restrict by source IPfrom="10.0.0.0/24" ssh-ed25519 AAAA... admin@office
# Disable specific forwardingno-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... restricted
# Combined restrictionscommand="/usr/local/bin/monitor",from="10.0.0.50",no-pty,no-port-forwarding ssh-ed25519 AAAA... monitor
# Restrict to specific environment variablesenvironment="PATH=/usr/bin:/bin" ssh-ed25519 AAAA... env-user# Deploy public key to remote serverssh-copy-id user@server.example.com
# Manual deploymentcat ~/.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 restrictionscat ~/.ssh/authorized_keysKey Rotation
Section titled “Key Rotation”# Generate new keyssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_new -C "user@workstation"
# Deploy new keyssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@server
# Test new keyssh -i ~/.ssh/id_ed25519_new user@server
# Remove old key from authorized_keys on serverssh user@server "sed -i "/OLD_KEY_COMMENT/d" ~/.ssh/authorized_keys"
# Update local configsed -i 's/id_ed25519/id_ed25519_new/' ~/.ssh/config
# Remove old keyrm ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pubServer Configuration
Section titled “Server Configuration”sshd_config
Section titled “sshd_config”# NetworkPort 22AddressFamily inet # inet (IPv4 only), inet6, anyListenAddress 0.0.0.0ListenAddress ::
# Host keysHostKey /etc/ssh/ssh_host_ed25519_keyHostKey /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
# CiphersCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
# MACsMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# AuthenticationPermitRootLogin prohibit-password # yes/no/prohibit-password/forced-commands-onlyPubkeyAuthentication yesPasswordAuthentication noPermitEmptyPasswords noChallengeResponseAuthentication noKbdInteractiveAuthentication noUsePAM no
# Authorized keys locationAuthorizedKeysFile .ssh/authorized_keysAuthorizedPrincipalsFile none
# Access controlAllowUsers deploy admin@10.0.0.0/24# AllowGroups ssh-users# DenyUsers baduser# DenyGroups nogroup
# SessionMaxAuthTries 3MaxSessions 10LoginGraceTime 30ClientAliveInterval 300ClientAliveCountMax 2X11Forwarding noAllowTcpForwarding yesPermitTunnel noPermitTTY yes
# SecurityStrictModes yes # check file permissions on key filesPermitRootLogin prohibit-passwordAllowAgentForwarding noAllowTcpForwarding no # disable if not needed
# LoggingSyslogFacility AUTHLogLevel VERBOSE
# BannerBanner /etc/ssh/banner
# SubsystemsSubsystem sftp /usr/lib/openssh/sftp-server# or for chrooted SFTP:# Subsystem sftp internal-sftpHost Key Management
Section titled “Host Key Management”# Generate host keysssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_keyssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key
# Show host key fingerprintsssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# Verify server fingerprint from clientssh-keyscan server.example.com | ssh-keygen -lf -Restart and Test
Section titled “Restart and Test”# Validate configuration before restartingsshd -tsshd -T # show effective configuration
# Restartsystemctl restart sshd
# Check statussystemctl status sshdsystemctl is-active sshdSSH Agent
Section titled “SSH Agent”ssh-agent
Section titled “ssh-agent”# Start the agenteval $(ssh-agent)ssh-agent bash # start a shell with agent
# Add keys to the agentssh-add # add default keysssh-add ~/.ssh/id_ed25519 # add specific keyssh-add -l # list keys in agentssh-add -L # list public keysssh-add -d ~/.ssh/id_ed25519 # remove specific keyssh-add -D # remove all keys
# Add key with limited lifetimessh-add -t 3600 ~/.ssh/id_ed25519 # 1 hourssh-add -t 8h ~/.ssh/id_ed25519 # 8 hours
# Lock agentssh-add -x # lock with password promptAgent Forwarding
Section titled “Agent Forwarding”# Enable forwarding per-host in ~/.ssh/configHost server ForwardAgent yes
# Or via command linessh -A user@server
# Or via ProxyJump (forward agent through jump host)Host internal ProxyJump bastion ForwardAgent yes