Skip to main content

🔐 Lesson 7.2: SSH and the Firewall

Connect to remote machines securely and control what traffic enters your system.

🎯 Learning Objectives

  • Connect to remote machines with ssh
  • Set up key-based authentication (no more passwords!)
  • Transfer files with scp and sftp
  • Simplify connections with an SSH config file
  • Enable and configure the UFW firewall

Estimated Time: 45 minutes

📑 In This Lesson

SSH Basics

SSH (Secure Shell) lets you log into another computer over the network and run commands on it — all encrypted. It's how virtually all remote Linux administration happens.

graph LR A["Your Machine
(SSH Client)"] -->|"Encrypted Connection
Port 22"| B["Remote Server
(SSH Server / sshd)"] style A fill:#3b82f6,stroke:#2563eb,color:#fff style B fill:#22c55e,stroke:#166534,color:#fff

Two sides of every SSH connection:

  • Client — your machine, where you type ssh. Installed by default on Ubuntu.
  • Server — the remote machine running sshd (the SSH daemon). Must be installed separately:
# Install the SSH server (on the machine you want to connect TO)
sudo apt install openssh-server

# It starts automatically. Verify:
sudo systemctl status ssh

💡 WSL Users

If you're using WSL (Windows Subsystem for Linux), you can install openssh-server in WSL and connect from Windows PowerShell or another WSL instance for practice. Just remember to start the service: sudo service ssh start (WSL doesn't use systemd by default).

Connecting to a Remote Machine

# Basic connection (prompts for password)
ssh username@192.168.1.100

# Connect using a hostname
ssh ray@devbox

# Connect on a non-standard port
ssh -p 2222 ray@192.168.1.100

# Run a single command without opening a shell
ssh ray@devbox "df -h"

# Run a command and return the output locally
ssh ray@devbox "cat /etc/hostname"

First Connection — The Fingerprint

The very first time you connect to a new server, SSH shows a fingerprint and asks you to verify:

The authenticity of host '192.168.1.100' can't be established.
ED25519 key fingerprint is SHA256:xR3...long-hash...7kQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.1.100' (ED25519) to the list of known hosts.

Type yes to accept. The fingerprint is saved to ~/.ssh/known_hosts so you won't be asked again for that server. If the fingerprint ever changes, SSH will warn you — that could mean the server was reinstalled or, in a worst case, someone is intercepting your connection.

⚠️ "Remote Host Identification Has Changed"

If you see this scary warning, it usually means the server was reinstalled. If you're sure it's safe, remove the old entry: ssh-keygen -R 192.168.1.100 and connect again.

Key-Based Authentication

Typing passwords every time is tedious and less secure. SSH keys use a public/private key pair — you keep the private key on your machine and put the public key on the server. No password needed.

graph LR A["Your Machine
🔑 Private Key
(~/.ssh/id_ed25519)"] -->|"Proves identity"| B["Remote Server
🔓 Public Key
(~/.ssh/authorized_keys)"] style A fill:#3b82f6,stroke:#2563eb,color:#fff style B fill:#22c55e,stroke:#166534,color:#fff

Step 1: Generate a Key Pair

# Generate an Ed25519 key (modern and secure)
ssh-keygen -t ed25519 -C "ray@desktop"

# It will ask:
#   File to save → press Enter for default (~/.ssh/id_ed25519)
#   Passphrase   → optional but recommended (encrypts the private key)

This creates two files:

  • ~/.ssh/id_ed25519 — your private key (NEVER share this!)
  • ~/.ssh/id_ed25519.pub — your public key (safe to share)

Step 2: Copy the Public Key to the Server

# The easy way (does everything for you)
ssh-copy-id ray@192.168.1.100

# Manual way (if ssh-copy-id isn't available):
cat ~/.ssh/id_ed25519.pub | ssh ray@192.168.1.100 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Step 3: Connect (No Password!)

# Now this just works — no password prompt
ssh ray@192.168.1.100

⚠️ Protect Your Private Key

Your private key file should have strict permissions. SSH will refuse to use it if others can read it:

chmod 600 ~/.ssh/id_ed25519
chmod 700 ~/.ssh

🐧 Passphrase + ssh-agent

If you set a passphrase on your key (recommended!), you'll be prompted for it each time. To avoid retyping it, use ssh-agent:

# Start the agent and add your key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Now you can SSH without entering the passphrase until you log out

Transferring Files: SCP and SFTP

scp — Secure Copy

scp works like cp but over SSH. Same syntax: scp source destination.

# Copy a local file TO the remote server
scp myfile.txt ray@devbox:/home/ray/

# Copy a file FROM the remote server to here
scp ray@devbox:/var/log/syslog ./syslog-copy.txt

# Copy an entire directory (recursive)
scp -r ./myproject ray@devbox:/home/ray/projects/

# Use a non-standard port
scp -P 2222 myfile.txt ray@devbox:/home/ray/

sftp — Interactive File Transfer

sftp gives you an interactive session for browsing and transferring files:

# Connect
sftp ray@devbox

# Once connected, you get an sftp> prompt:
sftp> ls                  # List remote files
sftp> cd /var/log         # Change remote directory
sftp> lcd ~/Downloads     # Change LOCAL directory
sftp> get syslog          # Download a file
sftp> put myfile.txt      # Upload a file
sftp> mget *.log          # Download multiple files
sftp> exit                # Disconnect

💡 Modern Alternative: rsync

rsync is the power tool for file syncing — it only transfers changed parts of files, making it much faster for repeated transfers:

# Sync a directory to a remote server
rsync -avz ./myproject/ ray@devbox:/home/ray/projects/myproject/
# -a archive mode (preserves permissions, timestamps, etc.)
# -v verbose
# -z compress during transfer

The SSH Config File

Tired of typing ssh -p 2222 ray@192.168.1.100? Create an SSH config file to define shortcuts.

# Create or edit your SSH config
nano ~/.ssh/config
# ~/.ssh/config

Host devbox
    HostName 192.168.1.100
    User ray
    Port 22
    IdentityFile ~/.ssh/id_ed25519

Host production
    HostName 203.0.113.50
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_production

Host *.internal
    User admin
    ProxyJump bastion

Now you can simply type:

ssh devbox          # Expands to: ssh -i ~/.ssh/id_ed25519 ray@192.168.1.100
ssh production      # Expands to: ssh -p 2222 -i ~/.ssh/id_production deploy@203.0.113.50
scp file.txt devbox:/tmp/   # Works with scp too!

💡 Useful SSH Config Options

OptionWhat It Does
HostNameThe real IP or domain name
UserDefault username
PortPort number (default 22)
IdentityFilePath to the private key
ServerAliveIntervalSend keepalive every N seconds (prevents disconnects)
ProxyJumpSSH through a bastion/jump host first

UFW — The Uncomplicated Firewall

A firewall controls which network traffic is allowed in and out of your machine. Ubuntu ships with UFW — a friendly frontend for the powerful (but complex) iptables.

graph LR A["Internet Traffic"] --> B{"UFW Firewall"} B -->|"Port 22 ✅ Allowed"| C["SSH Server"] B -->|"Port 80 ✅ Allowed"| D["Web Server"] B -->|"Port 3306 ❌ Denied"| E["Blocked"] style A fill:#f59e0b,stroke:#d97706,color:#fff style B fill:#6366f1,stroke:#4338ca,color:#fff style C fill:#22c55e,stroke:#166534,color:#fff style D fill:#22c55e,stroke:#166534,color:#fff style E fill:#ef4444,stroke:#b91c1c,color:#fff
# Check UFW status (disabled by default on Ubuntu Desktop)
sudo ufw status

# Enable the firewall
sudo ufw enable

# Disable the firewall
sudo ufw disable

# Check status with rule numbers (useful for deleting rules)
sudo ufw status numbered

# Check status verbose (shows default policies)
sudo ufw status verbose

⚠️ Allow SSH BEFORE Enabling UFW on a Remote Server

If you're connected to a server via SSH and you enable UFW without allowing SSH first, you will lock yourself out. Always run sudo ufw allow ssh before sudo ufw enable on remote machines.

Managing Firewall Rules

Allowing and Denying Traffic

# Allow by service name
sudo ufw allow ssh          # Port 22
sudo ufw allow http         # Port 80
sudo ufw allow https        # Port 443

# Allow by port number
sudo ufw allow 8080

# Allow a specific port with protocol
sudo ufw allow 53/udp

# Allow from a specific IP
sudo ufw allow from 192.168.1.50

# Allow from a specific IP to a specific port
sudo ufw allow from 192.168.1.50 to any port 22

# Allow from an entire subnet
sudo ufw allow from 192.168.1.0/24

# Deny a specific port (block it)
sudo ufw deny 3306

# Deny from a specific IP
sudo ufw deny from 10.0.0.5

Deleting Rules

# Delete by rule number (check numbers first)
sudo ufw status numbered
sudo ufw delete 3

# Delete by rule specification
sudo ufw delete allow 8080

Default Policies

# Set default policies (deny incoming, allow outgoing is the standard)
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Reset all rules to defaults
sudo ufw reset

💡 Application Profiles

Some packages install UFW profiles that bundle the right ports. You can list and use them:

# List available application profiles
sudo ufw app list

# Get info about a profile
sudo ufw app info "Nginx Full"

# Allow an application profile
sudo ufw allow "Nginx Full"   # Opens ports 80 and 443

🐧 Distro Note

UFW is Ubuntu/Debian-focused. Fedora uses firewalld (managed with firewall-cmd). Arch typically uses iptables or nftables directly. The concepts are the same — only the commands differ.

Exercises

🏋️ Exercise 1: SSH Key Setup

  1. Check if you already have keys: ls -la ~/.ssh/
  2. If no keys exist, generate one: ssh-keygen -t ed25519 -C "your-email"
  3. View your public key: cat ~/.ssh/id_ed25519.pub
  4. If you have another Linux machine or VM, copy the key over: ssh-copy-id user@hostname

🏋️ Exercise 2: SSH Config Shortcut

  1. Create the config file: nano ~/.ssh/config
  2. Add an entry for a machine (real or imagined):
Host myserver
    HostName 192.168.1.100
    User ray
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60

3. Set permissions: chmod 600 ~/.ssh/config

🏋️ Exercise 3: Firewall Practice

  1. Check current status: sudo ufw status verbose
  2. If inactive, allow SSH first: sudo ufw allow ssh
  3. Enable: sudo ufw enable
  4. Allow HTTP and HTTPS: sudo ufw allow http && sudo ufw allow https
  5. Check numbered rules: sudo ufw status numbered
  6. Delete the HTTP rule: sudo ufw delete allow http
  7. Verify: sudo ufw status

Knowledge Check

❓ Question 1

What's the easiest way to copy your SSH public key to a remote server?

❓ Question 2

What should you ALWAYS do before enabling UFW on a remote server?

❓ Question 3

Which file stores SSH connection shortcuts?

❓ Question 4

What command copies a local file to a remote server over SSH?

Summary

🎉 Key Takeaways

  • ssh user@host connects securely to remote machines over port 22
  • ssh-keygen -t ed25519 creates a key pair; ssh-copy-id installs the public key on the server
  • Key-based auth is more secure and convenient than passwords
  • scp copies files over SSH; sftp gives an interactive session; rsync syncs efficiently
  • ~/.ssh/config defines host shortcuts with custom users, ports, and keys
  • UFW is Ubuntu's firewall frontend: ufw allow, ufw deny, ufw status
  • Always allow SSH before enabling UFW on a remote machine!

🍎 On macOS

SSH works identically on macOS — ssh, ssh-keygen, ssh-copy-id, scp, sftp, rsync, and ~/.ssh/config all behave the same way. SSH is pre-installed.

Firewall: macOS doesn't use ufw. Instead, it has two firewall options:

  • Application Firewall (GUI) — System Settings → Network → Firewall. This blocks/allows incoming connections per application.
  • pfctl (command line) — a powerful packet filter for advanced users. Configuration lives in /etc/pf.conf.

For most Mac users, the GUI firewall is sufficient. Enable it in System Settings and it will prompt you whenever a new app tries to accept incoming connections.

🎉 Module 7 Complete!

You now know how to navigate networks, connect to remote machines securely, and protect your system with a firewall. Time to automate things with shell scripts!

🚀 What's Next?

Module 8 introduces Shell Scripting — writing your own Bash scripts to automate repetitive tasks.