Configure OpenSSH Server and Client¶
Overview¶
This guide covers configuration, management, and security best practices for OpenSSH server (sshd) and client (ssh) on Linux systems.
SSH Basics¶
SSH (Secure Shell) provides encrypted network communication for: - Remote command execution - Secure file transfer (SCP, SFTP) - Port forwarding and tunneling - X11 forwarding for GUI applications
Default port: 22/TCP
Installation¶
Install OpenSSH¶
# RHEL/CentOS/Fedora
dnf install openssh-server openssh-clients
# Ubuntu/Debian
apt install openssh-server openssh-client
# Check if installed
rpm -qa | grep openssh # RHEL
dpkg -l | grep openssh # Debian
SSH Server (sshd) Configuration¶
Service Management¶
# Start SSH service
systemctl start sshd
# Stop SSH service
systemctl stop sshd
# Restart SSH service
systemctl restart sshd
# Reload configuration (no connection drop)
systemctl reload sshd
# Enable at boot
systemctl enable sshd
# Check status
systemctl status sshd
# Check if enabled
systemctl is-enabled sshd
# View SSH service logs
journalctl -u sshd
journalctl -u sshd -f # Follow logs
Main Configuration File¶
Location: /etc/ssh/sshd_config
Important Configuration Directives:
# Port and address binding
Port 22 # Change default port
#Port 2222 # Custom port
ListenAddress 0.0.0.0 # Listen on all IPv4
ListenAddress :: # Listen on all IPv6
#ListenAddress 192.168.1.100 # Specific IP only
# Protocol version
Protocol 2 # Only use SSH protocol 2
# Host keys
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Logging
SyslogFacility AUTH
LogLevel INFO # QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG
# Authentication
PermitRootLogin no # Disable root login (RECOMMENDED)
#PermitRootLogin prohibit-password # Allow only key-based root login
#PermitRootLogin yes # Allow all root login (NOT RECOMMENDED)
PubkeyAuthentication yes # Enable public key authentication
PasswordAuthentication yes # Enable password authentication
PermitEmptyPasswords no # Disable empty passwords
ChallengeResponseAuthentication no
# PAM authentication
UsePAM yes
# Kerberos authentication
KerberosAuthentication no
KerberosOrLocalPasswd yes
# GSSAPI authentication
GSSAPIAuthentication no
# Connection settings
X11Forwarding yes # Enable X11 forwarding
X11UseLocalhost yes
PrintMotd no # Don't print /etc/motd
PrintLastLog yes
TCPKeepAlive yes
ClientAliveInterval 300 # Send keepalive every 300 seconds
ClientAliveCountMax 3 # Disconnect after 3 failed keepalives
# Login settings
MaxAuthTries 3 # Maximum authentication attempts
MaxSessions 10 # Maximum sessions per connection
LoginGraceTime 60 # Time to authenticate (seconds)
# Subsystem
Subsystem sftp /usr/libexec/openssh/sftp-server
# User/Group restrictions
AllowUsers user1 user2 # Only these users can connect
#DenyUsers baduser # These users cannot connect
AllowGroups sshusers # Only members of these groups
#DenyGroups restricted # Members cannot connect
# Banner
Banner /etc/ssh/banner # Display banner before login
Example: Secure Configuration¶
# /etc/ssh/sshd_config - Hardened configuration
Port 2222
Protocol 2
ListenAddress 0.0.0.0
# Encryption
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
# Authentication
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
# Access control
AllowGroups sshusers
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30
# Connection security
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
PrintMotd no
TCPKeepAlive yes
# Logging
LogLevel VERBOSE
SyslogFacility AUTH
Test Configuration¶
# Test configuration syntax
sshd -t
# Test with specific config file
sshd -t -f /etc/ssh/sshd_config
# Test and show configuration
sshd -T
# Show configuration for specific user
sshd -T -C user=john
Reload Configuration¶
# Reload without dropping connections
systemctl reload sshd
# Or send HUP signal
kill -HUP $(cat /var/run/sshd.pid)
SSH Client Configuration¶
Per-User Configuration¶
Location: ~/.ssh/config
# Global defaults
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes
ForwardAgent no
# Specific host
Host webserver
HostName web.example.com
User admin
Port 2222
IdentityFile ~/.ssh/web_rsa
Host db
HostName 192.168.1.100
User dbadmin
Port 22
IdentityFile ~/.ssh/db_key
ForwardAgent yes
# Pattern matching
Host *.example.com
User john
IdentityFile ~/.ssh/example_rsa
# Jump host (bastion)
Host internal-server
HostName 10.0.1.100
User admin
ProxyJump bastion.example.com
# Multiple jump hosts
Host deep-server
HostName 10.0.2.100
ProxyJump bastion1.example.com,bastion2.example.com
System-Wide Configuration¶
Location: /etc/ssh/ssh_config
SSH Key Management¶
Generate SSH Key Pairs¶
# Generate RSA key (default, 3072 bits)
ssh-keygen
# Generate RSA with specific bits
ssh-keygen -t rsa -b 4096 -C "user@email.com"
# Generate Ed25519 key (recommended, more secure)
ssh-keygen -t ed25519 -C "user@email.com"
# Generate ECDSA key
ssh-keygen -t ecdsa -b 521
# Specify file location
ssh-keygen -t ed25519 -f ~/.ssh/custom_key
# Generate without passphrase (not recommended)
ssh-keygen -t ed25519 -N ""
# Change passphrase of existing key
ssh-keygen -p -f ~/.ssh/id_ed25519
Key Files¶
~/.ssh/id_rsa # Private key (RSA)
~/.ssh/id_rsa.pub # Public key (RSA)
~/.ssh/id_ed25519 # Private key (Ed25519)
~/.ssh/id_ed25519.pub # Public key (Ed25519)
~/.ssh/authorized_keys # Authorized public keys
~/.ssh/known_hosts # Known host fingerprints
~/.ssh/config # Client configuration
Deploy Public Key¶
# Method 1: Using ssh-copy-id (recommended)
ssh-copy-id user@remote-host
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote-host
ssh-copy-id -p 2222 user@remote-host
# Method 2: Manual copy
cat ~/.ssh/id_ed25519.pub | ssh user@remote-host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# Method 3: Direct append
ssh user@remote-host "echo '$(cat ~/.ssh/id_ed25519.pub)' >> ~/.ssh/authorized_keys"
# Method 4: SCP
scp ~/.ssh/id_ed25519.pub user@remote-host:~/key.pub
ssh user@remote-host "mkdir -p ~/.ssh && cat ~/key.pub >> ~/.ssh/authorized_keys && rm ~/key.pub"
Correct Permissions¶
# On remote server
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub
chmod 644 ~/.ssh/known_hosts
chmod 600 ~/.ssh/config
# Fix all at once
chmod 700 ~/.ssh && chmod 600 ~/.ssh/* && chmod 644 ~/.ssh/*.pub
Manage Authorized Keys¶
# Add key to authorized_keys
echo "ssh-ed25519 AAAA..." >> ~/.ssh/authorized_keys
# View authorized keys
cat ~/.ssh/authorized_keys
# Remove specific key (edit file)
vim ~/.ssh/authorized_keys
# Limit key usage (prepend to key in authorized_keys)
from="192.168.1.0/24" ssh-ed25519 AAAA...
command="/usr/local/bin/backup.sh" ssh-ed25519 AAAA...
no-port-forwarding,no-X11-forwarding ssh-ed25519 AAAA...
SSH Agent¶
# Start SSH agent
eval $(ssh-agent)
# Add key to agent
ssh-add ~/.ssh/id_ed25519
# Add with timeout (seconds)
ssh-add -t 3600 ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# List loaded keys with full public key
ssh-add -L
# Remove specific key
ssh-add -d ~/.ssh/id_ed25519
# Remove all keys
ssh-add -D
# Kill agent
ssh-agent -k
Connecting with SSH¶
Basic Connection¶
# Connect to host
ssh user@hostname
# Connect to specific port
ssh -p 2222 user@hostname
# Connect using specific key
ssh -i ~/.ssh/custom_key user@hostname
# Connect with verbose output
ssh -v user@hostname # Level 1
ssh -vv user@hostname # Level 2
ssh -vvv user@hostname # Level 3 (most verbose)
# Connect and execute command
ssh user@hostname "ls -la /tmp"
# Connect and execute multiple commands
ssh user@hostname "uptime; df -h; free -m"
# Using config alias
ssh webserver # Uses ~/.ssh/config
Advanced Connection Options¶
# Disable strict host key checking (use carefully)
ssh -o StrictHostKeyChecking=no user@hostname
# Specify cipher
ssh -c aes256-gcm@openssh.com user@hostname
# Enable compression
ssh -C user@hostname
# Allocate pseudo-TTY
ssh -t user@hostname
# No pseudo-TTY
ssh -T user@hostname
# Run in background
ssh -f user@hostname "sleep 10; command"
# Keep connection alive
ssh -o ServerAliveInterval=60 user@hostname
# X11 forwarding
ssh -X user@hostname
ssh -Y user@hostname # Trusted X11 forwarding
Jump Hosts (Bastion)¶
# Connect through jump host
ssh -J jump-host user@target-host
# Multiple jump hosts
ssh -J jump1,jump2 user@target
# Alternative syntax
ssh -o ProxyJump=jump-host user@target
# With different users
ssh -J jumpuser@jump-host targetuser@target
SSH Tunneling and Port Forwarding¶
Local Port Forwarding¶
Forward local port to remote destination.
# Basic syntax: ssh -L local_port:destination:destination_port user@ssh_server
# Forward local port 8080 to remote localhost:80
ssh -L 8080:localhost:80 user@remote-host
# Access remote database locally
ssh -L 3306:localhost:3306 user@database-server
# Now connect to localhost:3306 locally
# Forward to third host through SSH server
ssh -L 8080:internal-web:80 user@gateway
# Multiple port forwards
ssh -L 8080:web:80 -L 3306:db:3306 user@gateway
# Bind to specific interface
ssh -L 192.168.1.100:8080:localhost:80 user@remote
Remote Port Forwarding¶
Forward remote port to local destination.
# Basic syntax: ssh -R remote_port:destination:destination_port user@ssh_server
# Expose local web server to remote
ssh -R 8080:localhost:80 user@remote-host
# Remote host can access your local web server on port 8080
# Allow remote server to forward to internal network
ssh -R 3306:database:3306 user@remote
# Bind to all remote interfaces (requires GatewayPorts yes in sshd_config)
ssh -R 0.0.0.0:8080:localhost:80 user@remote
Dynamic Port Forwarding (SOCKS Proxy)¶
Create a SOCKS proxy for all traffic.
# Create SOCKS proxy on local port 1080
ssh -D 1080 user@remote-host
# Use specific bind address
ssh -D 127.0.0.1:1080 user@remote
# Configure browser or application to use SOCKS proxy:
# Host: localhost, Port: 1080, SOCKS v5
# Test SOCKS proxy
curl --socks5 localhost:1080 http://example.com
Combined Tunneling¶
# Local + Dynamic forwarding
ssh -L 8080:web:80 -D 1080 user@gateway
# Background with no shell
ssh -fNL 8080:localhost:80 user@remote
# Options explained:
# -f: Background
# -N: No command execution
# -L: Local forward
# -R: Remote forward
# -D: Dynamic forward
SSH Tunnel as Daemon¶
# Create persistent tunnel
ssh -fNL 8080:localhost:80 user@remote
# With auto-reconnect in cron
*/5 * * * * pgrep -f "ssh -fNL" || ssh -fNL 8080:localhost:80 user@remote
# Using autossh (better for persistent tunnels)
autossh -M 0 -fNL 8080:localhost:80 user@remote
File Transfer with SSH¶
SCP (Secure Copy)¶
# Copy file to remote
scp file.txt user@remote:/path/to/destination
# Copy file from remote
scp user@remote:/path/to/file.txt /local/destination
# Copy directory recursively
scp -r /local/dir user@remote:/remote/dir
# Copy with specific port
scp -P 2222 file.txt user@remote:/path
# Copy with compression
scp -C large_file.txt user@remote:/path
# Preserve permissions and timestamps
scp -p file.txt user@remote:/path
# Copy between two remote hosts
scp user1@remote1:/file user2@remote2:/path
# Limit bandwidth (in Kbps)
scp -l 1000 large_file user@remote:/path
# Verbose output
scp -v file.txt user@remote:/path
SFTP (SSH File Transfer Protocol)¶
# Connect to SFTP server
sftp user@remote-host
# Connect with specific port
sftp -P 2222 user@remote
# SFTP interactive commands
sftp> ls # List remote directory
sftp> lls # List local directory
sftp> pwd # Print remote working directory
sftp> lpwd # Print local working directory
sftp> cd /remote/path # Change remote directory
sftp> lcd /local/path # Change local directory
sftp> get file.txt # Download file
sftp> get -r directory/ # Download directory
sftp> put file.txt # Upload file
sftp> put -r directory/ # Upload directory
sftp> mkdir newdir # Create remote directory
sftp> rmdir directory # Remove remote directory
sftp> rm file.txt # Delete remote file
sftp> rename old.txt new.txt # Rename remote file
sftp> chmod 755 script.sh # Change permissions
sftp> exit # Quit
# Batch mode with command file
echo "get file.txt" | sftp user@remote
# Execute single command
sftp user@remote <<< "get /remote/file.txt"
rsync over SSH¶
# Basic sync
rsync -avz /local/path/ user@remote:/remote/path/
# Sync with specific SSH port
rsync -avz -e "ssh -p 2222" /local/ user@remote:/remote/
# Sync with progress
rsync -avz --progress /local/ user@remote:/remote/
# Dry run (test without changes)
rsync -avz --dry-run /local/ user@remote:/remote/
# Delete files in destination not in source
rsync -avz --delete /local/ user@remote:/remote/
# Exclude files
rsync -avz --exclude='*.log' /local/ user@remote:/remote/
# Options explained:
# -a: Archive mode (preserves permissions, times, etc.)
# -v: Verbose
# -z: Compress
# -e: Specify SSH command
SSH Security Best Practices¶
1. Disable Root Login¶
# In /etc/ssh/sshd_config
PermitRootLogin no
2. Use Key-Based Authentication¶
# Generate strong key
ssh-keygen -t ed25519 -C "user@email.com"
# Disable password authentication after deploying keys
PasswordAuthentication no
3. Change Default Port¶
# In /etc/ssh/sshd_config
Port 2222
# Update firewall
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
4. Limit User Access¶
# In /etc/ssh/sshd_config
AllowUsers john jane admin
# Or use groups
AllowGroups sshusers
5. Use fail2ban¶
# Install fail2ban
dnf install fail2ban
# Configure for SSH
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/secure
maxretry = 3
bantime = 3600
6. Two-Factor Authentication¶
# Install Google Authenticator PAM module
dnf install google-authenticator
# Configure PAM
# Add to /etc/pam.d/sshd
auth required pam_google_authenticator.so
# Configure sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
7. Restrict SSH Protocol¶
# Only use protocol 2
Protocol 2
8. Set Login Grace Time¶
# Limit time to authenticate
LoginGraceTime 30
9. Use TCP Wrappers¶
# /etc/hosts.allow
sshd: 192.168.1.0/24
# /etc/hosts.deny
sshd: ALL
10. Configure Idle Timeout¶
# In /etc/ssh/sshd_config
ClientAliveInterval 300
ClientAliveCountMax 2
Troubleshooting SSH¶
Check SSH Service¶
# Service status
systemctl status sshd
# Check if listening
ss -tlnp | grep ssh
netstat -tlnp | grep ssh
# Test configuration
sshd -t
# View logs
journalctl -u sshd -f
tail -f /var/log/secure # RHEL
tail -f /var/log/auth.log # Ubuntu
Verbose Connection Testing¶
# Client-side debugging
ssh -vvv user@host
# Look for:
# - Key exchange
# - Authentication attempts
# - Cipher negotiation
# - Connection errors
Common Issues¶
Connection Refused¶
# Check if service running
systemctl status sshd
# Check firewall
firewall-cmd --list-all
iptables -L -n
# Check if listening on correct interface
ss -tlnp | grep :22
Permission Denied (publickey)¶
# Check key permissions
ls -la ~/.ssh/
# Should be:
# 700 for ~/.ssh/
# 600 for private keys
# 644 for public keys
# Check server logs
tail -f /var/log/secure
# Verify key is in authorized_keys
cat ~/.ssh/authorized_keys
# Test with password (if enabled)
ssh -o PubkeyAuthentication=no user@host
Host Key Verification Failed¶
# Remove old key
ssh-keygen -R hostname
# Or edit known_hosts
vim ~/.ssh/known_hosts
# Accept new key
ssh -o StrictHostKeyChecking=no user@host
Too Many Authentication Failures¶
# Limit keys offered
ssh -o IdentitiesOnly=yes -i ~/.ssh/specific_key user@host
# Or configure in ~/.ssh/config
Host problem-host
IdentitiesOnly yes
IdentityFile ~/.ssh/specific_key
Firewall Configuration¶
firewalld¶
# Allow SSH
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
# Allow custom SSH port
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
# Allow from specific source
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept'
firewall-cmd --reload
iptables¶
# Allow SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow from specific source
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT
# Save rules
iptables-save > /etc/sysconfig/iptables
Quick Reference Commands¶
Service Management¶
systemctl start/stop/restart sshd # Manage service
systemctl enable sshd # Enable at boot
sshd -t # Test configuration
Key Management¶
ssh-keygen -t ed25519 # Generate key
ssh-copy-id user@host # Deploy key
ssh-add # Add to agent
Connecting¶
ssh user@host # Basic connection
ssh -p 2222 user@host # Custom port
ssh -i key user@host # Specific key
ssh -J jump user@target # Jump host
Port Forwarding¶
ssh -L 8080:dest:80 user@host # Local forward
ssh -R 8080:dest:80 user@host # Remote forward
ssh -D 1080 user@host # SOCKS proxy
File Transfer¶
scp file user@host:/path # Copy file
sftp user@host # Interactive transfer
rsync -avz /src/ user@host:/dst/ # Sync directories
Exam Tips¶
- Know both server (
sshd_config) and client (ssh_config) configuration - Understand key-based authentication setup and troubleshooting
- Practice port forwarding scenarios (local, remote, dynamic)
- Know how to secure SSH (disable root, change port, keys only)
- Understand file permissions for SSH directories and files
- Be comfortable with
ssh-keygen,ssh-copy-id, andssh-agent - Know how to test SSH configuration without breaking access
- Practice troubleshooting with verbose output (
-vvv) - Understand TCP wrappers and firewall configuration for SSH
- Know the difference between SCP, SFTP, and rsync