Building Your Lab
A hypervisor, Linux + Windows Server VMs, containers, and an optional GPU
Appendix A — Building Your Lab
“For which of you, desiring to build a tower, does not first sit down and count the cost, whether he has enough to complete it?” — Luke 14:28 (ESV)
You cannot administer infrastructure by reading about it. The keyboard is the gym, and this appendix builds your gym. But before you install a single thing, you have to make one honest decision: how will you run this lab, given the laptop you actually own and the permissions you actually have? Many of you are on a Windows or Mac machine — possibly a locked-down school or work laptop where you can’t install a hypervisor or change a BIOS setting, possibly an 8 GB machine, possibly an Apple Silicon Mac where x86 Windows is painful. None of that stops you. It just decides which of two paths you take.
This appendix gives you both. Path A is a cloud lab that needs nothing installed on your laptop and no admin rights at all — the easy, cheap default, built on free tiers. Path B is a local lab of real virtual machines on your own hardware — free and the most hands-on, but it needs admin rights and a capable machine. Read A.1, pick your path, and build.
A word before you start. Do the work yourself. Don’t paste a setup script you found and call your lab built. Type the commands, watch them fail, read the error, fix it. The first time a VM won’t get an IP or a container can’t reach the host, you are learning the thing the chapter is actually about. That hour of friction is the rep.
One honest caveat, repeated throughout: prices, free-tier limits, and versions in this appendix are approximate and dated to 2026. Cloud free tiers change without warning — Oracle quietly cut its free ARM allotment in half in mid-2026, and any vendor can do the same. Treat every dollar figure and every “free” allotment as a snapshot, and re-verify against the vendor before you commit money or a deadline to it.
A.1 — Choose Your Lab Path
Here is the situation, stated plainly so you can size it. This is a system-administration course, so the projects need real infrastructure — but far less of it than you might fear. The backbone of almost every project is a single Linux machine with a container runtime. That one thing carries the large majority of the work. On top of that backbone, a handful of labs are richer with extras: a couple are about GPUs (mostly to read about and observe — you rent one by the hour only if you want to), the cloud chapter needs a cloud account (which Path A hands you for free anyway), and Windows Server appears as something to learn, not a hard gate on any project. So:
You do not need a powerful PC, and you do not need administrator rights on your laptop. You need one of the two paths below, plus a way to rent a GPU for an hour on the few weeks that want one.
Pick by your situation:
| Your situation | Take this path |
|---|---|
| You have admin rights, 16 GB+ RAM, and an Intel/AMD machine (or you’ll run ARM Linux on Apple Silicon) | Path B — Local VMs (A.3+). Free, most hands-on, closest to a real host. |
| Locked-down / school / work laptop, no admin rights, 8 GB RAM, Apple Silicon, or you just want the cheapest path that works | Path A — Cloud lab (A.2). Nothing to install locally, no BIOS changes, free tiers. |
| Somewhere in between | Hybrid. Run Linux + containers locally (Path B), and use the cloud (Path A) for the Windows half, the cloud chapter, and any GPU. That split is itself a realistic enterprise pattern. |
What every path must give you, by the end: a Linux box you control as root, a container runtime on it, access to a Windows Server when a lab wants one, and a way to reach a GPU for the few labs that are actually about the GPU. Path A and Path B both deliver all four — they just differ in where the machines live and what you had to install.
What each project actually needs (so you never over-provision — the architect’s habit, applied to your own lab):
| Project | Minimum lab | GPU? |
|---|---|---|
| P1 Runbook→Copilot, P3 Identity, P8 IaC, P10 Security ops, P13 Pipeline | One Linux box (+ containers); an LLM via a cloud API key or local Ollama on CPU | No |
| P2 Diagnose, P5 Network, P7 Containers, P9 Observability, P11 Backup/DR | One (or two) Linux boxes + containers | Optional |
| P4 Size the Estate, P6 Carve the GPU | Mostly the chapter’s interactive widget + the sizing math | Read/observe; rent 1 hr only to do it for real |
| P12 Cloud admin | A cloud account (Azure for Students / a free tier) — Path A already has this | Optional (rent by the hour) |
| P14 Capstone | Your choice of the above, plus a written architecture | Optional |
Notice what’s not there: no project forces you to stand up a Windows Server, and no project forces you to own a GPU. Build the backbone well; rent the rest by the hour.
Coach’s Note — The single most expensive mistake students make here is deciding they need a $1,500 GPU laptop to take a sysadmin course. You don’t. A $0 cloud Linux box and an occasional $1 rented GPU will carry you through all sixteen weeks. Counting the cost (Luke 14:28) starts with your own lab.
A.2 — Path A: A Cloud Lab With No Admin Rights (the easy, cheap default)
This path installs nothing on your laptop, changes no BIOS setting, and needs no administrator rights. You connect to machines that live in the cloud, from any Windows or Mac computer, using tools that ship with the operating system. It is the right default if your machine is locked down, low on RAM, Apple Silicon, or you simply want the path of least resistance.
A.2.1 — The free Linux box that is your backbone
Get one Linux server in the cloud and you have the foundation for almost everything. Three good ways, cheapest first:
- Oracle Cloud Always Free (recommended free option). Oracle’s free tier includes an Always Free Arm (Ampere A1) virtual machine — as of mid-2026, about 2 OCPUs and 12 GB of RAM total (it was 4/24 before a mid-2026 cut — verify the current limit), plus 200 GB of block storage and a generous 10 TB/month of egress, free for as long as you keep it. Twelve gigabytes of RAM and two Arm cores is a genuinely capable Linux+containers host. The catches: the sign-up asks for a card for identity verification (it isn’t charged on Always Free), Arm (aarch64) means you pull
arm64container images, and instances that exceed the free limits get shut down — so stay inside them. Provision an Ubuntu 24.04 (Arm) instance and you’re done. - Azure for Students (recommended if you’re enrolled). $100 in credit, no credit card required, verified with your school email; it renews each year you’re still a student. Spin up a small Linux VM from it. The same credit also gives you the Windows half (A.2.3) and the cloud-AI services in Chapter 12 — one account, most of your needs. (AWS and Google Cloud also offer student/free programs and ~$300 trial credits; any of them works.)
- A cheap VPS (recommended if you want x86 and no Oracle sign-up). A small instance at Hetzner (
€4/month, 2026), DigitalOcean, Linode/Akamai, or Vultr ($4–6/month) gives you a clean x86 Ubuntu box you fully control. A few dollars a month, destroyed when the course ends, is the least-friction paid option.
Connect from Windows or Mac — no admin required. An SSH client ships built in with both:
# macOS Terminal, or Windows Terminal / PowerShell (OpenSSH is built into Windows 10/11):
ssh ubuntu@<your-server-ip> # no install, no admin rights needed
# generate a key first (also built in) and paste the .pub into the cloud console:
ssh-keygen -t ed25519 -C "sysadmin-lab"
Most clouds also give you a browser-based shell (Azure Cloud Shell, OCI Cloud Shell, AWS CloudShell) — a terminal in a web page that needs nothing on your machine at all. That is your ultimate fallback on the most locked-down laptop.
Once you’re in, you are root on your own server — the exact thing a sysadmin needs — and the entire Linux side of this book (A.5’s baseline tools, A.7’s containers, A.8’s networking concepts) applies unchanged.
A.2.2 — Containers and quick labs, with nothing installed locally
- Install Docker/Podman on your cloud Linux box (you’re root there) using the steps in A.7. That’s the durable home for the container labs.
- GitHub Codespaces — a full Linux dev environment (VS Code in your browser, with Docker available) that needs nothing installed and no admin. Free personal accounts get about 120 core-hours/month (~60 hours on a 2-core machine) and 15 GB (2026; verify). Perfect for the container and CI labs when you don’t want to manage a server.
- Throwaway browser sandboxes for a single quick exercise: Killercoda, Play with Docker, and Play with Kubernetes give you a real root shell (and even multi-node Kubernetes) in a browser tab for a time-limited session, free. Ideal for “I just need to try this one command” — useless for anything you need to keep.
A.2.3 — The Windows Server half (when a lab calls for it)
No project requires Windows Server, but you’ll learn the enterprise better with one. The cheapest no-admin way is a Windows Server VM from your Azure for Students credit (or any cloud): create it, connect over RDP (Microsoft Remote Desktop is a free app on both Windows and Mac), do the lab, and delete it when you’re done so it stops drawing on your credit. Running x86 Windows Server in a local VM on an Apple Silicon Mac is the one genuinely hard case — this cloud route sidesteps it entirely.
A.2.4 — A GPU when a lab is actually about the GPU
You almost certainly don’t own an NVIDIA GPU, and you don’t need to. Use a free notebook (Google Colab, Kaggle) for “load a model and watch it generate,” or rent a real GPU by the hour (RunPod, Lambda, Vast.ai, or a hyperscaler) for the labs that administer the hardware. Full details, costs, and the all-important teardown discipline are in A.9 — they apply to both paths.
A.2.5 — Verify Path A end to end
ssh ubuntu@<your-server-ip> # you're in, from a stock laptop, no admin
hostnamectl # confirms it's a cloud VM (e.g. virtualization: kvm)
ip -brief addr && ping -c 3 1.1.1.1 # address + outbound internet
docker run --rm hello-world # after installing Docker per A.7
If those four lines work, your cloud lab is real — and you never touched your laptop’s settings. Now mind the money: on a free tier, stay inside the limits; on anything paid, set a budget alert and delete instances you’re done with. A forgotten cloud VM is the cloud-era version of leaving the lights on.
A.3 — Path B: A Local Lab (free, most hands-on — needs admin + a capable machine)
If you have administrator rights on a reasonably capable machine, building the lab locally is free, completely under your control, and the closest thing to running a real virtualization host. It does require admin rights — to install a hypervisor and to enable hardware virtualization (Intel VT-x / AMD-V) in firmware — which is exactly why Path A exists for everyone who doesn’t have them.
Your minimum local lab is four pieces:
| Piece | Purpose | Our default |
|---|---|---|
| Hypervisor | Runs the VMs | VirtualBox (free) or Proxmox (homelab/server) |
| Linux VM | The administrator’s daily workhorse | Ubuntu Server 24.04 LTS |
| Windows Server VM | The other half of the enterprise (optional) | Windows Server 2025 (180-day eval) |
| Container runtime | Where modern workloads live | Docker or Podman, on the Linux VM |
The hardware floor: a 64-bit machine with hardware virtualization (Intel VT-x / AMD-V), 16 GB RAM (32 GB is much more comfortable once you run two VMs and containers at once), and ~120 GB of free disk. If you have an Apple Silicon Mac, note up front that x86 Windows Server in a VM is painful there — use the cloud Windows route in A.2.3 for the Windows half. (Your Linux half is fine on Apple Silicon — see A.5.)
Coach’s Note — Build the lab once, snapshot it often. Every hypervisor here supports VM snapshots. Before any project that touches system state, take a snapshot. When you break it — and you will, that’s the point — roll back in thirty seconds instead of rebuilding in an afternoon. A sysadmin who can’t recover their own lab won’t recover production either.
A.4 — Choosing a Hypervisor
Four reasonable choices. They differ in cost, where they run, and how “production-shaped” the experience is.
| Hypervisor | Type | Cost (approx., 2026) | Runs on | Best for |
|---|---|---|---|---|
| VirtualBox | Type 2 (on your OS) | Free (GPLv3; Oracle) | Win/Linux/Intel Mac | Starting out, x86 laptops |
| VMware Workstation Pro / Fusion | Type 2 | Free for personal use | Win/Linux/Mac | Polished desktop VMs |
| Proxmox VE | Type 1 (bare metal) | Free (AGPL; paid support optional) | A dedicated box | A real homelab/server, clustering, PCIe passthrough |
| Hyper-V | Type 1 (built into Windows) | Included w/ Win Pro/Server | Windows | Windows shops, WSL2 users |
My recommendation depends on your situation:
- One laptop, just getting going? VirtualBox. It’s free, cross-platform on x86, and every command in this book works on it.
- Have a spare machine to dedicate? Proxmox VE. It’s a Type 1 hypervisor you administer over a web UI and
ssh, supports clustering, ZFS, and — critically for the GPU chapters — PCIe passthrough. This is the closest thing to running a real virtualization host on your own hardware. - Live in the Microsoft world / use WSL2 already? Hyper-V. (Note: Hyper-V and VirtualBox fight over the virtualization stack on the same Windows host. Pick one as primary.)
Type 1 vs Type 2 is worth fixing in your head now because Chapter 6 lives here. A Type 1 (bare-metal) hypervisor — Proxmox, Hyper-V, ESXi — runs directly on the hardware; the VMs are the only thing on the box. A Type 2 hypervisor — VirtualBox, VMware Workstation — runs as an application on top of your normal OS. Type 1 gives you better isolation and the hardware features (IOMMU, SR-IOV) that GPU passthrough needs; Type 2 is more convenient on a machine you also use for everything else.
Verify hardware virtualization is on before you install anything (this step needs admin). On Linux:
# Non-zero means VT-x/AMD-V is present and enabled in firmware
egrep -c '(vmx|svm)' /proc/cpuinfo
# Confirm KVM is usable (for Linux-native hypervisors / Proxmox guests)
sudo apt-get install -y cpu-checker && sudo kvm-ok
On Windows (PowerShell as admin):
# "VirtualizationFirmwareEnabled : True" is what you want
Get-ComputerInfo -Property "HyperV*"
systeminfo | findstr /i "virtualization"
If virtualization is off, it’s a firmware/BIOS setting (often “Intel VT-x,” “AMD SVM,” or “SVM Mode”) — reboot into firmware and enable it. If you can’t get into firmware or don’t have admin, that’s your signal to use Path A instead — don’t fight it.
A.5 — The Linux VM (Ubuntu Server)
Ubuntu Server 24.04 LTS is the default Linux for this book: long-term support through 2029, the largest body of documentation, and the distro most cloud images assume. (Debian 12 is an equally fine choice if you prefer it; commands are nearly identical. RHEL-family — Rocky/Alma — uses dnf instead of apt.) Everything in this section applies equally to a Path A cloud Linux box — you’re just SSH’d into it instead of opening a console window.
Get the image and build the VM:
- Download the Ubuntu Server 24.04 LTS ISO from
ubuntu.com/download/server. Verify the checksum — this is a sysadmin reflex, not paranoia:
# Compare against the SHA256SUMS published next to the ISO
sha256sum ubuntu-24.04.*-live-server-amd64.iso
-
Create the VM: 2 vCPU, 4 GB RAM (8 GB if you’ll run containers with models), 40 GB disk. Attach the ISO and install. Choose the minimal install, enable OpenSSH during setup, and skip the snap bundles you don’t need.
-
After first boot, update and install the baseline tools:
sudo apt-get update && sudo apt-get -y upgrade
sudo apt-get install -y \
build-essential git curl wget htop \
net-tools dnsutils tmux jq unzip ca-certificates
Verify the VM is healthy:
hostnamectl # OS, kernel, virtualization (should say e.g. "oracle" or "kvm")
ip -brief addr # the VM has an IP
ping -c 3 1.1.1.1 # outbound network works
systemctl is-system-running # "running" (or "degraded" — then check failed units)
Coach’s Note — On a local VM, install the guest additions / guest agent for your hypervisor (
virtualbox-guest-utils,open-vm-tools, orqemu-guest-agenton Proxmox). It’s the difference between a VM that resizes cleanly, shares a clipboard, and reports its IP to the host, and one that fights you. (On a cloud VM you can skip this — the cloud agent is already there.)
Apple Silicon / Arm note: Ubuntu Server for ARM64 runs natively under UTM or VMware Fusion on Apple Silicon — download the arm64 ISO instead of amd64. (An Oracle Always Free instance is Arm too, so the same arm64 world applies in the cloud.) Your Linux half is fine on a Mac. It’s the Windows half that’s the problem — use A.2.3.
A.6 — The Windows Server VM (Evaluation) — Optional
You administer Windows whether you love it or not, and you’ll understand the enterprise better with a Windows Server to poke at — though, again, no project hard-requires it. Microsoft ships a free evaluation that’s perfect for the lab.
- Windows Server 2025, 180-day evaluation, downloadable from the Microsoft Evaluation Center (
microsoft.com/evalcenter). The eval is fully functional; it just stops after 180 days. You canslmgr /rearmto extend it a limited number of times, or just rebuild from a snapshot — which is good practice anyway. - Build it with 4 GB RAM minimum (more for the Desktop Experience GUI), 2 vCPU, 50 GB disk.
- Choose Server Core (no GUI, administered by PowerShell and remoting — the way real servers run) or Desktop Experience (full GUI). I recommend starting with Desktop Experience to learn the roles visually, then rebuilding as Core once you’re comfortable.
Verify and baseline it (PowerShell):
Get-ComputerInfo -Property OsName, OsVersion, WindowsInstallationType
Get-Date # check the clock — eval clock matters
Test-NetConnection 1.1.1.1 -InformationLevel Quiet # outbound network works
Get-NetIPConfiguration # the VM has an IP/gateway
Apple Silicon / no-admin reality check: there is no supported x86 Windows Server eval that runs well on Apple Silicon, and a locked-down laptop can’t install one anyway. On a Mac, or without admin, do the Windows labs on a cloud Windows Server instance (A.2.3 — Azure for Students is the cheapest), connect over RDP, and delete it when done. That split is itself a realistic enterprise pattern.
A.7 — Container Runtime: Docker or Podman
Containers run on your Linux box — local VM or cloud, it’s identical. Two mainstream choices:
- Docker — the default everyone knows; daemon-based; Docker Compose for multi-container stacks. Docker Engine (the daemon + CLI on Linux) is free and open source. Docker Desktop is a separate paid product for orgs over the free-use threshold — you don’t need it; install Docker Engine directly on the Linux box.
- Podman — daemonless, runs containers rootless by default (a real security advantage), drop-in CLI compatibility with Docker (
alias docker=podmanworks for most things), andpodman-compose/ Quadlet for orchestration. Red Hat’s default.
For this book either works; commands are nearly identical. I’ll show Docker because it’s what most documentation assumes, and note Podman where it differs.
Install Docker Engine on Ubuntu (the official convenience path):
# Official Docker install script
curl -fsSL https://get.docker.com | sudo sh
# Run docker without sudo (log out/in after this)
sudo usermod -aG docker "$USER"
# Enable on boot
sudo systemctl enable --now docker
Install Podman instead:
sudo apt-get install -y podman
Verify the runtime works end to end:
docker --version
docker run --rm hello-world # pulls + runs a tiny image; prints a success message
docker run --rm -p 8080:80 -d --name web nginx # a real service
curl -s localhost:8080 | head -n 5 # confirm it serves
docker rm -f web
# Podman equivalents:
podman --version
podman run --rm hello-world
If hello-world pulls and prints its success message, your runtime, networking, and DNS are all working. If the pull hangs, it’s almost always DNS or a proxy — check /etc/resolv.conf. (On an Arm box — Oracle Always Free or Apple Silicon — Docker pulls arm64 images automatically; a rare image that’s x86-only will tell you so.)
Coach’s Note — This is the very split Chapter 7 hammers: the container runtime is the floor, the front-end and the engine are separate layers on top. When you later run Ollama or vLLM in a container and put Open WebUI in front of it, you’ll be standing on exactly this foundation. Get it solid now.
A.8 — Networking Basics: Making the VMs Talk
Most “my lab is broken” problems are networking. (If you took Path A, your cloud provider handles most of this for you — but read it anyway, because Chapter 5 is this, and a cloud “security group” is just a firewall with a friendlier name.) Three VM network modes you must understand, because choosing wrong is the #1 cause of “the VM has no internet” and “I can’t reach the VM from my laptop”:
| Mode | VM gets internet? | Host can reach VM? | Other VMs can reach it? | Use it for |
|---|---|---|---|---|
| NAT | Yes | Only via port-forward | No (separate NATs) | A single VM that just needs outbound internet |
| Bridged | Yes (own IP on your LAN) | Yes | Yes | VMs that act like real machines on your network |
| Host-only / Internal | No (by default) | Yes | Yes | A private lab network between VMs |
The pattern I recommend for a two-VM local lab: give each VM two adapters — one NAT (for outbound internet / updates) and one host-only (a private 192.168.56.0/24-style network where your Linux and Windows VMs talk to each other and to the host). That mirrors a real DMZ-plus-internal-network shape and keeps your lab traffic off your home LAN.
Verify connectivity, layer by layer (the order matters — diagnose bottom-up):
# 1. Does the VM have an address on each adapter?
ip -brief addr
# 2. Is there a default route (a gateway out)?
ip route
# 3. Can it resolve names? (DNS — the most common silent failure)
getent hosts ubuntu.com || nslookup ubuntu.com
# 4. Can it reach the host on the private network? (replace with host's host-only IP)
ping -c 3 192.168.56.1
# 5. Can it reach the OTHER VM? (replace with the Windows VM's host-only IP)
ping -c 3 192.168.56.20
# 6. Is a service actually listening where you think?
ss -tlnp
On the Windows VM, the equivalents are ipconfig /all, Resolve-DnsName ubuntu.com, Test-NetConnection <ip> -Port <port>, and Get-NetTCPConnection -State Listen. Remember Windows Firewall blocks inbound ping (ICMP) and most ports by default — if the Linux VM can’t reach a Windows service, the firewall is the first suspect, not the network. (In the cloud, the equivalent first suspect is the security group / firewall rule — open the port there before you blame the app.)
Coach’s Note — When something can’t connect, walk the layers from the bottom: link → address → route → DNS → reachability → port → application. Nine times in ten the break is DNS or a firewall, and you’ll find it in under a minute if you don’t skip steps. Guessing wastes the afternoon; the checklist takes ninety seconds.
A.9 — Getting a GPU When a Lab Needs One
Most of this book runs fine on CPU. But several chapters — local model serving, quantization, GPU virtualization (MIG/passthrough), container-served LLMs — are far more instructive with a real NVIDIA GPU, and a few are genuinely about the GPU. You almost certainly don’t own one, and you don’t have to. Three honest options; pick by how often you’ll need it and what you already own.
Option 1 — A workstation GPU (you own the hardware). Buy or borrow a machine with an NVIDIA GPU and run everything locally. A used 24 GB card (e.g., an RTX 3090, ~$700–$1,000 on the secondary market, 2026) comfortably serves a quantized 7B–13B model and lets you actually do the passthrough and MIG-adjacent labs on your own iron. Pro: zero marginal cost once owned, full control, real PCIe passthrough. Con: large up-front cost, and consumer cards don’t support every datacenter feature (full MIG needs A100/H100-class hardware — you’ll read about it, not run it, on a consumer card). Do not buy hardware for this course; rent.
Option 2 — A cloud GPU instance (rent by the hour). Spin up a GPU VM, do the lab, destroy it the moment you’re done. This is the right default for most students: you pay only for the hours you use, and you can reach hardware (A100, H100) you’d never buy.
| Source (2026, approximate) | Rough cost | Notes |
|---|---|---|
| Hyperscaler on-demand (AWS/Azure/GCP), 1× mid-tier GPU (e.g., L4/A10-class) | ~$1–$2 / hr | Easiest to integrate with the rest of the cloud; priciest per hour |
| Hyperscaler 1× A100/H100 (80 GB) | ~$3–$8+ / hr on-demand | What you want for 70B-class or MIG-flavored labs |
| Specialist GPU clouds (e.g., Lambda, RunPod, Vast.ai-style marketplaces) | often ~$0.30–$2+ / hr for consumer/older cards | Cheapest path to a usable GPU by the hour; availability varies |
| Spot / preemptible instances | ~50–70% off on-demand | Can be reclaimed mid-job — fine for labs, not for anything you can’t restart |
The discipline that saves you money: set a budget alert, tag the instance, and tear it down. A forgotten H100 left running overnight is a real and famous way to lose a few hundred dollars. Treat the teardown as part of the lab.
# After provisioning a cloud GPU VM, confirm the GPU is visible and the driver is live:
nvidia-smi
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv
# Confirm a container can see the GPU (needs the NVIDIA Container Toolkit installed):
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
If nvidia-smi works on the host but the container can’t see the GPU, you’re missing the NVIDIA Container Toolkit — install it and re-run; that’s the bridge between Docker and the GPU you’ll use in Chapter 7.
Option 3 — A managed notebook (zero setup, free). For a single experiment where you don’t want to manage a VM at all, a hosted notebook gives you a GPU behind a Jupyter interface:
- Google Colab — a free tier with a (time-limited, not-guaranteed) GPU, and a paid tier (~$10/month, 2026) for better/longer access. Easiest possible on-ramp.
- Kaggle Notebooks — free GPU/TPU hours per week, no card required.
- Hugging Face Spaces — free CPU Spaces; paid GPU Spaces (billed by the hour while running).
Managed notebooks are perfect for “I just need to load a model and see it generate tokens” and useless for “I need to configure the host, the driver, and passthrough.” Use them for the quantization and embedding labs; use Option 1 or 2 for anything that’s actually about administering the GPU.
Coach’s Note — Match the tool to the job, the same way you’ll match a model tier to a workload all through this book. Reading about MIG? A cheap notebook or no GPU at all is fine. Administering a GPU — drivers, the container toolkit, passthrough? Rent a real cloud instance by the hour. Don’t buy an H100 to run
hello-world, and don’t try to learn passthrough on a notebook that hides the hardware from you.
A teardown checklist for rented GPUs — run it every single time:
# 1. Confirm nothing is mid-flight you'll lose
nvidia-smi # any processes still using the GPU?
# 2. Pull anything you need OFF the box (models, logs, results)
# 3. Stop and DELETE the instance from the cloud console (stopping a GPU VM
# sometimes still bills for the GPU reservation — DELETE, don't just stop)
# 4. Check the billing dashboard the next morning. Verify the spend stopped.
A.10 — Verifying the Whole Lab
Before you call the lab built, prove every piece end to end. This is your acceptance test — run it now, and re-run it whenever something feels off. (Run the parts that apply to your path; a Path A student skips the host-only-VM lines.)
# --- On your Linux box (local VM or cloud) ---
hostnamectl # OS + virtualization confirmed
ip route && getent hosts ubuntu.com # network + DNS
docker run --rm hello-world # container runtime
ss -tlnp # know what's listening
# (Path B only) reach the Windows VM over the private network (use its host-only IP)
ping -c 3 192.168.56.20
# (If you have a GPU available, local or cloud)
nvidia-smi && docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
# --- On the Windows VM, if you built one (local or cloud) ---
Get-ComputerInfo -Property OsName, OsVersion
Test-NetConnection 1.1.1.1 -InformationLevel Quiet # internet
Test-NetConnection <linux-box-ip> -Port 22 # reach the Linux box's SSH
If every command that applies to your path returns what you expect, your lab is real. On a local lab, take a snapshot of each VM in a known-good state and label it baseline. On a cloud lab, note the exact steps to recreate the box (or save an image) — your baseline is reproducibility, not a snapshot.
A.11 — The Course Toolkit (Install Once — Nothing Your Instructor Has to Hand Out)
Everything the projects use, in one place, installed on your lab box (where you are root) — not on your laptop. You never wait on a hand-out: this section is the install list. Run the base bootstrap once; reach for a per-project extra only when a project calls for it. All of it is free and works with no admin rights on your own machine, because it all runs on the cloud (or local) Linux box from A.2/A.3.
The base bootstrap — run once on your Linux box, then verify:
sudo apt-get update
sudo apt-get install -y git curl wget jq unzip ca-certificates \
python3 python3-pip python3-venv sysstat net-tools dnsutils
# Docker Engine (A.7) and Ollama (Appendix B) if a project needs them:
curl -fsSL https://get.docker.com | sudo sh && sudo usermod -aG docker "$USER" # log out/in after
curl -fsSL https://ollama.com/install.sh | sh # local LLM on CPU is fine
# Verify the toolkit is alive:
git --version && python3 --version && docker --version && docker compose version
Python work goes in a virtual environment (this is the venv Appendix B refers to). Make one per
project and install into it — never sudo pip:
python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install openai pyyaml # the two most-used; add per-project libs below
Per-project extras — install the row you need, when you need it. Every one is no-admin (it runs on your lab box or in the browser):
| Need it for | Tool | One command (on your lab box) |
|---|---|---|
| P2 (I/O triage) | iostat | sudo apt-get install -y sysstat (already in the bootstrap above) |
| P4, P11 (vectors / DB) | Postgres + pgvector | docker run -d --name pgv -e POSTGRES_PASSWORD=devpass -p 5432:5432 pgvector/pgvector:pg17 then docker exec -it pgv psql -U postgres -c "CREATE EXTENSION vector;" |
| P7 (2nd model backend, no GPU) | llama.cpp server | docker run -d -p 8080:8080 -v "$PWD/models:/models" ghcr.io/ggml-org/llama.cpp:server -m /models/<model>.gguf |
| P8 (IaC) | Ansible + lint | pipx install --include-deps ansible && pipx inject ansible ansible-lint (or pip install ansible ansible-lint in a venv) |
| P8 (IaC) | Terraform (or OpenTofu) + tflint | sudo snap install --classic terraform (or download the OpenTofu binary); tflint via its install script |
| P8 (Ansible modules) | community.general | ansible-galaxy collection install community.general |
| P11 (backups) | aws CLI | sudo apt-get install -y awscli (or use AWS CloudShell, which ships it) |
| P11 (WORM/immutable backup, no AWS bill) | MinIO w/ object-lock | docker run -d -p 9000:9000 -p 9001:9001 -e MINIO_ROOT_USER=admin -e MINIO_ROOT_PASSWORD=devpass123 minio/minio server /data --console-address ":9001" — then make an object-lock bucket (mc mb --with-lock local/wormbucket). This is the free, local stand-in for S3 Object Lock; LocalStack (docker run -p 4566:4566 localstack/localstack) is the alternative. |
| P13 (CI gates) | ruff, pytest | pip install ruff pytest (in your venv) |
| P13, P8 (secret scan) | gitleaks | curl -sSL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_$(uname -s)_$(uname -m).tar.gz | tar -xz -C /tmp && sudo mv /tmp/gitleaks /usr/local/bin/ — or just let the GitHub Action run it (A.12.5) |
Coach’s Note (midterm, P8) — The Week-8 midterm is closed-internet.
ansible-galaxy,terraform init, and provider/collection downloads all need the network. So pre-install and pre-cache everything before the clock starts: install Ansible/Terraform/tflint, runansible-galaxy collection install community.general, and runterraform init -backend=falseonce in the project folder so thehashicorp/awsprovider is already on disk. Then the exam itself touches no network. If your instructor ships a pre-baked exam image, this is already done for you — but verify it before the clock.
Reaching a web UI on your lab box from your laptop (Grafana, Prometheus, Open WebUI, Kibana). Don’t open firewall ports — forward the port over your existing SSH connection, which needs no admin and exposes nothing publicly:
# from your laptop; now http://localhost:3000 in your browser hits the box's :3000
ssh -L 3000:localhost:3000 -L 9090:localhost:9090 -L 9200:localhost:9200 ubuntu@<your-box-ip>
(Heads-up: both Grafana and Open WebUI default to port 3000 — run one on a different port, e.g.
map Grafana to 3001, or you’ll get a collision.)
What you do not need (so you don’t over-build): a real GPU (the GPU chapters work on the
simulator/widget or a serverless API — rent one by the hour only to do it for real, A.9); Docker Desktop
(use Docker Engine on the box — free); Wireshark/tcpdump for P5 (it ships you the capture as CSV);
matplotlib for P5 (a table is fine); tfsec/checkov for P8 (a grep-based check is provided).
A.12 — Submitting Your Work: git, GitHub, and the Hand-In
Every project is submitted the same way: a link to a public GitHub repository. Here is the whole mechanic, end to end — including a path that needs no git and no admin at all, so a student on a locked-down Chromebook in a library can submit just as easily as anyone else.
A.12.1 — Get a GitHub account
Sign up free at github.com. That’s it — a free account can create unlimited public repositories and run CI
on them. You do not need to install anything on your laptop to have a place to submit.
A.12.2 — Two ways to get your work onto GitHub
Path 1 — git from your lab box (you’re root there; git is in the A.11 bootstrap). Set your identity once:
git config --global user.name "Your Name"
git config --global user.email "you@school.edu"
Authenticate your pushes — pick one:
- A Personal Access Token (simplest). On GitHub: Settings → Developer settings → Personal access tokens
→ Fine-grained tokens → create one scoped to your repo with Contents: read/write. Use it as your
password when git prompts, and cache it:
git config --global credential.helper store. - An SSH key for GitHub.
ssh-keygen -t ed25519 -C "github", then paste the public key (cat ~/.ssh/id_ed25519.pub) into GitHub → Settings → SSH and GPG keys. (This is a different key from the one you used to log in to your VM in A.2.1 — GitHub needs its own.)
Then create an empty public repo on github.com and push your project into it:
cd my-project
git init
printf ".venv/\n__pycache__/\n.env\n*.key\n" > .gitignore # keep secrets and junk out (see A.12.4)
git add .
git commit -m "Project N submission"
git branch -M main
git remote add origin https://github.com/<you>/<repo>.git
git push -u origin main
Path 2 — no git, no install (the most locked-down laptop). Create the repo on github.com, then “Add file → Upload files,” drag your deliverables in, and commit — all in the browser. Or open the repo in GitHub Codespaces (A.2.2) and work entirely in the browser. This is the perfect path for the document-heavy capstone (P14), and a fine fallback for any project.
A.12.3 — Branches and tags (only the few projects that need them)
git checkout -b regression-demo # P13: commit a deliberate regression on a branch, open a Pull Request
git tag midterm-p8 && git push --tags # P8: tag the commit you submit for the midterm
A.12.4 — A .gitignore you should always have
Never commit secrets, virtual environments, or caches. The four lines in A.12.2 cover the common cases; the
key one is .env — your API keys live there (Appendix B.5.1) and must never reach a public repo.
Confirm with git status that .env is not staged before your first push.
A.12.5 — GitHub Actions in two minutes (for P8 Medium and P13)
A file at .github/workflows/ci.yml in your repo makes GitHub run your pipeline automatically on every
push — free minutes for public repos. Watch runs in the repo’s Actions tab; a red run is the evidence
P13 asks for. Two things students miss:
- Secrets go in the repo, not in
.env. A model API key the CI eval gate needs goes in Settings → Secrets and variables → Actions (as a secret); a non-secret like a model id goes there as a variable. The workflow reads them as${{ secrets.NAME }}/${{ vars.NAME }}. - A GitHub runner can’t reach a model on your box. GitHub’s hosted runners are in the cloud — they cannot see Ollama on your laptop or lab box. For an eval gate that calls a model in CI, point it at a cloud API (Appendix B.5), not a local endpoint. (Local Ollama is fine for development; just not from a hosted runner.)
A.12.6 — The submission checklist (every project)
Before you submit the repo URL to the LMS, confirm the repo is Public and contains:
README.txt— the exact commands a grader runs to reproduce your result.- The project’s named deliverables (the files the project’s Submission section lists).
REPORT.docx— your write-up.- The AI artifact for the phase — and this is the one students get wrong, so fix it in your head now:
- Phase 1 (Weeks 1–8): an
AI_USAGE.txt(or an “AI usage” section inREPORT.docx) — what you used AI for, what you verified, what you rejected. Noagent-log.txtyet. - Phase 2 (Weeks 9–16): the
agent-log.txtfrom Appendix C — required and graded.
- Phase 1 (Weeks 1–8): an
Coach’s Note — Here is the whole truth about this course’s hardware requirement: you can complete and submit every project from a borrowed Chromebook in a library. A free GitHub account, a free cloud Linux box, and a browser is the entire kit. Everything else installs on a machine in the cloud where you’re root, and the hand-in happens over the web. If anyone tells you that you need to buy a powerful laptop to take a systems course in 2026, they have not read this appendix.
A.13 — The Steward’s Lab
“…does not first sit down and count the cost…” — Luke 14:28 (ESV)
A lab is an act of stewardship before it is an act of engineering. You are given finite resources — a machine you may not even own, a tiny budget, your own hours — and you are accountable for spending them well. The student who insists they need a $1,500 GPU laptop, or who leaves a rented H100 running overnight, has not committed a technical error so much as failed to count the cost: to size the work, match the tool to it, use the free thing when the free thing suffices, and tear down what’s done. Every “use a free tier,” every teardown checklist, every “rent it by the hour” in this appendix is, quietly, a discipline of faithfulness with what you’ve been entrusted.
That same posture is the spine of this whole book. AI will offer to provision your lab, write your setup scripts, and tear your instances down for you — faster than you can type. But the choice of which path fits your machine and your wallet, the budget alert that catches the runaway GPU, the verification that the spend actually stopped — those stay with you. The human stays in the loop where the judgment lives. A lab you can build on a borrowed laptop, verify, and account for to the dollar is the first proof that you’re ready to govern systems larger than yourself.
Build it well — and no bigger than you need. Then let’s get to work.
See you in Chapter 1.
Up next: Return to the course overview and begin Chapter 1. Getting models running locally and in the cloud (Ollama, vLLM, cloud API keys) is in Appendix B; the agentic-AI toolkit and classroom AI policy are in Appendix C.