SSH is the workhorse of remote access. But most people only scratch the surface. Here’s how to use it like a pro.
SSH Config: Stop Typing So Much# Instead of:
1
ssh -i ~/.ssh/prod-key.pem -p 2222 ubuntu@ec2-54-123-45-67.compute-1.amazonaws.com
Create ~/.ssh/config:
H H H o o o s s s t t t H U P I H U I F P U p o s o d s o s d o r s r s e r e t s e e r . o e o t r t n a t r n w i x r d N t g N t a n y a u 2 i i a d i r t J a m b 2 t n m e t d e u d e u 2 y g e p y A r m m n 2 F l F g n p i e t i s o i e a n c u l t y l n l b 2 e a e t a - g s 5 ~ i ~ y t 4 / n / e i - . g . s o 1 s . s n 2 s e s 3 h x h - / a / 4 p m s 5 r p t - o l a 6 d e g 7 - . i . k c n c e o g o y m - m . k p p e u e y t m . e p - e 1 m . a m a z o n a w s . c o m
Now just:
1
2
3
ssh prod
ssh staging
ssh db.internal
Key Management# Generate Strong Keys# 1
2
3
4
5
# Ed25519 (recommended, modern)
ssh-keygen -t ed25519 -C "yourname@example.com"
# RSA (wider compatibility, use 4096 bits)
ssh-keygen -t rsa -b 4096 -C "yourname@example.com"
SSH Agent# Don’t type your passphrase repeatedly:
1
2
3
4
5
6
7
8
9
10
11
# Start agent
eval " $( ssh-agent -s) "
# Add key (prompts for passphrase once)
ssh-add ~/.ssh/id_ed25519
# List loaded keys
ssh-add -l
# macOS: Add to keychain
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Agent Forwarding# Access servers from a jump host without copying keys:
1
2
3
4
5
6
# One-time
ssh -A bastion
# Or in config
Host bastion
ForwardAgent yes
⚠️ Security note : Only forward to trusted hosts. A compromised server with your forwarded agent can use your keys.
Jump Hosts / Bastion# ProxyJump (Modern)# 1
2
3
4
5
6
# Command line
ssh -J bastion internal-server
# Config
Host internal-*
ProxyJump bastion
ProxyCommand (Legacy)# H o s t P i r n o t x e y r C n o a m l m - a * n d s s h - W % h : % p b a s t i o n
Multi-Hop# 1
2
3
4
5
6
# Jump through multiple hosts
ssh -J bastion1,bastion2 target
# Config
Host target
ProxyJump bastion1,bastion2
Port Forwarding# Local Forward: Access Remote Service Locally# 1
2
3
4
5
6
7
# Forward local:8080 to remote's localhost:80
ssh -L 8080:localhost:80 server
# Forward local:5432 to database behind server
ssh -L 5432:db.internal:5432 bastion
# Now connect to localhost:5432 to reach the database
Use case : Access internal dashboards, databases, admin panels.
Remote Forward: Expose Local Service Remotely# 1
2
3
4
# Make local:3000 accessible on server:8080
ssh -R 8080:localhost:3000 server
# Anyone connecting to server:8080 reaches your local:3000
Use case : Share local dev server, webhook testing.
Dynamic Forward (SOCKS Proxy)# 1
2
3
4
5
# Create SOCKS proxy on local:1080
ssh -D 1080 server
# Configure browser to use SOCKS proxy localhost:1080
# All traffic goes through the server
Use case : Access region-locked content, browse as if from server’s network.
Persistent Tunnels# 1
2
3
4
5
6
7
8
# Keep tunnel alive with autossh
autossh -M 0 -f -N -L 5432:db:5432 bastion
# Or in config with ServerAlive
Host tunnel
LocalForward 5432 db:5432
ServerAliveInterval 60
ServerAliveCountMax 3
File Transfer# SCP (Simple)# 1
2
3
4
5
6
7
8
9
10
11
# Upload
scp file.txt server:/path/to/dest/
# Download
scp server:/path/to/file.txt ./
# Recursive
scp -r ./folder server:/path/
# With specific port
scp -P 2222 file.txt server:/path/
Rsync (Better)# 1
2
3
4
5
6
7
8
9
10
11
# Sync directory (only changes)
rsync -avz ./local/ server:/remote/
# Delete files on remote that don't exist locally
rsync -avz --delete ./local/ server:/remote/
# Dry run first
rsync -avzn ./local/ server:/remote/
# Exclude patterns
rsync -avz --exclude '*.log' --exclude 'node_modules' ./local/ server:/remote/
SFTP (Interactive)# 1
2
3
4
5
6
sftp server
> put localfile.txt
> get remotefile.txt
> ls
> cd /path
> bye
Multiplexing: Faster Connections# Reuse existing connections:
H o s t C C C o o o n n n t t t r r r o o o l l l M P P a a e s t r t h s e i r ~ s / t a . u s 6 t s 0 o h 0 / s o c k e t s / % r @ % h - % p
Create the socket directory:
1
mkdir -p ~/.ssh/sockets
First connection is normal. Subsequent connections reuse the socket — instant.
Remote Commands# One-Off Commands# 1
2
3
4
5
6
7
8
# Run command, get output
ssh server "df -h"
# Pipe data through SSH
cat backup.sql | ssh server "mysql database"
# Local script, remote execution
ssh server "bash -s" < local-script.sh
Interactive with Pseudo-TTY# 1
2
3
4
5
# Force TTY allocation (needed for interactive commands)
ssh -t server "sudo vim /etc/nginx/nginx.conf"
# Multiple hops with TTY
ssh -t bastion ssh -t internal "sudo systemctl restart app"
Keep Connections Alive# Client-Side# H o s t S S e e r r v v e e r r A A l l i i v v e e I C n o t u e n r t v M a a l x 6 3 0
Sends keepalive every 60 seconds, disconnects after 3 failures.
Server-Side (sshd_config)# C C l l i i e e n n t t A A l l i i v v e e I C n o t u e n r t v M a a l x 6 3 0
Escape Sequences# While connected, press ~ followed by:
~. — Disconnect (when frozen)~^Z — Suspend SSH~# — List forwarded connections~? — Show helpMust be after newline. Press Enter first.
Security Hardening# Client Config# H o s t H I A a d d s e d h n K K t e n i y o t s w i T n e o H s A o O g s n e t l n s y t y y y e e e s s s
Server Config (/etc/ssh/sshd_config)# # P C # P # A # K # M a h e l e a D s a D r A l U x L x i s l i m l o s A i A s w l s i l w e l m u a o e a t o U g i t b r n b R w s m o t h l d g l o e o r T e A e e o o r d i a r u R t n s e t u i p t e r L l r h t e a h s o o y d n m h s s e p o g e s s n o t i s p k a 3 w t n n p l e c t o i s l e o y u t r c e o n c y r e d a A g o i e v m t u i f a x e p a i t n i d c 2 t u o h c m h 5 s t n e i a 5 h n u n n 1 n t s g 9 o i e e - c r s a s h t a i 2 o 5 n 6 @ n l o i b s s h . o r g , d i f f i e - h e l l m a n - g r o u p 1 6 - s h a 5 1 2
Debugging# 1
2
3
4
5
6
7
8
9
10
# Verbose output (add more v's for more detail)
ssh -v server
ssh -vv server
ssh -vvv server
# Test config
ssh -G server
# Check what keys are being offered
ssh -v server 2>& 1 | grep "Offering"
Quick Reference# Task Command Connect ssh serverWith key ssh -i key.pem serverDifferent port ssh -p 2222 serverJump host ssh -J bastion serverLocal forward ssh -L 8080:localhost:80 serverRemote forward ssh -R 8080:localhost:3000 serverSOCKS proxy ssh -D 1080 serverCopy file scp file server:/path/Sync directory rsync -avz dir/ server:/path/Run command ssh server "command"
SSH is one of those tools where the basics are easy but mastery takes time. Set up your config file, learn the forwarding options, and you’ll save hours of typing and waiting.