SSH: Secure Shell Protocol Complete Guide
SSH (Secure Shell) is a cryptographic network protocol for secure remote access, file transfer, and network services over unsecured networks. SSH has become the standard for secure remote administration, replacing insecure protocols like Telnet and rlogin. This comprehensive guide explains SSH, its features, configuration, and best practices.
What is SSH?
SSH is a protocol that provides secure encrypted communication between two computers over an insecure network. It uses strong cryptography to authenticate users and encrypt all traffic, including passwords, commands, and data.
SSH Basics
Protocol characteristics:
Layer: Application layer (Layer 7)
Transport: TCP
Port: 22 (default)
Encryption: Strong cryptography
Authentication: Multiple methods
Purpose: Remote access, file transfer, tunneling
SSH replaces:
Telnet: Unencrypted remote access
rlogin: Unencrypted remote login
rsh: Unencrypted remote shell
FTP: Unencrypted file transfer
Learn more about FTP and SSL/TLS.
SSH versions:
SSH-1: Original, deprecated (insecure)
SSH-2: Current standard, secure
Status: Only use SSH-2
How SSH Works
SSH Connection Process
Connection establishment:
1. Client connects to server (port 22)
2. Server sends public key
3. Client verifies server identity
4. Negotiate encryption algorithms
5. Establish encrypted connection
6. User authentication
7. Secure session established
Encryption layers:
Transport Layer:
- Server authentication
- Encryption
- Integrity
User Authentication Layer:
- Password
- Public key
- Keyboard-interactive
Connection Layer:
- Multiplexing
- Channel management
SSH Authentication Methods
Password authentication:
Process:
1. User enters password
2. Password sent encrypted
3. Server verifies password
4. Access granted or denied
Security: Weakest method
Risk: Brute force attacks
Recommendation: Disable for production
Public key authentication:
Process:
1. User has key pair (public/private)
2. Public key on server
3. Server sends challenge
4. Client signs with private key
5. Server verifies with public key
6. Access granted
Security: Strong
Advantages: No password transmission
Recommendation: Preferred method
Keyboard-interactive:
Process:
1. Server sends prompts
2. User responds
3. Can include multiple factors
4. Flexible authentication
Use cases:
- Two-factor authentication
- One-time passwords
- Custom challenges
Host-based authentication:
Process:
1. Client host authenticated
2. Based on host keys
3. User trusted from that host
Use: Automated systems
Security: Less common
SSH Key Management
Generating SSH Keys
RSA keys (traditional):
# Generate RSA key (2048-bit minimum, 4096-bit recommended)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# Output:
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/user/.ssh/id_rsa
Your public key has been saved in /home/user/.ssh/id_rsa.pub
Ed25519 keys (modern, recommended):
# Generate Ed25519 key (faster, more secure)
ssh-keygen -t ed25519 -C "your_email@example.com"
# Advantages:
- Smaller key size
- Faster
- More secure
- Modern standard
ECDSA keys:
# Generate ECDSA key
ssh-keygen -t ecdsa -b 521 -C "your_email@example.com"
# Note: Ed25519 preferred over ECDSA
Key files:
Private key: ~/.ssh/id_ed25519 (keep secret!)
Public key: ~/.ssh/id_ed25519.pub (share this)
Permissions: 600 for private, 644 for public
Deploying Public Keys
Copy to server:
# Easiest method
ssh-copy-id user@server.com
# Manual method
cat ~/.ssh/id_ed25519.pub | ssh user@server.com "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# Or copy-paste
cat ~/.ssh/id_ed25519.pub
# Copy output, then on server:
echo "paste-public-key-here" >> ~/.ssh/authorized_keys
Authorized keys file:
Location: ~/.ssh/authorized_keys
Permissions: 600
Format: One public key per line
Multiple keys:
# authorized_keys can contain multiple keys
ssh-rsa AAAAB3... user1@host1
ssh-ed25519 AAAAC3... user2@host2
ssh-rsa AAAAB3... user3@host3
Key Passphrases
Purpose:
Protect private key
Additional security layer
Required if key stolen
Using ssh-agent:
# Start ssh-agent
eval "$(ssh-agent -s)"
# Add key (enter passphrase once)
ssh-add ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# Remove all keys
ssh-add -D
Keychain (persistent):
# Install keychain
sudo apt install keychain
# Add to ~/.bashrc
eval $(keychain --eval id_ed25519)
# Keys loaded on login
SSH Client Usage
Basic Connection
Connect to server:
# Basic connection
ssh user@server.com
# Specify port
ssh -p 2222 user@server.com
# Specify key
ssh -i ~/.ssh/custom_key user@server.com
# Verbose output (debugging)
ssh -v user@server.com
ssh -vv user@server.com # More verbose
ssh -vvv user@server.com # Maximum verbosity
First connection:
The authenticity of host 'server.com (203.0.113.1)' can't be established.
ED25519 key fingerprint is SHA256:abc123...
Are you sure you want to continue connecting (yes/no)?
Type: yes
Result: Host added to ~/.ssh/known_hosts
SSH Config File
Location: ~/.ssh/config
Basic configuration:
Host myserver
HostName server.example.com
User alice
Port 22
IdentityFile ~/.ssh/id_ed25519
Host github
HostName github.com
User git
IdentityFile ~/.ssh/github_key
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
Usage:
# Instead of: ssh alice@server.example.com
ssh myserver
# Instead of: ssh git@github.com
ssh github
Advanced options:
Host production
HostName prod.example.com
User admin
Port 2222
IdentityFile ~/.ssh/prod_key
ForwardAgent yes
Compression yes
LogLevel INFO
Host *.internal
ProxyJump bastion.example.com
User internal_user
Remote Command Execution
Run single command:
# Execute command and exit
ssh user@server.com "ls -la"
# Multiple commands
ssh user@server.com "cd /var/log && tail -n 20 syslog"
# With sudo
ssh user@server.com "sudo systemctl restart nginx"
Script execution:
# Run local script on remote server
ssh user@server.com 'bash -s' < local_script.sh
# With arguments
ssh user@server.com 'bash -s' < script.sh arg1 arg2
Here document:
ssh user@server.com << 'EOF'
cd /var/www
git pull
npm install
pm2 restart app
EOF
SSH File Transfer
SCP (Secure Copy)
Upload file:
# Single file
scp file.txt user@server.com:/path/to/destination/
# Multiple files
scp file1.txt file2.txt user@server.com:/path/
# Directory (recursive)
scp -r directory/ user@server.com:/path/
Download file:
# Single file
scp user@server.com:/path/to/file.txt .
# Multiple files
scp user@server.com:/path/to/*.txt .
# Directory
scp -r user@server.com:/path/to/directory/ .
Options:
# Preserve timestamps and permissions
scp -p file.txt user@server.com:/path/
# Limit bandwidth (KB/s)
scp -l 1000 file.txt user@server.com:/path/
# Specify port
scp -P 2222 file.txt user@server.com:/path/
# Compression
scp -C largefile.tar user@server.com:/path/
SFTP (SSH File Transfer Protocol)
Interactive session:
# Connect
sftp user@server.com
# Commands
sftp> ls # List remote files
sftp> lls # List local files
sftp> pwd # Remote directory
sftp> lpwd # Local directory
sftp> cd /path # Change remote directory
sftp> lcd /path # Change local directory
sftp> get file.txt # Download file
sftp> put file.txt # Upload file
sftp> get -r directory/ # Download directory
sftp> put -r directory/ # Upload directory
sftp> mkdir newdir # Create remote directory
sftp> rm file.txt # Delete remote file
sftp> exit # Quit
Batch mode:
# Execute commands from file
sftp -b commands.txt user@server.com
# commands.txt:
cd /var/www
put index.html
put style.css
quit
rsync over SSH
Sync directories:
# Basic sync
rsync -avz /local/dir/ user@server.com:/remote/dir/
# Options:
-a: Archive mode (preserves permissions, timestamps)
-v: Verbose
-z: Compression
-P: Progress and partial transfers
--delete: Delete files not in source
# Exclude files
rsync -avz --exclude '*.log' /local/ user@server.com:/remote/
# Dry run (test)
rsync -avz --dry-run /local/ user@server.com:/remote/
Advantages over scp:
Only transfers changes
Resume capability
Compression
Exclude patterns
Preserves permissions
Faster for updates
SSH Tunneling and Port Forwarding
Local Port Forwarding
Forward local port to remote:
# Syntax
ssh -L local_port:destination:destination_port user@ssh_server
# Example: Access remote database
ssh -L 3306:localhost:3306 user@database-server.com
# Now connect to localhost:3306 → remote MySQL
# Access service on different host
ssh -L 8080:internal-server:80 user@bastion.com
# localhost:8080 → internal-server:80 via bastion
Use cases:
Access remote database
Bypass firewall
Secure unencrypted protocols
Access internal services
Remote Port Forwarding
Forward remote port to local:
# Syntax
ssh -R remote_port:destination:destination_port user@ssh_server
# Example: Share local web server
ssh -R 8080:localhost:80 user@public-server.com
# public-server.com:8080 → your localhost:80
# Expose local service
ssh -R 3000:localhost:3000 user@server.com
Use cases:
Expose local development server
Share local service temporarily
Bypass NAT/firewall
Remote access to local machine
Dynamic Port Forwarding (SOCKS Proxy)
Create SOCKS proxy:
# Start SOCKS proxy on local port
ssh -D 1080 user@server.com
# Configure browser/application to use:
SOCKS5 proxy: localhost:1080
# All traffic routed through SSH tunnel
Use cases:
Secure browsing on public WiFi
Bypass geographic restrictions
Encrypt all traffic
Access region-locked content
Browser configuration:
Firefox:
Settings → Network Settings → Manual proxy
SOCKS Host: localhost
Port: 1080
SOCKS v5: Yes
SSH Jump Host (ProxyJump)
Access through bastion:
# Old method
ssh -J bastion.com user@internal-server
# Or
ssh -o ProxyJump=bastion.com user@internal-server
# Multiple jumps
ssh -J bastion1.com,bastion2.com user@internal-server
Config file:
Host internal
HostName internal-server.local
User admin
ProxyJump bastion.example.com
SSH Server Configuration
Installation
Debian/Ubuntu:
sudo apt update
sudo apt install openssh-server
RHEL/CentOS:
sudo yum install openssh-server
Start service:
sudo systemctl start sshd
sudo systemctl enable sshd
Configuration File
Location: /etc/ssh/sshd_config
Basic hardening:
# Port (change from default)
Port 2222
# Protocol
Protocol 2
# Authentication
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
# Security
X11Forwarding no
MaxAuthTries 3
MaxSessions 10
LoginGraceTime 60
# Logging
SyslogFacility AUTH
LogLevel VERBOSE
# Allow specific users
AllowUsers alice bob
# Or allow specific groups
AllowGroups sshusers
Apply changes:
# Test configuration
sudo sshd -t
# Restart service
sudo systemctl restart sshd
Security Best Practices
1. Disable password authentication:
PasswordAuthentication no
ChallengeResponseAuthentication no
2. Disable root login:
PermitRootLogin no
3. Change default port:
Port 2222
# Security through obscurity (minor benefit)
# Reduces automated attacks
4. Limit users:
AllowUsers alice bob
# Or
AllowGroups sshusers
5. Use fail2ban:
# Install
sudo apt install fail2ban
# Configure /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
6. Two-factor authentication:
# Install Google Authenticator
sudo apt install libpam-google-authenticator
# Configure PAM
# /etc/pam.d/sshd
auth required pam_google_authenticator.so
# /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
7. Keep updated:
sudo apt update
sudo apt upgrade openssh-server
Advanced SSH Features
SSH Agent Forwarding
Purpose:
Use local SSH keys on remote servers
Access further servers without copying keys
Convenient for jump hosts
Enable:
# Command line
ssh -A user@server.com
# Config file
Host server
ForwardAgent yes
Security warning:
Risk: Admin on intermediate server can use your keys
Use: Only on trusted servers
Alternative: ProxyJump (more secure)
SSH Multiplexing
Purpose:
Reuse existing connection
Faster subsequent connections
Reduce overhead
Configuration:
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h:%p
ControlPersist 10m
Create socket directory:
mkdir -p ~/.ssh/sockets
Benefits:
First connection: Normal
Subsequent: Instant (reuses connection)
Persist: Stays open for 10 minutes
SSH Escape Sequences
During session:
~. : Disconnect
~^Z : Background SSH
~# : List forwarded connections
~& : Background SSH at logout
~? : Help
Usage:
Press Enter, then ~.
Immediately disconnects
Useful for hung connections
Troubleshooting SSH
Connection Issues
Connection refused:
Check: SSH service running
Check: Firewall rules
Check: Correct port
Test: telnet server.com 22
Connection timeout:
Check: Network connectivity
Check: Firewall blocking
Check: Server reachable
Test: ping server.com
Permission denied:
Check: Username correct
Check: Key permissions (600 for private)
Check: authorized_keys permissions (600)
Check: Home directory permissions (755)
Verbose: ssh -vvv user@server.com
Authentication Issues
Public key not working:
Check: Public key in authorized_keys
Check: File permissions
Check: SELinux (if enabled)
Check: sshd_config allows PubkeyAuthentication
Debug: ssh -vvv user@server.com
Permissions:
# Fix permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
Host key verification failed:
Warning: REMOTE HOST IDENTIFICATION HAS CHANGED!
Causes:
- Server reinstalled
- Man-in-the-middle attack
- IP address reused
Fix (if legitimate):
ssh-keygen -R server.com
# Or edit ~/.ssh/known_hosts
Performance Issues
Slow connection:
Cause: DNS lookup
Fix: UseDNS no in sshd_config
Cause: GSSAPI authentication
Fix: GSSAPIAuthentication no
Cause: Network latency
Test: ssh -v to see delays
Slow file transfer:
Enable compression: scp -C
Use rsync: More efficient
Check network: Bandwidth limits
SSH Best Practices
Client-Side
1. Use SSH keys:
Generate strong keys (Ed25519 or RSA 4096)
Use passphrases
Use ssh-agent
2. Configure SSH config:
Organize connections
Set defaults
Use aliases
3. Verify host keys:
Check fingerprints on first connection
Don't blindly accept
Compare with known good value
4. Use ProxyJump:
Safer than agent forwarding
Access internal servers
Cleaner than manual tunneling
Server-Side
1. Harden configuration:
Disable password authentication
Disable root login
Change default port (optional)
Limit users
2. Monitor logs:
Watch for failed attempts
Detect brute force
Investigate anomalies
3. Use fail2ban:
Automatic IP blocking
Reduce brute force attempts
Configurable thresholds
4. Keep updated:
Regular security updates
Monitor CVEs
Test updates in staging
5. Regular audits:
Review authorized_keys
Check user accounts
Verify permissions
Review logs
Conclusion
SSH is the standard for secure remote access and file transfer, providing strong encryption, flexible authentication, and powerful features like tunneling and port forwarding. Proper SSH configuration with key-based authentication, disabled password login, and security hardening is essential for secure server management.
Related Articles
Secure Protocols
- SSL/TLS - TLS encryption
- FTP - SFTP uses SSH
- HTTP vs HTTPS - Web security
- VPN Basics - VPN tunneling
Network Concepts
- Port Forwarding - SSH tunneling
- TCP/IP Model - Protocol stack
- Firewall Basics - SSH access control
- Default Gateway - Remote access
Security
- IP Blacklisting - SSH brute force protection
- IP Spoofing - SSH security
- Network Scanning - SSH port scanning
Explore More
- Protocols - Internet protocols hub
- Security & Privacy - Security resources
Key takeaways: - SSH provides encrypted remote access - Port 22 (default), customizable - Key-based authentication preferred - Disable password authentication - Use Ed25519 or RSA 4096 keys - SSH config simplifies connections - SCP/SFTP for secure file transfer - Port forwarding for tunneling - Harden server configuration - Monitor and update regularly
SSH is indispensable for secure server administration. Always use key-based authentication, disable password login on production servers, keep SSH updated, and follow security best practices. Proper SSH configuration protects against unauthorized access while providing convenient and secure remote management capabilities.