Skip to content
Learni
View all tutorials
Administration Système

How to Set Up Secure SSH from A to Z in 2026

Lire en français

Introduction

SSH (Secure Shell) is the standard protocol for securely accessing remote servers, replacing outdated ones like Telnet. In 2026, with rampant brute-force attacks and zero-day vulnerabilities, mastering SSH is essential for every developer, sysadmin, or DevOps engineer—not optional. This beginner tutorial guides you step by step from installation to advanced configuration, with practical examples on Linux (Ubuntu/Debian), macOS, and Windows (via WSL or OpenSSH). You'll generate ED25519 keys (more secure than RSA), disable passwords, and implement tunneling for proxy connections. At the end, you'll have an impenetrable production-ready SSH server. Estimated time: 20 minutes. Why it's crucial: 80% of server breaches involve weak SSH credentials (source: Verizon DBIR 2025). Bookmark this guide as your go-to reference.

Prerequisites

  • A client computer: Linux (Ubuntu 24.04+), macOS Ventura+, or Windows 11 with WSL2.
  • A remote server: Ubuntu 24.04 VPS (e.g., DigitalOcean droplet at $6/month) with root/initial password access.
  • Terminal: GNOME Terminal, iTerm2, or PowerShell.
  • Basic command-line knowledge (cd, ls).
  • Firewall allowing port 22 (ufw allow 22).

Install OpenSSH Client and Server

terminal
# On the client (Linux/macOS)
sudo apt update && sudo apt install openssh-client -y

# On the server (Ubuntu/Debian)
sudo apt update && sudo apt install openssh-server -y
sudo systemctl enable ssh
sudo systemctl start ssh

# Check status
sudo systemctl status ssh

# On Windows (via PowerShell as admin)
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

These commands install and enable OpenSSH. On the server, systemctl enable ensures auto-start on boot. Verify with status: you should see 'active (running)'. Pitfall: on Windows, run as admin; otherwise, the feature fails silently.

Verify Installation and First Connection

Test basic password connection: ssh user@server_ip. If it works, you're ready for keys. Think of SSH like a vault door: passwords are the basic lock, keys are biometrics.

Generate an ED25519 Key Pair

terminal
cd ~/.ssh
ssh-keygen -t ed25519 -C "your-email@example.com" -f id_ed25519

# Passphrase recommended (optional but secure)
# Enter a strong passphrase (e.g., 20+ chars with numbers/symbols)

# List generated keys
ls -la

# Content of the public key (to copy)
cat ~/.ssh/id_ed25519.pub

ED25519 is faster and quantum-resistant compared to RSA. The -C adds a comment for identification. Pitfall: no passphrase means a stolen key compromises everything; use ssh-agent for daily convenience.

Copy the Public Key to the Server

Use ssh-copy-id to automate: it creates ~/.ssh/authorized_keys with correct permissions (600/644).

Copy the Key and Test Passwordless Connection

terminal
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip

# Test the connection
ssh -i ~/.ssh/id_ed25519 user@server_ip

# On the server, check permissions
echo "authorized_keys permissions:"
ls -la ~/.ssh/authorized_keys

# Fix if needed
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

ssh-copy-id appends the public key to authorized_keys. Test: you should connect without a password prompt. Pitfall: overly permissive permissions (e.g., 777) block SSH for security; always fix with chmod.

Configure the SSH Server for Enhanced Security

/etc/ssh/sshd_config controls the daemon. Edit with sudo nano, then restart: sudo systemctl restart ssh.

Secure Server sshd_config

/etc/ssh/sshd_config
Port 2222
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key

PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no

UsePAM no
X11Forwarding no
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server

Match User root
    PermitRootLogin no

LogLevel VERBOSE

This config changes the port (anti-scanning), disables passwords/root login, and enforces keys. Match User root blocks root even with keys. After editing, test the connection before restarting—or risk lockout.

Configure the Client for Aliased Connections

Create ~/.ssh/config for shortcuts: ssh prod instead of ssh -p 2222 -i key user@ip.

Client ~/.ssh/config

~/.ssh/config
Host prod
    HostName 192.0.2.1
    User ubuntu
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes
    Compression yes

Host dev
    HostName dev.example.com
    User devuser
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes

Host *
    AddKeysToAgent yes
    UseKeychain yes  # macOS
    ServerAliveInterval 60

Host blocks simplify frequent connections. IdentitiesOnly yes prevents trying all keys (slows things down). ServerAliveInterval keeps sessions alive. Permissions: chmod 600 ~/.ssh/config.

SSH Tunneling Example (Port Forwarding)

terminal
# Local tunneling: expose server port 8080 on client localhost:3000
ssh -L 3000:localhost:8080 prod

# Remote tunneling: expose client localhost:3000 on server:8080
ssh -R 8080:localhost:3000 prod

# With compression for slow connections
ssh -C -L 3000:localhost:8080 -N prod

# Close tunnel cleanly: Ctrl+C

-L for local forwarding (e.g., remote DB access), -R for remote (expose local service). -N runs no command, just the tunnel. Great for debugging via localhost:3000. Pitfall: forget -N and the shell hangs.

Bash Script for Automated Connections

connect.sh
#!/bin/bash

SERVER=$1
if [ -z "$SERVER" ]; then
  echo "Usage: ./connect.sh <prod|dev>"
  exit 1
fi

ssh-add ~/.ssh/id_ed25519 > /dev/null 2>&1
ssh "$SERVER" -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new

# Features:
# - Adds key to agent
# - 10s timeout
# - Auto-accepts new host keys

This script makes connections a one-liner: ./connect.sh prod. ssh-add loads the key into the agent. StrictHostKeyChecking=accept-new handles new servers without manual MITM checks. Make executable: chmod +x connect.sh.

Best Practices

  • Always change the default port (22) to reduce automated scans (millions daily).
  • Use ED25519 or ECDSA, avoid RSA < 4096 bits.
  • Fail2ban: install to ban IPs after 3 failures (sudo apt install fail2ban).
  • Audit logs: check grep 'Failed password' /var/log/auth.log daily.
  • 2FA: via Google Authenticator with google-authenticator and ChallengeResponseAuthentication yes.

Common Errors to Avoid

  • authorized_keys permissions 644+: SSH refuses with 'permissions too open'. Fix: chmod 600.
  • Forget to restart ssh after config: changes ignored. Always systemctl restart ssh.
  • Passphraseless keys on laptops: theft = compromise. Use ssh-agent + PIN.
  • Root login enabled: behind 99% of hacks. Force sudo after non-root login.

Next Steps

  • Official docs: man ssh_config(5).
  • Advanced tools: Mosh (over SSH for mobility), Teleport (zero-trust SSH).
  • Training: Check our DevOps and security courses at Learni to master Kubernetes with integrated SSH.
  • Hands-on project: Set up a Raspberry Pi cluster with SSH keys and Docker Swarm.