Secure Shell (SSH)
SSH is a cryptographic network protocol for operating network services securely over an unsecured network. As a DevOps engineer, SSH is your primary method for accessing cloud VMs, physical servers, and containers.
# Connect using username and IP address
$ ssh [email protected]
[email protected]'s password: ********
# Connect using a specific port (non-default)
$ ssh -p 2222 [email protected]
# Connect with a specific SSH key
$ ssh -i ~/.ssh/custom_key.pem [email protected]SSH Config File — ~/.ssh/config
Save time by configuring hosts in your SSH config:
$ cat ~/.ssh/config
# Production server
Host prod-server
HostName 54.123.45.67
User admin
Port 22
IdentityFile ~/.ssh/prod_key
ForwardAgent yes
# Staging server
Host staging
HostName staging.example.com
User deploy
Port 2222
IdentityFile ~/.ssh/staging_key
# Jump host / bastion
Host bastion
HostName bastion.example.com
User admin
IdentityFile ~/.ssh/bastion_key
# Use bastion to reach internal servers
Host webserver
HostName 10.0.1.50
User ubuntu
ProxyJump bastion
# Default settings for all hosts
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes# Now connect simply by nickname
$ ssh prod-server
$ ssh stagingPublic Key Authentication
Passwords can be guessed. SSH keys are cryptographically strong and are the production standard.
Step 1: Generate a Keypair
$ ssh-keygen -t ed25519 -C "[email protected]"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/admin/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/admin/.ssh/id_ed25519.
Your public key has been saved in /home/admin/.ssh/id_ed25519.pub.
$ ls -la ~/.ssh/
total 48
drwxr-xr-x 3 root root 4096 Apr 10 08:00 .
drwxr-xr-x 2 root root 4096 Apr 10 08:00 ..
-rw------- 1 admin admin 464 Apr 10 08:00 id_ed25519 ← Private key (keep secret!)
-rw-r--r-- 1 admin admin 103 Apr 10 08:00 id_ed25519.pub ← Public key (can share)
-rw-r--r-- 1 admin admin 205 Apr 10 08:00 config
-rw-r--r-- 1 admin admin 3867 Apr 10 08:00 known_hostsKey types:
| Type | Bits | Recommendation |
|---|---|---|
ed25519 | 256 | Recommended — modern, fast, secure |
rsa | 4096 | Legacy — widely supported |
ecdsa | 256/384/521 | Older elliptic curve |
Step 2: Copy Public Key to Server
# The easy way (copies to server's authorized_keys)
$ ssh-copy-id [email protected]
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: /home/admin/.ssh/id_ed25519.pub
/usr/bin/ssh-copy-id: INFO: attempting to log into server with new key(s)
[email protected]'s password: ********
Number of key(s) added: 1
# Now you can log in without a password
$ ssh [email protected]Manual method:
# On server, add your public key to authorized_keys
$ cat ~/.ssh/id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# Or directly edit on the server
$ ssh [email protected]
$ mkdir -p ~/.ssh
$ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..." >> ~/.ssh/authorized_keys
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keysHow Key Authentication Works
Client (has private key) Server (has public key in authorized_keys)
| |
| 1. Client: "I'd like to connect" |
|───────────────────────────────────────>
| |
| 2. Server: "Prove yourself - sign this challenge"
|<───────────────────────────────────────|
| |
| 3. Client: Signs with private key |
|───────────────────────────────────────|
| |
| 4. Server: Verifies signature using |
| stored public key → Access granted |
|<───────────────────────────────────────|
SSH Tunneling (Port Forwarding)
Local Port Forwarding
Access a remote service through an SSH tunnel — useful for accessing internal databases or services.
# Forward local port 5432 to remote PostgreSQL's port 5432
# Access remote DB through localhost:5432
$ ssh -L 5432:localhost:5432 admin@prod-server
# Forward local port 8080 to internal app at 10.0.1.50:8080
$ ssh -L 8080:10.0.1.50:8080 admin@bastion-server
# In another terminal, connect as if the DB is local
$ psql -h localhost -p 5432 -U myapp mydbDynamic Port Forwarding (SOCKS Proxy)
# Create a SOCKS proxy on local port 1080
$ ssh -D 1080 admin@bastion-server
# Configure browser to use localhost:1080 as SOCKS proxy
# All traffic routes through the bastionExecuting Remote Commands
Run commands on remote servers without entering an interactive shell:
# Run a single command
$ ssh [email protected] "systemctl status nginx"
● nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
Active: active (running)
# Run with sudo (requires passwordless sudo on server)
$ ssh [email protected] "sudo systemctl restart nginx"
# Run multiple commands
$ ssh [email protected] "df -h && free -h"
# Copy files using SSH (remote to local)
$ scp [email protected]:/var/log/app.log ./app.log
# Copy files (local to remote)
$ scp ./config.yaml [email protected]:/tmp/config.yaml
# Copy entire directory
$ scp -r ./myapp [email protected]:/opt/myappSSH Hardening
Server Configuration — /etc/ssh/sshd_config
# Disable root login
PermitRootLogin no
# Use key-based authentication only
PasswordAuthentication no
PubkeyAuthentication yes
# Change default port (security through obscurity)
Port 2222
# Disable empty passwords
PermitEmptyPasswords no
# Limit users who can SSH in
AllowUsers admin deploy
# Disable agent forwarding unless needed
AllowAgentForwarding no
# Client alive check (detect dead connections)
ClientAliveInterval 300
ClientAliveCountMax 2
# After changes, reload SSH
$ sudo systemctl reload sshBefore disabling password authentication, ensure you have confirmed SSH key access works. If you lock yourself out, you'll need console access to recover.
SSH Jump Host / Bastion
Use a bastion/jump host to reach internal network servers:
# Direct (requires VPN or direct network access)
$ ssh [email protected]
# Via bastion (standard cloud architecture)
$ ssh -J [email protected] [email protected]
# Or via SSH config (preferred)
# In ~/.ssh/config:
# Host webserver
# HostName 10.0.1.50
# ProxyJump [email protected]Quick Reference
| Task | Command |
|---|---|
| Connect to server | ssh user@host |
| Connect with key | ssh -i key.pem user@host |
| Connect on port | ssh -p 2222 user@host |
| Copy remote file | scp user@host:/path local |
| Copy local file | scp local user@host:/path |
| Run remote command | ssh user@host "command" |
| Local port forward | ssh -L local:remote user@host |
| Jump/bastion | ssh -J jumpuser@jumphost user@host |
| Generate key | ssh-keygen -t ed25519 -C "email" |
| Copy public key | ssh-copy-id user@host |
Practice Challenge
- Generate an SSH keypair:
ssh-keygen -t ed25519 -C "your_email" - View your public key:
cat ~/.ssh/id_ed25519.pub - Create a
~/.ssh/configfile with a server alias - Use
ssh-copy-idto install your public key on a test server - Try connecting with
ssh server-alias(using your config nickname) - Use
ssh user@host "df -h"to run a remote command