iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

SSH

SSH (Secure Shell) is the encrypted remote-shell + tunneling protocol. ssh user@host opens a shell; scp copies files; -L tunnels ports. Public-key auth is the safe default.

Keys, config, tunnels, agent

EXAMPLE
# 1) Basic connection
ssh ada@server.example.com
ssh ada@server.example.com -p 2222            # non-default port
ssh ada@server.example.com 'uname -a'         # run a single command + exit

# 2) Generate a keypair (Ed25519 — modern, fast, small)
ssh-keygen -t ed25519 -C 'ada@example.com'
# Press Enter to accept default location (~/.ssh/id_ed25519)
# Set a passphrase (or skip with empty input)

# Inspect public key
cat ~/.ssh/id_ed25519.pub

# 3) Install public key on a server
ssh-copy-id ada@server.example.com
# Appends your ~/.ssh/id_ed25519.pub to ~/.ssh/authorized_keys on the server
# After this, ssh ada@server.example.com works without a password

# Or manually:
cat ~/.ssh/id_ed25519.pub | ssh ada@server 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'

# 4) SSH config — name your hosts
# ~/.ssh/config
Host prod-web
    HostName        prod-web-1.example.com
    User            ada
    Port            22
    IdentityFile    ~/.ssh/id_ed25519
    IdentitiesOnly  yes
    ForwardAgent    no

Host prod-jump
    HostName        bastion.example.com
    User            ada

Host prod-db
    HostName        10.0.5.10
    User            ada
    ProxyJump       prod-jump                    # bounce via bastion

Host github.com
    User            git
    IdentityFile    ~/.ssh/id_github

# Now:
ssh prod-web           # all settings applied
ssh prod-db            # connects via bastion automatically

# 5) ssh-agent — cache passphrases
# Linux
eval $(ssh-agent -s)
ssh-add ~/.ssh/id_ed25519
ssh-add -l                                       # list keys
ssh-add -d ~/.ssh/id_ed25519                     # remove

# macOS — Keychain integration
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
# Auto-unlock on login

# ssh-agent forwarding (-A) — sensitive; only forward to TRUSTED servers
ssh -A ada@trusted-server

# 6) Copy files — scp
scp file.txt ada@server:/path/to/                # local → remote
scp ada@server:/path/file.txt ./                  # remote → local
scp -r dir/ ada@server:/path/                     # recursive
scp -P 2222 file.txt ada@server:/path/            # custom port

# 7) Sync files — rsync (better than scp for big trees)
rsync -avz --progress dir/ ada@server:/path/      # archive, verbose, compress
rsync -avz --delete dir/ ada@server:/path/        # delete files on dest not in source
rsync -avz -e 'ssh -p 2222' dir/ ada@server:/path/

# 8) Tunnels — port forwarding

# Local forward — connect to local port → forwarded to remote
ssh -L 5432:db.internal:5432 ada@bastion
# localhost:5432 → bastion → db.internal:5432
# Access prod DB through bastion without exposing it publicly

# Remote forward — remote port → forwarded to local
ssh -R 8080:localhost:3000 ada@server
# server:8080 → my-laptop:3000
# Useful for sharing a local dev server temporarily

# Dynamic forward — SOCKS proxy
ssh -D 1080 ada@bastion
# All traffic through localhost:1080 tunnels through bastion
# Configure browser to use SOCKS5 localhost:1080

# 9) Run a remote command and stream output
ssh ada@server 'tail -f /var/log/app.log'
ssh ada@server 'cat /etc/os-release'
ssh ada@server 'docker ps' | grep nginx

# 10) Heredoc — multi-line remote scripts
ssh ada@server 'bash -s' << 'EOF'
echo 'Hello from $(hostname)'
uptime
free -h
EOF

# 11) Run a remote sudo command
ssh -t ada@server 'sudo systemctl restart nginx'    # -t allocates a pseudo-tty

# 12) Multiplexing — reuse connections (much faster than reconnecting)
# ~/.ssh/config
Host *
    ControlMaster auto
    ControlPath   ~/.ssh/cm-%r@@%h:%p
    ControlPersist 10m

# First connection establishes; subsequent ones use the same tunnel.
# Cuts ~500ms off every ssh invocation.

# 13) Server-side authorized_keys options
# /home/ada/.ssh/authorized_keys
# Restrict to a single command (e.g. for backup automation)
command="/usr/local/bin/backup.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... backup-key

# 14) SSH server hardening (sshd_config)
# /etc/ssh/sshd_config
Port                 2222                # change default 22 (security through obscurity, weak win)
PermitRootLogin      no
PasswordAuthentication no                 # ONLY public-key auth
PubkeyAuthentication yes
AuthenticationMethods publickey
AllowUsers           ada bo
ClientAliveInterval  300
ClientAliveCountMax  2
LogLevel             VERBOSE
MaxAuthTries         3
LoginGraceTime       30

sudo systemctl reload sshd
# Test in a NEW terminal before closing the current one!

# 15) Fail2ban — auto-ban brute force attempts
sudo apt install fail2ban
# /etc/fail2ban/jail.local
# [sshd]
# enabled = true
# maxretry = 5
# bantime = 3600

# 16) Known hosts — first-time-trust pattern
# ~/.ssh/known_hosts gets a server's host key on first connection.
# If it changes, ssh refuses (MITM warning).

# Clear a host's entry (e.g. after legitimate server change)
ssh-keygen -R server.example.com
ssh-keygen -R 192.0.2.1

# Verify a host's fingerprint OUT OF BAND (DNS, official docs)
ssh-keyscan server.example.com

# 17) GitHub / GitLab SSH
# Generate a key, add to GitHub Settings → SSH keys
ssh-keygen -t ed25519 -f ~/.ssh/id_github
# Test:
ssh -T git@github.com
# 'Hi Ada! You've successfully authenticated.'

# 18) SCP vs SFTP vs rsync
# scp     : simple file copy; legacy; lacks delete + resume
# sftp    : interactive (sftp ada@server) + scriptable; supports resume
# rsync   : best for syncing trees; delta transfer; resume; --delete

# 19) Tunneling pattern — secure DB access
# 1. SSH-tunnel: ssh -L 5432:db:5432 bastion
# 2. Use 'psql -h localhost -p 5432' from your laptop
# 3. No need to expose db publicly

# 20) Common bugs
#   • Permission denied: check ~/.ssh and key file modes (700 + 600)
#   • Host key changed: someone may have reset the server; verify before clearing
#   • Slow connections: ssh multiplexing (ControlMaster auto)
#   • Wrong key used: -i flag or IdentityFile in config + IdentitiesOnly yes
#   • Sudo without -t: 'sudo: no tty present'; use -t flag

# 21) Best practices
#   ✅ Ed25519 keys (or RSA 4096); never use DSA / ECDSA P-256 (revocation issues)
#   ✅ Set passphrase on private keys
#   ✅ Use ssh-agent (with macOS Keychain or KeePassXC)
#   ✅ Disable password authentication on servers
#   ✅ Use ~/.ssh/config for hosts you connect to often
#   ✅ ProxyJump for bastion hosts
#   ✅ ssh-keyscan + DNS for verifying new hosts
#   ✅ fail2ban / rate limits on internet-facing SSH
#   ✅ Use a separate key per service (one for personal, one for work)
#   ✅ Multiplexing for snappier feel

# 22) Modern alternatives
#   • Tailscale / WireGuard — VPN with SSH on top
#   • Cloudflare Access / Teleport / StrongDM — managed SSH access with audit
#   • SSH certificates (signed by CA) — instead of authorized_keys
#   • AWS SSM Session Manager — no SSH port at all (uses agent + IAM)

Why it matters

SSH config + Ed25519 keys + ssh-agent + ProxyJump turns daily server access into one-word commands. For internet-facing SSH, disable password auth, restrict by AllowUsers, and add fail2ban — otherwise the bots will find you.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
ssh user@host
ssh -p 2222 user@host
ssh -i ~/.ssh/key.pem user@host
Try it Yourself »

Discussion

Loading…