01 · Server Basics & SSH Access¶
Before you can administer a server you need to know what kind of thing you're actually logging into, and how to get a secure shell on it. This module covers the mental model and the first login.
What "a server" actually is¶
In practice you'll meet three flavors of "server," and the day-to-day admin work is almost identical on all three:
- Physical server — a real machine in a rack (or under someone's desk). You reach it via an out-of-band management interface (iDRAC/iLO/IPMI) or physically, then SSH once the OS is up.
- Virtual machine (VM) — a slice of a physical host's CPU/RAM/disk, managed by a hypervisor (KVM, VMware, Hyper-V). Feels like a real machine to the OS running on it.
- Cloud instance — a VM (or occasionally bare metal) provisioned through a cloud provider's API (AWS EC2, GCP Compute Engine, Azure VM, DigitalOcean Droplet, Hetzner Cloud, etc.), billed by the hour/month, with the provider handling the hypervisor and physical hardware entirely.
For this course, assume a fresh Ubuntu/Debian-family cloud instance or VM with only SSH access — that's the most common starting point in the real world and everything here transfers directly to bare metal.
SSH: your primary interface to the server¶
SSH (Secure Shell) gives you an encrypted remote shell. Almost everything
else in server administration — file transfer (scp/rsync), port
forwarding, running remote commands — is built on top of it.
First connection¶
The first time you connect to a given host, SSH shows you the server's host key fingerprint and asks you to confirm it:
The authenticity of host '203.0.113.10 (203.0.113.10)' can't be established.
ED25519 key fingerprint is SHA256:abcd1234...
Are you sure you want to continue connecting (yes/no/[fingerprint])?
Accepting this stores the key in ~/.ssh/known_hosts on your local machine.
On a real deployment, verify the fingerprint out-of-band (from your cloud
provider's console output, for instance) before typing "yes" — this is the
step that protects you from a machine-in-the-middle silently swapping in a
different server.
Generating and using an SSH key pair¶
Password auth over SSH is workable but weaker and slower than key-based auth (we'll disable it entirely in the hardening module). Generate a key pair on your local machine, not the server:
-t ed25519— a modern, fast, secure key type. Use-t rsa -b 4096only if you must support very old systems that lack ed25519 support.-C— a comment, purely for your own bookkeeping (shows up next to the key wherever it's listed).-f— output path. Omit it andssh-keygenwill prompt interactively.
This produces two files:
~/.ssh/id_ed25519— your private key. Never copy this to a server, paste it anywhere, or commit it to a repo. Treat it like a password.~/.ssh/id_ed25519.pub— your public key. Safe to share; this is what gets installed on servers you want to access.
Copy the public key to the server (if you still have password access, or the provider lets you paste a key at instance-creation time):
ssh-copy-id appends your public key to ~/.ssh/authorized_keys on the
remote user's home directory. If ssh-copy-id isn't available, the manual
equivalent is:
cat ~/.ssh/id_ed25519.pub | ssh root@203.0.113.10 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
The permission bits matter: SSH refuses to trust authorized_keys if the
.ssh directory or the file itself is group- or world-writable.
A minimal local SSH config¶
~/.ssh/config on your local machine lets you avoid retyping hostnames,
users, and key paths:
Now ssh webserver connects with the right user and key automatically —
useful once you're managing more than one host.
Worked example: first login and a sanity check¶
# Connect using the alias defined above
ssh webserver
# Once connected, confirm who and where you are
whoami
hostname
uname -a
cat /etc/os-release | grep PRETTY_NAME
df -h /
free -h
Typical output on a fresh 1 vCPU / 1 GB cloud instance:
deploy
web-01
Linux web-01 6.8.0-31-generic #31-Ubuntu SMP x86_64 GNU/Linux
PRETTY_NAME="Ubuntu 24.04.1 LTS"
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 25G 1.8G 22G 8% /
total used free shared buff/cache available
Mem: 957Mi 112Mi 650Mi 0.0Ki 194Mi 688Mi
That's your baseline: OS version, disk headroom, and memory. You'll come back
to df -h and free -h constantly once the server is doing real work.
Not literally executed against a live server
The commands and output above are correct and runnable as written, but this course text is generated rather than run against a real cloud instance — treat sample output as representative, not as a captured transcript, and verify against your own server.
How It Actually Works¶
The TCP handshake and the SSH transport layer. ssh webserver first opens
a plain TCP connection to port 22 (SYN → SYN-ACK → ACK). Only after that does
SSH's own protocol begin: client and server exchange version banners, then
negotiate a shared set of algorithms (key exchange, host-key type, cipher,
MAC) by each sending an ordered list of what they support — the first mutual
match wins. A Diffie-Hellman (or, on modern OpenSSH, Curve25519) key exchange
then derives a shared secret over the insecure channel without ever
transmitting it: each side sends a public value computed from a private
random number, and both combine the other's public value with their own
private one to reach the same shared secret, which an eavesdropper capturing
only the public values cannot reconstruct. This secret seeds symmetric
session keys (typically chacha20-poly1305 or AES-GCM) — from this point every
byte of the session, including your login prompt and file transfers, is
encrypted with those symmetric keys, which is why SSH is fast despite the
expensive asymmetric math happening only once at setup.
Why the host-key fingerprint check exists. The DH exchange above proves
you share a secret with whoever answered on port 22 — not that it's the
right machine. The server proves its identity separately by signing part of
the handshake with its long-lived host private key; your client checks that
signature against the public host key it already trusts (from
known_hosts) or asks you to trust on first use. Skip that verification and
a machine-in-the-middle can complete its own valid-looking handshake with
you while relaying to the real server, reading everything in between.
Why key-based auth resists what password auth doesn't. After the
transport layer is established, SSH negotiates authentication on top of it.
Public-key auth works because your client signs a challenge (a hash derived
from the session) with your private key, and the server verifies that
signature using the public key already sitting in authorized_keys — this
proves possession of the private key without ever sending it, so there's no
password to brute-force or phish over the wire. The chmod 700/600
requirement on .ssh and authorized_keys isn't cosmetic: sshd refuses to
honor an authorized_keys file that group- or world-writable permissions
could let another local user tamper with, closing a local-privilege-escalation
path.
Exercise¶
- Spin up a free-tier or lowest-cost VM from any provider you have access to (or a local VM via VirtualBox/UTM/multipass if you'd rather not spend money), running Ubuntu 22.04 or 24.04.
- Generate a new ed25519 key pair dedicated to this course (don't reuse a key you use elsewhere).
- Get the public key onto the server and confirm you can
sshin without being prompted for a password. - Add a
Hostentry for it in your local~/.ssh/configand confirmssh <alias>works. - Run
uname -a,cat /etc/os-release,df -h, andfree -hand note the values — you'll compare against them again in later modules.