Your Gateway to Remote Systems
SSH is how you manage servers that aren’t sitting under your desk. Every cloud instance, every production server, every container host—you’ll access them through SSH.
Basic SSH is connecting with a password. Production SSH means key-based authentication, secure configurations, tunnels, and jump hosts. That progression represents real career growth.
Basic SSH Connection
Connecting
# Basic connection
ssh user@hostname
# Specific port
ssh -p 2222 user@hostname
# Verbose (for debugging)
ssh -v user@hostname
# Very verbose
ssh -vvv user@hostname
Running Remote Commands
# Run command and exit
ssh user@server "hostname && uptime"
# Run script remotely
ssh user@server "bash -s" < local-script.sh
# Interactive command
ssh -t user@server "sudo apt update"
The -t flag allocates a pseudo-terminal, needed for interactive commands like sudo.
Key-Based Authentication
Passwords are for beginners. Keys are mandatory for production.
Creating Keys
# Generate key pair (use Ed25519 - modern and secure)
ssh-keygen -t ed25519 -C "[email protected]"
# Or RSA if Ed25519 not supported
ssh-keygen -t rsa -b 4096 -C "[email protected]"
# Keys are created in:
# ~/.ssh/id_ed25519 (private - never share)
# ~/.ssh/id_ed25519.pub (public - share freely)
Copying Keys to Servers
# Easiest method
ssh-copy-id user@server
# Manual method
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# Or copy and paste into ~/.ssh/authorized_keys on the server
Key Permissions
SSH refuses to use keys with wrong permissions:
# Required permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
- Interview classic: "SSH says permission denied but the key is correct." Answer: check key file permissions with
ls -la ~/.ssh.
SSH Config File
Stop typing long commands. Use ~/.ssh/config:
# ~/.ssh/config
# Simple alias
Host prod
HostName 192.168.1.100
User deploy
Port 22
# Now just: ssh prod
# With specific key
Host staging
HostName staging.example.com
User admin
IdentityFile ~/.ssh/staging_key
# Jump host (bastion)
Host internal
HostName 10.0.0.50
User admin
ProxyJump bastion
Host bastion
HostName bastion.example.com
User jumpuser
# Wildcard for multiple servers
Host web-*
User www-data
IdentityFile ~/.ssh/web_key
Host web-1
HostName 192.168.1.11
Host web-2
HostName 192.168.1.12
# Keep connections alive
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
SSH Tunnels
Local Port Forwarding
Access remote service as if it's local:
# Access remote database locally
ssh -L 5432:localhost:5432 user@dbserver
# Now connect to localhost:5432 to reach the remote database
# Access internal web app
ssh -L 8080:internal-app:80 user@jumphost
# Visit localhost:8080 in browser
Remote Port Forwarding
Expose local service to remote server:
# Let remote server access your local web server
ssh -R 8080:localhost:3000 user@server
# Remote server can now access localhost:8080
Dynamic Port Forwarding (SOCKS Proxy)
# Create SOCKS proxy
ssh -D 1080 user@server
# Configure browser to use localhost:1080 as SOCKS proxy
# All traffic routes through the remote server
Persistent Tunnels
# Background tunnel that stays open
ssh -fN -L 5432:localhost:5432 user@server
# Kill background SSH
pkill -f "ssh -fN"
Secure SSH Configuration
Server Hardening (/etc/ssh/sshd_config)
# Disable password authentication
PasswordAuthentication no
# Disable root login
PermitRootLogin no
# Use only SSH protocol 2
Protocol 2
# Limit users who can SSH
AllowUsers admin deploy
# Change default port (security through obscurity, but reduces noise)
Port 2222
# Disconnect idle sessions
ClientAliveInterval 300
ClientAliveCountMax 2
After changes:
sudo sshd -t # Test config
sudo systemctl restart sshd
Warning: Always keep a second session open when changing SSH config. If you break something, you can still fix it.
Fail2Ban for Brute Force Protection
# Install
sudo apt install fail2ban
# Enable for SSH
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check status
sudo fail2ban-client status sshd
SCP and SFTP: File Transfer
SCP (Secure Copy)
# Copy file to remote
scp file.txt user@server:/path/to/destination/
# Copy file from remote
scp user@server:/path/to/file.txt ./
# Copy directory recursively
scp -r directory/ user@server:/path/
# With specific port
scp -P 2222 file.txt user@server:/path/
SFTP (Interactive)
# Connect
sftp user@server
# Commands
get remote-file.txt # Download
put local-file.txt # Upload
ls # List remote
lls # List local
cd /path # Change remote dir
lcd /path # Change local dir
rsync over SSH
# Sync directory to remote
rsync -avz --progress local-dir/ user@server:/remote-dir/
# Sync from remote
rsync -avz user@server:/remote-dir/ ./local-dir/
# With delete (mirror exactly)
rsync -avz --delete local/ user@server:/remote/
SSH Agent
Avoid typing passphrase repeatedly:
# Start agent
eval $(ssh-agent)
# Add key
ssh-add ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# Forward agent to remote (use carefully)
ssh -A user@server
Jump Hosts / Bastion
Access internal servers through a gateway:
# Single command
ssh -J jumpuser@bastion admin@internal-server
# In config file (shown earlier)
Host internal
HostName 10.0.0.50
ProxyJump bastion
Troubleshooting SSH
Connection Refused
# Is SSH running?
sudo systemctl status sshd
# Is the port open?
sudo ss -tlpn | grep 22
# Firewall blocking?
sudo ufw status
Permission Denied
# Check key permissions
ls -la ~/.ssh/
# Verify key is being offered
ssh -v user@server 2>&1 | grep "Offering"
# Check server's authorized_keys
ssh user@server "cat ~/.ssh/authorized_keys"
Connection Timeout
# Network reachable?
ping server
# Port reachable?
nc -zv server 22
# Check route
traceroute server
Interview Questions
- "How do you set up SSH key authentication?"
"Generate a key pair with
ssh-keygen -t ed25519, then copy the public key to the server's~/.ssh/authorized_keysusingssh-copy-id. Ensure permissions are correct: 700 on .ssh directory, 600 on private key, 644 on public key, 600 on authorized_keys." - "How would you access a server that's behind a firewall?"
"Through a bastion host. I'd SSH to the bastion first, then to the internal server—or use ProxyJump in my SSH config for a single command. For ongoing access, I'd set up the jump configuration in ~/.ssh/config."
- "Someone's brute-forcing your SSH. What do you do?"
"Immediate: check
/var/log/auth.logfor the attacking IPs and block them with iptables or ufw. Long-term: implement fail2ban to auto-block after failed attempts, disable password auth entirely, and consider moving SSH to a non-standard port."
Quick Reference
# Connecting
ssh user@host # Basic connection
ssh -p 2222 user@host # Specific port
ssh -i key.pem user@host # Specific key
# Keys
ssh-keygen -t ed25519 # Generate key
ssh-copy-id user@host # Copy key to server
ssh-add ~/.ssh/key # Add to agent
# File transfer
scp file user@host:/path # Copy to remote
scp user@host:/file ./ # Copy from remote
rsync -avz dir/ user@host:/path/ # Sync
# Tunnels
ssh -L 8080:localhost:80 user@host # Local forward
ssh -R 8080:localhost:80 user@host # Remote forward
ssh -D 1080 user@host # SOCKS proxy
# Jump hosts
ssh -J jump@bastion user@internal
# Troubleshooting
ssh -v user@host # Verbose
ssh -vvv user@host # Very verbose
The Career Translation
| Skill | Demonstrates | Role Level |
|---|---|---|
| Basic SSH with password | Can connect | Helpdesk (£25-30k) |
| Key auth + config file | Proper security practice | Junior Sysadmin (£30-40k) |
| Tunnels, jump hosts | Production infrastructure | Mid-level (£40-50k) |
| Hardening, automation | Security engineering | Senior (£50k+) |
Next Steps
- Ansible - Automation over SSH
- SSH certificates - Enterprise key management
- Teleport/Boundary - Modern access management
- Mosh - Mobile shell for flaky connections
SSH is your daily driver for remote administration. Master it and you can manage any server, anywhere.
Part 10 of the Linux Fundamentals series. Next: text processing with grep, sed, and awk—parsing logs and data like a pro.
Linux Fundamentals Series - Part 10 of 12
Previous: Log Files and journalctl

