Capstone Server+ — Complete Beginner's Walkthrough

Three phases. Bare-metal hardware to a running, segmented network with services. Every step explained in plain English. Every acronym spelled out the first time it's used.

For someone who has never built a server lab before

What you're building (and why)

Imagine you have one big metal computer (a "server") that you want to turn into five smaller fake computers inside it — each pretending to be its own machine, each doing a different job. They all share the same CPU, RAM, and disks, but they're isolated from each other. That's virtualization, and the software that does it is called a hypervisor.

Then you want those five fake computers to talk to each other through three different "rooms" with locked doors between them — so even if a stranger sneaks into one room, they can't reach the others. That's network segmentation, and we do it with virtual switches and a firewall.

Then on top of all that, we install real services: a website (web server), a database, a Windows domain controller, a Linux desktop client. So you can prove the whole thing works the way a real small company's network does.

Why this matters for your capstone

This is what every IT department in the world does at scale. Your future job will involve some version of these same skills: hypervisor administration, network design, firewall configuration, server roles, client testing. The hardware you're using is real enterprise gear. The software is real production software. You're not playing a simulation — you're building a tiny version of the real thing.

What you'll have when you're done

  • One physical server (HP ML350p Gen8) running Proxmox VE 8.2 — a free hypervisor
  • Three virtual networks: a "management" network, a "DMZ" network, and a "LAN"
  • Five virtual machines, each on the right network for its job
  • A firewall (pfSense) routing traffic between networks and out to the internet
  • A web server stack (LAMP and/or LEMP) serving pages
  • A Windows server with Active Directory for user authentication
  • A Linux desktop client to test everything from a "real user's" perspective

Total time, if you've never done it before: about 25–35 hours of focused work, spread over 3–4 weeks.

Network concepts in plain English

If you've never set up a network before, the next 5 paragraphs will be the most important reading of your capstone. Don't skip.

The neighborhood analogy. A network is like a neighborhood. Every house has an address (an IP address — Internet Protocol address). The mailman (the router) takes mail from any house to any other house using the addresses. The phone book (the DNS — Domain Name System) lets you look up "who lives at this name?" so you can use names instead of memorizing numbers. The security guard at the gate (the firewall) decides which mail trucks get in and out. And every house has a unique nameplate (the MAC address — Media Access Control address) that the mailman recognizes even if the address changes.

Five things you absolutely need to grasp

1. IP address

A number like 192.168.0.20. It's the "house address" of one device on the network. Two devices can't have the same IP at the same time, just like two houses can't have the same address.

2. Subnet

A group of houses on the same street. Written like 192.168.0.0/24, where the /24 means the first 24 bits identify the street and the last 8 bits identify the house number — so houses can range from 192.168.0.1 to 192.168.0.254 on this street. Devices on the same subnet can talk directly. Devices on different subnets need a router to forward their messages.

3. Gateway

The IP address of the router on your subnet. When your computer wants to send something to a device that's NOT on its street, it sends it to the gateway and says "you handle it." For our lab, when a Linux server at 192.168.0.20 wants to reach Google, it sends the packet to 192.168.0.1 (the gateway, which is the firewall pfSense) and pfSense forwards it out to the internet.

4. DNS — Domain Name System

The phone book of the internet. When you type www.google.com into your browser, your computer asks a DNS server "what's the IP for that name?" and the server replies with something like 142.251.157.119. Then your browser uses that IP to make the actual connection. In our lab, pfSense runs a DNS server (Unbound) that does this for all the VMs.

5. DHCP — Dynamic Host Configuration Protocol

A service that hands out IP addresses automatically. When a new device joins a network, it shouts "anyone got an IP for me?" and the DHCP server replies with "use 192.168.0.157, and your gateway is 192.168.0.1, and your DNS is 192.168.0.1." Without DHCP, you'd have to manually configure every device. In our lab, pfSense runs DHCP for both internal subnets.

Three more terms you'll see often

NAT — Network Address Translation

The trick that lets many internal devices share one external IP. Your home router uses it: all your phones and laptops have private addresses like 192.168.x.x, but to the internet they all look like one address (your ISP-assigned public IP). The router rewrites the source address as packets leave and rewrites the destination as replies come back. pfSense does NAT for our lab.

DMZ — Demilitarized Zone

A network "buffer area" — an isolated subnet for things that need to face the outside world but shouldn't have direct access to your internal stuff. In our lab the jumpbox lives in the DMZ. If a hacker breaks into the jumpbox, the firewall still stops them from reaching the LAN.

VLAN, vSwitch, Bridge

Different names for the same idea: a virtual network "switch" inside a hypervisor that connects virtual machines together. In Proxmox they're called bridges (with names like vmbr0, vmbr1, vmbr2). Each bridge is a separate isolated network unless a router (like pfSense) connects them.

Glossary — every acronym you'll see

Bookmark this section. Whenever a step uses an acronym, it's defined here.

AD — Active Directory
Microsoft's central database for user accounts, computer accounts, and security policies on a Windows network.
AD-DS — Active Directory Domain Services
The Windows Server role that turns a server into a "domain controller" — the boss of a Windows network.
Apache
A web server program (originally "A Patchy server"). Listens for browser requests on a port and sends back web pages.
ARP — Address Resolution Protocol
How a device on a network finds the MAC address that goes with an IP address. The "first step" in any local network conversation.
BIOS — Basic Input/Output System
The firmware that runs when a computer first turns on, before any operating system loads. Configures hardware and tells it what to boot from.
CIDR — Classless Inter-Domain Routing
The notation like /24 after an IP. Tells you how big the subnet is. /24 = 256 addresses, /16 = 65,536, /8 = 16 million.
CLI — Command Line Interface
Typing commands into a black-and-white text terminal, as opposed to clicking buttons in a window.
CPU — Central Processing Unit
The "brain chip" of a computer. Modern CPUs have multiple "cores," each able to do work in parallel.
DHCP — Dynamic Host Configuration Protocol
Automatically hands IP addresses to devices joining a network. Your home Wi-Fi router does this for you constantly.
DMZ — Demilitarized Zone
An isolated network "buffer" for things that face the outside world. Compromising a DMZ host doesn't immediately compromise your LAN.
DNS — Domain Name System
The phonebook of the internet — translates names like google.com into IP addresses.
DNSSEC — DNS Security Extensions
A way to digitally sign DNS responses so attackers can't lie about what IP a name points to. pfSense's resolver uses it.
FQDN — Fully Qualified Domain Name
The full hostname including all parts. winsrv.capstone.local is an FQDN; just winsrv is a hostname.
FTP — File Transfer Protocol
An old protocol for moving files between computers. Mostly replaced by SSH-based methods now (SFTP, SCP).
GUI — Graphical User Interface
The point-and-click world. Buttons, menus, mouse cursors. Opposite of the CLI.
HDD — Hard Disk Drive
Mechanical spinning-platter storage. Slower than SSD but cheaper per gigabyte.
HTTP — HyperText Transfer Protocol
How web browsers and web servers talk. The plain (unencrypted) version. Default port 80.
HTTPS — HTTP Secure
HTTP with TLS encryption layered underneath. Default port 443. The padlock icon in your browser.
ICMP — Internet Control Message Protocol
The protocol used by ping. Sends a small "are you there?" packet and waits for a "yes" reply.
IDS / IPS
Intrusion Detection / Prevention System. Software that watches network traffic for bad behavior and alerts (IDS) or blocks (IPS) it.
IIS — Internet Information Services
Microsoft's web server, built into Windows Server. The Windows equivalent of Apache or NGINX.
iLO — integrated Lights-Out
HP's out-of-band server management — a tiny computer inside the server that lets you manage it even when the main OS is off. Equivalents on Dell are iDRAC, on Cisco are CIMC.
IP — Internet Protocol
The fundamental addressing scheme of the internet. IPv4 = 32-bit (e.g. 192.168.0.1), IPv6 = 128-bit (e.g. fe80::1).
iptables
The classic Linux firewall command. Defines what packets to allow, drop, or modify.
ISO — Disk image file
A single file that contains the entire contents of a CD or DVD. Operating-system installers come as ISOs that you "mount" as a virtual disc.
KVM — Kernel-based Virtual Machine
Linux's built-in hypervisor. Proxmox uses KVM (plus QEMU) under the hood.
LAMP
A web stack: Linux + Apache + MariaDB/MySQL + PHP. Old, ubiquitous, well-documented.
LAN — Local Area Network
Your local network — the computers in one office or one floor that can reach each other directly.
LDAP — Lightweight Directory Access Protocol
The protocol Active Directory uses to store and look up users, groups, and computers.
LEMP
A web stack: Linux + Engine-X (NGINX) + MariaDB + PHP. Modern, faster than LAMP at high concurrency.
LTS — Long Term Support
A version of Ubuntu (or other software) that gets security updates for 5+ years. Use LTS in production. Ubuntu LTS releases are years ending in even numbers (24.04, 26.04).
LVM — Logical Volume Manager
A Linux feature that lets you group physical disks into one big "pool" and slice virtual partitions out of it. Easy to resize later.
MAC — Media Access Control (address)
The factory-burned hardware ID of a network card. 12 hex digits, like BC:24:11:02:24:2B. Unique per NIC.
MariaDB / MySQL
Two compatible open-source database engines. MariaDB is a community fork of MySQL. Both speak the same SQL.
NAT — Network Address Translation
The trick where many private addresses share one public address by rewriting packet source/destination on the fly.
NGINX (engine-x)
A modern web server, often used as a reverse proxy in front of slower apps. Reads and writes a lot of connections per megabyte of RAM.
NIC — Network Interface Card
The hardware (or virtual hardware) that lets a computer connect to a network. Each NIC has a MAC address.
noVNC
A web-based viewer for VM consoles. Proxmox's "Console" tab uses noVNC. Doesn't accept paste from the host machine — that's why we SSH in for paste-friendly work.
NTP — Network Time Protocol
How computers keep their clocks accurate by syncing to time servers on the internet. Critical for security (Kerberos, certificates, logs all need correct time).
OS — Operating System
The software that manages a computer's hardware and provides services to applications. Windows, Linux, macOS are all OSes.
PHP — PHP: Hypertext Preprocessor
A programming language for the web, runs on the server side. Powers WordPress, Wikipedia, Facebook (originally).
PHP-FPM — PHP FastCGI Process Manager
A way to run PHP as a separate process pool that NGINX talks to over a Unix socket. Better isolation than embedding PHP in the web server.
Proxmox VE — Proxmox Virtual Environment
A free, open-source hypervisor based on Debian Linux + KVM + LXC. Has a web GUI for managing VMs.
QEMU — Quick EMUlator
The software that emulates virtual hardware (CPU, NICs, disks) for KVM virtual machines.
RAID — Redundant Array of Independent Disks
Combining multiple physical disks for speed (RAID 0), redundancy (RAID 1), or both (RAID 5/6/10). RAID 5 = your "one drive can fail without losing data" choice.
RAM — Random Access Memory
Volatile working memory. Way faster than disk. Loses everything when power cuts. Measured in gigabytes (GB).
RDP — Remote Desktop Protocol
Microsoft's protocol for controlling a Windows computer's GUI from another machine. Default port 3389.
RFC1918
The standards document that reserves three IP ranges for private use: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. Routers won't forward these to the public internet.
SMB — Server Message Block
Microsoft's file-sharing and printer-sharing protocol. Default port 445. Also known as CIFS.
SSD — Solid State Drive
Flash-memory storage. Much faster than HDD, more expensive per gigabyte, no moving parts.
SSH — Secure Shell
Encrypted command-line access to a remote computer. Default port 22. Universal in Linux/Unix admin.
subiquity
Ubuntu Server's text-mode installer. The "blue and white" screens you see during install.
TCP — Transmission Control Protocol
The reliable, ordered transport protocol on top of IP. Web (HTTP/HTTPS), email (SMTP), SSH all use TCP.
TLS / SSL — Transport Layer Security / Secure Sockets Layer
The encryption that turns HTTP into HTTPS. SSL is the old name; TLS is the modern one. Most people still say "SSL certificate."
UDP — User Datagram Protocol
The fast, unreliable cousin of TCP. Used for DNS, video calls, gaming — places where dropping a packet is OK.
UEFI — Unified Extensible Firmware Interface
The modern replacement for BIOS. More features, supports bigger disks, has a graphical pre-boot environment on many systems.
UFW — Uncomplicated Firewall
A user-friendly front-end to iptables on Ubuntu. Lets you write ufw allow 22 instead of long iptables incantations.
URL — Uniform Resource Locator
A web address. https://example.com/about.
vCPU — Virtual CPU
A "fake CPU core" assigned to a VM. Multiple vCPUs share the host's real CPU cores. You can over-allocate (more total vCPUs than real cores).
VM — Virtual Machine
A software-emulated computer that runs inside a host. Has its own OS, IP, MAC, but actually shares the host's hardware.
VNC — Virtual Network Computing
A protocol for viewing a remote computer's screen and clicking on it. noVNC is a browser-based VNC viewer.
VPN — Virtual Private Network
An encrypted tunnel that lets you appear to be on a different network. Used for remote work, privacy, and reaching internal resources from outside.
WAN — Wide Area Network
A network that covers a large area — the internet itself, or a corporate network spanning multiple buildings.
WinRM — Windows Remote Management
Microsoft's remote shell protocol. PowerShell uses it. Default ports 5985 (HTTP) and 5986 (HTTPS).
1

Phase 1 — Hardware + Hypervisor

Bare-metal server → bootable Proxmox install → web GUI you can log into

~6–8 hours Touch the physical server No virtual machines yet

Stage 1.1 — Inventory the hardware

What we're doing

Open the server, photograph every component, and record specs (CPU, RAM, disks, NICs, PSUs). Without this you can't ask the instructor smart questions or order replacement parts.

Why it matters: the lab guide is generic — your specific server might have different RAM modules, different drives, even a different CPU. Knowing what you actually have prevents 90% of "why doesn't X work?" questions later.

How to do it

  1. Power off the server. Unplug both power cords.
  2. Press the latches on the top cover, slide it off.
  3. Photograph: motherboard label, RAM stickers, drive labels, PSU labels, expansion cards.
  4. Record in your asset spreadsheet: model number, serial number, firmware version where visible.
What success looks like: a labeled set of photos and a filled-out asset row with every spec readable. You should be able to answer "how much RAM total?" and "how many disks?" without going back to look.
Common issues:
  • Cover won't slide off — there's usually a latch on top with a thumb-press. Don't force it.
  • Can't read a label — use a flashlight at an angle. Reflection-off-the-sticker is real.
  • Numbers look wrong — double-check the part number against the manufacturer's site. HMT41GR7BFR4A-PB on a SK Hynix RAM module is real.

Stage 1.2 — Power on + enter BIOS

What we're doing

Boot the server into its BIOS / UEFI firmware (the menus that appear before any operating system loads) and configure it for the install we're about to do.

Why it matters: the BIOS controls boot order, RAID, virtualization extensions (CPU features that hypervisors need), and out-of-band management. If virtualization extensions are off, Proxmox installs but VMs run 10× slower.

How to do it

  1. Plug the server back in. Connect a monitor and keyboard directly to the server's video and USB ports.
  2. Press the power button. Watch the boot screen.
  3. When prompted "Press F9 for Setup, F11 for Boot Menu, F10 for Intelligent Provisioning" — press F9.
  4. The BIOS / System Utilities loads (HP calls it "RBSU"). Use arrow keys to navigate.
  5. Verify these settings:
    • System Options → Processor Options → Intel Virtualization Technology = Enabled
    • System Options → Processor Options → Intel VT-d = Enabled (this is for direct device passthrough, helpful for advanced labs)
    • Boot Options → Boot Mode = Legacy BIOS (Proxmox prefers this on Gen8 hardware)
    • Boot Options → Boot Order = USB before HDD (so we can boot from the install USB)
  6. Save and exit.
What success looks like: server reboots, you see the HP splash screen, then the boot order shows USB first, then internal drives.
Common issues:
  • No video output — check the monitor cable. ML350p Gen8 has VGA, not HDMI. You may need a VGA-to-HDMI adapter.
  • F9 doesn't open BIOS — there's a tiny window during POST (Power-On Self Test). Press F9 repeatedly while the HP logo is still on screen.
  • Settings reset after reboot — the CMOS battery on the motherboard might be dead. Common on a 12-year-old server. Replace with a CR2032.

Stage 1.3 — Build the RAID array

What we're doing

Combine the server's three physical hard disks into one big logical drive using RAID 5 — Redundant Array of Independent Disks, level 5. With three 1 TB drives in RAID 5, you get ~2 TB of usable space and can survive any one drive failing.

The analogy: RAID 5 is like keeping your most important documents in three filing cabinets, where any two cabinets together can rebuild the third. Lose one cabinet, you can recover. Lose two, you've lost the data.

How to do it (HP Smart Array P420i)

  1. Reboot. When you see "Press F8 to enter ORCA" (Option ROM Configuration for Arrays), press F8.
  2. The ORCA menu opens. Select Create Logical Drive.
  3. RAID Level: RAID 5
  4. Available drives: select all three of your physical disks (use spacebar to mark them, they'll show "X")
  5. Spare drive: None
  6. Stripe size: leave default
  7. Maximum Boot Partition: Disable (4 GB)
  8. Save and exit.
  9. Wait 1–2 minutes while the array initializes.
What success looks like: ORCA's main menu now shows "View Logical Drive" as an active option, and selecting it shows your new drive at ~2 TB usable.
Common issues:
  • "No drives detected" — drives might not be seated. Power off, reseat each drive (push firmly until you hear/feel the latch click).
  • POST message "1785 — Drive Array Not Configured" after reboot — that's normal until you create the array. Once you've built it, this message goes away.
  • Drives show different sizes — RAID 5 uses the smallest drive's size for all of them. If you have two 1 TB and one 500 GB, you get only ~1 TB usable. Replace the small drive.

Stage 1.4 — Install Proxmox VE

What we're doing

Boot from a USB stick that has the Proxmox installer, walk through the screens, and install Proxmox VE 8.2 onto the RAID array.

Why Proxmox: it's free, open-source, has a clean web GUI, and is what most home-lab and small-business hypervisor environments use. It includes both VM (KVM/QEMU) and container (LXC) virtualization.

Preparation (do this on your laptop first)

  1. Download the Proxmox VE 8.2 ISO from https://www.proxmox.com/en/downloads.
  2. Get a USB stick that's at least 4 GB (it'll be erased — don't use one with anything important).
  3. Use Rufus (Windows) or Balena Etcher (Mac/Linux) to write the ISO to the USB:
    • Mode: DD mode (image mode), not ISO mode
    • File system: FAT32, partition scheme: MBR

Install on the server

  1. Plug the USB into a server USB port (front or back, doesn't matter).
  2. Reboot. Press F11 for the boot menu.
  3. Pick the USB stick.
  4. The Proxmox installer's purple boot menu appears. Pick Install Proxmox VE (Graphical).
  5. Accept the license.
  6. Target disk: pick your RAID 5 array (will show as /dev/sda or similar at ~2 TB). File system: ext4.
  7. Country / time zone / keyboard: pick your real location.
  8. Set the root password (write it down — you cannot recover it without re-installing) and an admin email.
  9. Network configuration:
    • Management interface: pick the NIC plugged into your school network
    • Hostname: tctmachine.local (or whatever your team chose)
    • IP / CIDR: 10.10.10.10/16 (your school-LAN-assigned address)
    • Gateway: 10.10.10.1 (your school's router)
    • DNS: 1.1.1.1 (Cloudflare's public DNS — works anywhere)
  10. Confirm and install. Takes 5–10 minutes.
  11. When done, eject the USB. Reboot.
What success looks like: after reboot, the server's monitor shows a console with https://10.10.10.10:8006 as the URL to manage it from. From your laptop browser, that URL opens the Proxmox login page.
Common issues:
  • USB doesn't appear in boot menu — back to BIOS, make sure USB is in the boot order. Some BIOSes require enabling "Legacy USB Support."
  • Installer freezes at "configuring storage" — could be a bad drive in the RAID array. Run the HP Smart Array Diagnostics from F10 → Intelligent Provisioning.
  • Browser says "can't establish a secure connection" — Proxmox uses a self-signed TLS certificate. Click "Advanced" → "Proceed anyway." This is fine for a lab.
  • Wrong network config — log in via the physical console (root + password), then run nano /etc/network/interfaces to fix the IP, gateway, DNS.

Stage 1.5 — Log into the web GUI + first sanity check

What we're doing

Open the Proxmox web interface from your laptop, log in, and confirm everything looks normal.

How to do it

  1. From a laptop on the same school network, open Safari or Chrome.
  2. Go to https://10.10.10.10:8006 (replace with your IP if different).
  3. Click through the certificate warning.
  4. Log in: User root, Password = whatever you set, Realm PAM.
  5. Dismiss the "no subscription" popup (that's fine — community edition).
  6. In the left tree click your node name (e.g. tctmachine).
  7. Look at the right panel: Summary tab.
What you should see: a green checkmark on the node icon, RAM / CPU / disk graphs, kernel version, uptime starting at zero. The Summary panel says Online.
Common issues:
  • Connection refused — Proxmox isn't running, or the network config is wrong. SSH to root@10.10.10.10 from a Linux/Mac terminal and run systemctl status pveproxy pvedaemon.
  • Login fails — Realm must be PAM (the Linux user database), not "Proxmox VE auth server." If you forgot the password, you'll need to boot into single-user mode from the server's physical console and reset it.
  • Page loads but everything is blank — browser cache. Hard reload (Cmd+Shift+R).

Phase 1 done — checkpoint

Before moving on, you should have:

Now you have a hypervisor. Empty, but ready. Phase 2 fills it with virtual machines.

2

Phase 2 — Networking + Virtual Machines

Three subnets · five VMs · one firewall doing all the routing

~10–14 hours Lots of installer screens Most "wait, what?" moments live here

Stage 2.1 — Plan the network

What we're doing

Before clicking anything, write down what addresses you'll use. This 10-minute step prevents 10 hours of pain.

The lock-in plan

ZoneSubnetPurposeGateway
School LAN (vmbr0)10.10.0.0/16Where Proxmox lives + WAN side of pfSenseSchool router (e.g. 10.10.10.1)
DMZ (vmbr1)172.16.0.0/24Jumpbox lives here · public-facing tier172.16.0.1 (pfSense)
LAN (vmbr2)192.168.0.0/24WinSrv + LinuxServer + Linux Desktop · internal tier192.168.0.1 (pfSense)

VM IP plan

VMIPBridge
Proxmox host10.10.10.10vmbr0 (physical NIC)
pfSense (firewall)WAN 10.10.110.10 · DMZ 172.16.0.1 · LAN 192.168.0.1vmbr0 + vmbr1 + vmbr2
Jumpbox172.16.0.100 via DHCPvmbr1
Windows Server (WinSrv)192.168.0.15 staticvmbr2
Linux Server (LinuxServer)192.168.0.20 staticvmbr2
Linux Desktop (Linux-Ubuntu)192.168.0.25 staticvmbr2

Static IPs are below the DHCP pool (which is .100–.200) — so no lease ever conflicts.

Stage 2.2 — Create the virtual bridges

What we're doing

Inside the Proxmox host, create two new virtual switches (called "bridges"): one for the DMZ, one for the LAN. vmbr0 already exists from the Proxmox install.

How to do it

  1. Proxmox UI → click your node (tctmachine) → top tab >_ Shell. A web terminal opens.
  2. Edit the network configuration file:
nano /etc/network/interfaces

Add these two blocks at the bottom (don't touch vmbr0):

auto vmbr1
iface vmbr1 inet static
    address 172.16.0.10
    netmask 255.255.255.0
    bridge_ports none
    bridge_stp off
    bridge_fd 0

auto vmbr2
iface vmbr2 inet static
    address 192.168.0.10
    netmask 255.255.255.0
    bridge_ports none
    bridge_stp off
    bridge_fd 0

Save (Ctrl+O Enter) and exit (Ctrl+X). Reload networking:

ifreload -a
ip -br addr
What success looks like: ip -br addr shows three lines for vmbr0, vmbr1, vmbr2 — all in state UP with the correct IPs.
Common issues:
  • "ifreload: command not found" — older Proxmox needs systemctl restart networking. Pause critical workloads first; this can briefly drop your SSH session.
  • vmbr1 / vmbr2 don't shownano may have introduced typos. Run cat /etc/network/interfaces and check spelling. bridge_ports not bridgeports.
  • You lose access to Proxmox web GUI — you accidentally edited vmbr0. Use the physical console: log in as root, fix the file, restart networking.

Stage 2.3 — Upload installer ISOs

What we're doing

Get the operating-system installer disks (ISO files) onto Proxmox so VMs can boot from them. ISOs needed:

  • pfSense Community Edition installer (e.g. netgate-installer-v1.1.1-RELEASE-amd64.iso)
  • Ubuntu Server LTS (e.g. ubuntu-24.04-live-server-amd64.iso or 26.04) — used for jumpbox + LinuxServer
  • Ubuntu Desktop LTS (e.g. ubuntu-24.04.4-desktop-amd64.iso) — used for Linux-Ubuntu client
  • Windows Server 2025 Evaluation (download from Microsoft Evaluation Center)

How to do it

  1. Proxmox UI → in the tree click local (your-node-name) → tab ISO Images → button Upload.
  2. Pick the ISO file from your laptop. Wait for it to upload (multi-GB files take 5–15 minutes).
  3. Repeat for each ISO.
What success looks like: all four ISOs listed under local → ISO Images, with sizes that look right (Windows ~7 GB, Ubuntu Desktop ~6 GB, Ubuntu Server ~2.7 GB, pfSense ~1 GB).

Stage 2.4 — Install pfSense (the firewall)

What we're doing

Build the most important VM: the firewall/router that will route traffic between all our subnets and out to the internet.

Why pfSense: it's free, runs on FreeBSD, and is genuinely production-grade. It does routing, NAT, DHCP, DNS, firewall, VPN, IDS/IPS — all in one box.

Create the VM

  1. Proxmox UI top right → Create VM.
  2. General: VM ID 103, Name PFsense2.
  3. OS: ISO image = the pfSense installer. OS type = "Other".
  4. System: defaults are fine. BIOS = SeaBIOS, Machine = Default (i440fx).
  5. Disks: 20 GB on local-lvm.
  6. CPU: 2 cores, type "x86-64-v2-AES".
  7. Memory: 2048 MB.
  8. Network: NIC #1 on vmbr0, model VirtIO (paravirtualized).
  9. Confirm and create.
  10. Add two more NICs after creation: click VM 103 → Hardware → Add → Network Device → bridge vmbr1, model VirtIO. Repeat for vmbr2.

Install pfSense

  1. Click VM 103 → Console. Hit Start (▶).
  2. Boot into the pfSense installer. Accept defaults all the way through (Auto ZFS install).
  3. When it says "Installation complete, reboot," eject the ISO (Hardware → CD/DVD Drive → "Do not use any media") then reboot.
  4. The pfSense main menu appears. Select option 2 — Set interface(s) IP address.
  5. Assign:
    • WAN (vtnet0) → DHCP from school LAN (it'll get something like 10.10.110.10)
    • DMZ (vtnet1) → static 172.16.0.1/24
    • LAN (vtnet2) → static 192.168.0.1/24
What success looks like: the pfSense main menu now shows three interfaces with IPs at the top. From your laptop, you can browse to https://10.10.110.10 (the WAN IP) and see the pfSense login page (default admin / pfsense).
🚨 Change the default password immediately. Log into the web GUI → System → User Manager → admin → click pencil → set strong password → Save. Anyone on the school LAN can log in with pfsense until you do this.
Common issues:
  • VM keeps rebooting into installer — you forgot to eject the ISO. Hardware → CD/DVD Drive → change to "Do not use any media."
  • Interface assignment is wrong — it's tedious because pfSense names them vtnet0/1/2 not by what you called them. Match by MAC address: in Proxmox VM 103 → Hardware, note each net's MAC, then in pfSense console option 1 it'll show the same MACs.
  • WAN didn't get a DHCP IP — your school network might filter unrecognized MACs. Talk to the instructor.

Stage 2.5 — Install the Jumpbox (Linux SSH gateway)

What we're doing

A small Ubuntu Server VM in the DMZ that you SSH into first, then SSH from there into the LAN servers. It's the "secure entry point."

The analogy: a hotel lobby. You don't let guests wander straight into the rooms — they check in at the lobby first. The jumpbox is the lobby.

Create + install

  1. Create VM: ID 101, Name jumpbox, OS = Ubuntu Server ISO, OS type Linux 6.x.
  2. Disk 25 GB, CPU 2 cores, RAM 2048 MB, NIC on vmbr1.
  3. Boot into the installer.
  4. subiquity walkthrough: language English, keyboard US, install Ubuntu Server.
  5. Network: leave at DHCP (it'll get 172.16.0.x from pfSense).
  6. Storage: use entire disk, LVM default ON.
  7. Profile: server name jumpbox, username tct_jumpbox (or whatever your team picks), strong password.
  8. SSH: ✓ Install OpenSSH server.
  9. Skip snaps. Install. Reboot.
  10. Detach the ISO before reboot (Hardware → CD/DVD → "Do not use any media").

Configure the firewall (UFW) inside the VM

  1. Log in at the console.
  2. Run:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 10.10.10.0/24 to any port 22
sudo ufw allow from 172.16.0.0/24 to any port 22
sudo ufw allow from 192.168.0.0/24 to any port 22
sudo ufw enable
sudo ufw status verbose
What success looks like: from the Proxmox host shell, you can ssh tct_jumpbox@172.16.0.X (whatever IP DHCP gave it) and reach a prompt.
Common issues:
  • SSH connection refused — sshd isn't running. Console in, run sudo systemctl status ssh; enable with sudo systemctl enable --now ssh.
  • Connection times out — UFW is blocking your source IP. Run sudo ufw status to see the rules.
  • Don't know the IP — in the jumpbox console, run ip -br addr.

Stage 2.6 — Install Windows Server (WinSrv)

What we're doing

Install Windows Server 2025 (Datacenter Evaluation edition) on a VM that will eventually become a Domain Controller, DNS server, and IIS web server.

Create + install

  1. Create VM: ID 102, Name WinSrv, OS = Windows Server ISO, OS type Windows 11/2025.
  2. System: BIOS = OVMF (UEFI). Machine = q35. Add EFI Disk.
  3. Disk 32 GB. CPU 2 cores. RAM 4096 MB.
  4. NIC: model e1000 (Windows has built-in drivers for this; VirtIO needs extra drivers). Bridge vmbr2. Enable Proxmox firewall.
  5. Boot installer. Pick Datacenter Evaluation (Desktop Experience).
  6. Custom partition → use the full disk → install. Takes ~10 minutes.
  7. Set Administrator password. Sign in. Server Manager opens.
  8. Eject ISO before reboot.

Set static IP

Win+R → type ncpa.cpl → right-click Ethernet → Properties → double-click Internet Protocol Version 4 (TCP/IPv4) → set:

  • IP: 192.168.0.15
  • Mask: 255.255.255.0
  • Gateway: 192.168.0.1
  • DNS: 192.168.0.1
What success looks like: Command Prompt → ipconfig /all → IPv4 Address shows 192.168.0.15(Preferred), DHCP Enabled: No.
Common issues:
  • Windows installer freezes — usually graphics-driver related. Try setting Display = SPICE or VirtIO-GPU in Hardware.
  • "No drivers" error during partitioning — you set Disk to VirtIO without loading the driver. Either change to SCSI/SATA, or attach the VirtIO ISO and load drivers during install.
  • APIPA address (169.254.x.x) after IP change — netsh or the GUI couldn't apply the static. Re-do via GUI carefully; restart the network adapter (Disable then Enable).

Stage 2.7 — Install Linux Server (services host)

What we're doing

Another Ubuntu Server VM, this time on the LAN. It'll host web servers (NGINX or Apache) and the database (MariaDB).

Create + install

  1. VM ID 105, Name LinuxServer, OS = Ubuntu Server ISO.
  2. Disk 32 GB, CPU 2 cores, RAM 2048 MB, NIC on vmbr2.
  3. subiquity install. At the Network screen, click ens18 → Edit IPv4 → Manual:
    • Subnet: 192.168.0.0/24
    • Address: 192.168.0.20
    • Gateway: 192.168.0.1
    • Name servers: 192.168.0.1
  4. Profile: server name linuxserver, admin user, strong password.
  5. ✓ Install OpenSSH server.
  6. Wait. Detach ISO. Reboot.

After first boot

sudo systemctl enable ssh
ip -br addr
ping -c 2 192.168.0.1
sudo apt update && sudo apt upgrade -y
What success looks like: hostname is linuxserver, IP is 192.168.0.20/24, ping to 192.168.0.1 succeeds, apt update reaches Ubuntu's mirrors (proves NAT through pfSense works).

Stage 2.8 — Install Linux Desktop (client tester)

What we're doing

A Ubuntu Desktop VM with Firefox — used to test web services from a "real user" perspective.

If Ubuntu Desktop ISO freezes during install: common on resource-limited hosts. Switch to Ubuntu Server + xubuntu-core^ on top:
  1. Install Ubuntu Server normally (same procedure as VM 105 above).
  2. Boot, log in.
  3. Run: sudo apt install -y xubuntu-core^ firefox lightdm
  4. Run: sudo systemctl set-default graphical.target
  5. Reboot — you boot to a graphical login.
Lighter, faster, almost never freezes.

Create + install

  1. VM ID 104, Name Linux-Ubuntu, OS = Ubuntu Desktop ISO (or Server ISO if going with the Xubuntu-core approach).
  2. Disk 32 GB, CPU 2 cores, RAM 4096 MB (Desktop wants more), Display = SPICE, Machine = q35.
  3. NIC on vmbr2, model VirtIO.
  4. Walk through installer. Set static IP 192.168.0.25 via GNOME Settings → Network → Wired → ⚙ → IPv4 = Manual after install (or in subiquity if going with Server).
What success looks like: from the desktop, open Firefox, browse to http://192.168.0.20 — should reach LinuxServer (default NGINX or Apache page once installed in Phase 3).

Phase 2 done — checkpoint

Five VMs running, basic network alive. Now we add services.

3

Phase 3 — Services + Verification

Web stacks · Active Directory · DNS · firewall hardening · end-to-end testing

~9–13 hours Most of the "make it actually do something" work Lab-report screenshot territory

Stage 3.1 — pfSense DHCP + DNS Resolver

What we're doing

Make pfSense automatically hand out IP addresses to anything that asks (DHCP) and let internal VMs look up names via pfSense's DNS resolver (Unbound).

How to do it

  1. Log into pfSense web GUI (https://10.10.110.10 or via SSH tunnel).
  2. Services → DHCP Server → DMZ tab:
    • ✓ Enable DHCP server on DMZ interface
    • Range: 172.16.0.100172.16.0.200
    • DNS Server: 172.16.0.1
    • Save → Apply
  3. Services → DHCP Server → LAN tab:
    • ✓ Enable DHCP server on LAN interface
    • Range: 192.168.0.100192.168.0.200
    • DNS Server: 192.168.0.1
    • Save → Apply
  4. Services → DNS Resolver → General Settings:
    • ✓ Enable DNS resolver
    • Network Interfaces: select DMZ + LAN (Ctrl+click)
    • Outgoing Network Interfaces: WAN
    • ✓ Enable DNSSEC Support
    • Save → Apply
  5. Firewall → NAT → Outbound: ensure Mode = Automatic outbound NAT rule generation. Save.
What success looks like: from the jumpbox, cat /etc/resolv.conf shows 172.16.0.1 as nameserver. From the LinuxServer, nslookup google.com returns an IP. From any VM, curl https://www.google.com reaches Google.

Stage 3.2 — Hardened LAN firewall

What we're doing

Apply a 9-rule firewall ruleset on pfSense's LAN interface that follows defense-in-depth: only allow what's needed, deny everything else.

Why these specific rules: a typical "allow LAN to anywhere" rule is the lazy default. Production networks use rules like these to limit blast radius if a server gets compromised. Building it this way is a Week 3 lab-deliverable showpiece.

Required aliases first (Firewall → Aliases)

  • OUTBOUND_WEB (Ports): 80, 443, 53, 123
  • RFC1918 (Networks): 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • DMZ_NET (Networks): 172.16.0.0/24
  • LAN_NET (Networks): 192.168.0.0/24

The 9 rules — Firewall → Rules → LAN tab — ADD IN ORDER

#ActionSourceDestinationDescription
1PASSLAN_NETThis Firewall · ICMP echoreqPing outbound (gateway only)
2PASSLAN_NETThis Firewall · UDP/123NTP to PFsense
3PASSLAN_NETThis Firewall · UDP/53DNS to PFsense
4BLOCKLAN_NETThis Firewall · anyBlock servers → pfSense management
5BLOCKLAN_NETDMZ_NET · anyBlock servers → DMZ (no return-init)
6BLOCKLAN_NETRFC1918 · anyBlock other private-range access
7PASSLAN_NETOUTBOUND_WEB · TCP/UDPOutbound web/DNS/NTP only
8PASSLAN_NET5985–5986 · TCPWindows Update/WinRM
9PASSLAN_NET445 · TCPSMB

Apply changes after adding all rules.

What success looks like: From LinuxServer, ping 1.1.1.1 fails (correct — only ICMP to gateway is allowed) but curl https://www.google.com succeeds (correct — port 443 in OUTBOUND_WEB). From WinSrv, Windows Update can fetch updates over HTTPS.

Stage 3.3 — Install LAMP and/or LEMP on LinuxServer

What we're doing

Install a web stack so we have something for clients to hit. LAMP = Linux + Apache + MariaDB + PHP. LEMP = same but NGINX instead of Apache.

Detailed step-by-step (with click-to-copy commands) lives at LAMP + LEMP setup walkthrough →. That page covers both stacks side-by-side.

Quick highlights

  1. SSH from Proxmox host shell into LinuxServer: ssh user@192.168.0.20
  2. Install MariaDB → run mysql_secure_installation → create capstone_db
  3. Install NGINX (port 80) + PHP-FPM
  4. (Optionally) install Apache on port 8080 with mod_php for both stacks side-by-side
  5. Build test pages with PHP info + database connection test
  6. Configure UFW: allow 22, 80, 443, 8080

Stage 3.4 — Install Active Directory on WinSrv

What we're doing

Promote WinSrv to a Domain Controller. After this, WinSrv is the boss of a Windows network — managing user logins, computer accounts, security policies, DNS for the internal domain.

Prereqs (do these first)

  • Set time zone to your real time zone (Settings → Time & language)
  • Run all pending Windows Updates
  • WinSrv must be on a static IP (already done in Phase 2)
  • Pick a domain name. Suggested: capstone.local

Phase A — Install the role (3 minutes)

  1. Server Manager → Manage → Add Roles and Features
  2. Role-based / feature-based → Next
  3. Server Selection → next
  4. Server Roles → ✓ Active Directory Domain Services → Add Features popup → Add Features → Next
  5. Features → Next · AD-DS info → Next
  6. Install. Takes ~3 min. Don't reboot — it doesn't need to.

Phase B — Promote to Domain Controller (10 minutes)

  1. Top-right of Server Manager → click the yellow flag icon → "Promote this server to a domain controller"
  2. Deployment Configuration: Add a new forest · Root domain name: capstone.local · Next
  3. Domain Controller Options: leave defaults · DSRM password: pick + write down (separate from Administrator password)
  4. DNS Options: ignore the warning about delegation · Next
  5. Additional Options: NetBIOS name CAPSTONE auto-fills · Next
  6. Paths: defaults · Next
  7. Review · Next
  8. Prerequisites Check (yellow warnings ok, red errors not) → Install
  9. Server reboots itself when done.
What success looks like: after reboot, login screen now says "Sign in to: CAPSTONE." ipconfig /all shows Primary DNS Suffix = capstone.local, DNS Servers = ::1 + 127.0.0.1. Server Manager left sidebar now has AD-DS and DNS entries.
Common issues:
  • Prereqs Check shows red errors — usually IP-isn't-static or hostname-still-default. Fix first, then retry.
  • "DNS server cannot be created" warning — that's the parent-zone-delegation warning. Ignore; not relevant for an internal-only domain.
  • Time/Kerberos errors after reboot — clocks must be accurate within 5 minutes for Kerberos. Check your time zone is correct.

Stage 3.5 — End-to-end verification

What we're doing

Test that everything works together from a real client's perspective.

From the Linux Desktop (Firefox)

URLExpected
http://192.168.0.20/NGINX welcome page
http://192.168.0.20:8080/Apache welcome page (if both stacks installed)
http://192.168.0.20/dbtest.phpDatabase connection success message
https://www.google.com/Loads normally (proves NAT through pfSense)

From the WinSrv (Command Prompt)

nslookup linuxserver.capstone.local
nslookup google.com
ping 192.168.0.20
ping 172.16.0.100

From the Jumpbox (SSH session)

ssh user@192.168.0.20  # SSH to LinuxServer
curl http://192.168.0.20/  # web reachability
ping -c 2 google.com  # DNS + NAT
ping -c 2 192.168.0.15  # WinSrv reachable
What success looks like: every URL loads, every ping responds (where allowed), DNS resolves names, NAT carries internet traffic. Take screenshots of all of this for the lab report.

Phase 3 done — final checkpoint

You've built a real, segmented, functioning network with services. That's it. That's the lab.

Troubleshooting — when things break

A flat list of every common issue, organized by symptom. Search this page (Cmd+F) when you hit a wall.

Universal first checks (do these before anything else)

  • Is the right VM running? Proxmox UI shows a green play arrow next to running VMs.
  • Is the right network bridge attached? VM → Hardware → Network Device → check the bridge name.
  • Is the IP what you think it is? Inside the VM: ip -br addr (Linux) or ipconfig /all (Windows).
  • Is the gateway reachable? ping 192.168.0.1 (LAN VMs) or ping 172.16.0.1 (DMZ VMs).
  • Did you save your firewall changes in pfSense? "Apply Changes" button at the top of pfSense pages — yellow banner appears when there are unsaved changes.
  • Is your browser showing a cached page? Hard reload: Cmd+Shift+R or Cmd+Option+R.

Phase 1 — Hardware + Hypervisor

SymptomCause / Fix
No video output from serverCheck the cable. ML350p Gen8 has VGA, not HDMI. Use a real VGA monitor or a VGA-to-HDMI converter.
Server beeps repeatedly on powerMemory error. Reseat the RAM modules — push them firmly until both latches snap.
"Press F1 to continue, F9 for setup"BIOS event log filled. Press F1 to dismiss; clear in BIOS → System Options → Health Logs.
RAID drives not detectedReseat drives. Check the cable from the Smart Array P420i to the backplane. POST should show the controller initializing.
Proxmox installer freezesBad RAID drive. Boot Intelligent Provisioning (F10) → diagnostics. Or install onto a single working drive temporarily.
Can't reach Proxmox web GUI from laptopWrong IP, wrong subnet, school firewall blocking 8006, or self-signed cert refused. SSH directly first to confirm Proxmox is alive.

Phase 2 — Networking + Virtual Machines

SymptomCause / Fix
Lost SSH to Proxmox after editing /etc/network/interfacesYou edited vmbr0 by accident. Use the physical console; nano /etc/network/interfaces to fix; ifreload -a.
VM won't boot — black screen foreverWrong machine type or bad ISO. For Linux Desktop: try Display = SPICE, Machine = q35. For Windows: BIOS = OVMF (UEFI).
Ubuntu Desktop installer hangsOut of RAM (need 4 GB+) or graphics driver. Boot with "safe graphics" mode (press e at GRUB, append nomodeset). Or switch to Server + Xubuntu Core.
VM has no IP after installNIC name changed (was ens18, became enp6s18 after machine type change). Set up the new interface name in Network settings.
pfSense WAN didn't get DHCPSchool filters unfamiliar MACs. Reboot the VM, or have your instructor whitelist the MAC.
pfSense WAN got an IP but no internetDefault-deny "block private networks on WAN" rule is on. Disable it (Interfaces → WAN → uncheck "Block private networks") — your school IS a private network.
noVNC console won't pasteKnown limitation. SSH from Proxmox host shell into the VM instead — that's paste-friendly.
Ping from VM to gateway works, but ping to internet failsNAT on pfSense isn't configured (Firewall → NAT → Outbound = Automatic). Or the LAN firewall rule blocks ICMP outbound (correct behavior — try curl instead).
Static IP set but APIPA (169.254.x.x) shows up(Windows) DHCP got disabled but static didn't apply. Use the GUI (ncpa.cpl), not netsh — more reliable.

Phase 3 — Services + Verification

SymptomCause / Fix
NGINX shows "Welcome to nginx" but won't render PHPFastCGI socket path wrong. ls /run/php/, find the actual php*-fpm.sock, fix the path in /etc/nginx/sites-available/default, sudo systemctl reload nginx.
Apache fails with "AllowOverride not allowed here"The Directory directive needs to be inside the VirtualHost. Move it from any conf-enabled file into /etc/apache2/sites-available/000-default.conf.
Two web servers conflict on port 80Move Apache to 8080: edit /etc/apache2/ports.conf change Listen 80 to Listen 8080, edit 000-default.conf change VirtualHost *:80 to *:8080.
MariaDB connection from PHP failsWrong password in PHP, or user doesn't have privileges. Run sudo mariadbSHOW GRANTS FOR 'capuser'@'localhost';
AD-DS install fails Prerequisites Check (red error)Almost always: WinSrv has a DHCP IP (needs static), or hostname is still WIN-XXXXX default. Fix both, retry.
Domain join from another VM failsClient's DNS must point at the DC's IP (so it can find the domain). Set DNS to WinSrv's IP, not pfSense.
Two DHCP servers fighting (Windows DHCP + pfSense DHCP)Disable pfSense's LAN DHCP first (Services → DHCP Server → LAN tab → uncheck Enable). Then activate Windows DHCP role.
pfSense shows red "default password" warningChange it (System → User Manager → admin → pencil → set strong password).
RFC1918 alias contains "10.0.0.o" (letter O)Typo. Edit (Firewall → Aliases → IP → RFC1918) → fix to 10.0.0.0/8.
Browser can't reach internal web server but ping worksUFW blocking on the server. sudo ufw allow 80/tcp and sudo ufw allow 443/tcp.

"I'm stuck and don't know why" — diagnostic flow

  1. Where in the path is it broken? Try ping/curl from progressively further away: same VM → same subnet → across subnets → to internet. Whichever hop fails, that's where the issue is.
  2. Read the actual error. Linux: journalctl -xe or tail -f /var/log/syslog. Windows: Event Viewer → System log. The first red error is usually the cause; everything after is fallout.
  3. Check the obvious before the clever. Cable plugged in. Service running. Firewall not blocking. Time correct. DNS resolving. 95% of "weird" issues are one of these.
  4. Snapshot before risky changes. Proxmox UI → VM → Snapshots → Take Snapshot. If you break something, you can roll back in 30 seconds.
  5. Document as you fix. When you solve a weird issue, write down what you tried + what worked. Saves you 2 hours next time.

Where to go from here

You've built the lab. Now what?

Immediate next steps

  • Take screenshots of everything — your lab report wants visual proof of every working service. See week2-verification.html for the screenshot checklist.
  • Take a Proxmox snapshot of every working VM. If you break something experimenting, you can roll back.
  • Practice the demo — your final presentation is a 15-minute walkthrough. Rehearse it once end-to-end before the actual demo.

Stretch goals (Week 3+ material)

  • Backups — schedule nightly Proxmox VM backups to a second disk. Restore one to prove it works.
  • Snort or Suricata IDS — pfSense can run intrusion detection on the WAN and DMZ interfaces.
  • VPN — set up OpenVPN or WireGuard on pfSense so you can reach the lab remotely.
  • Monitoring — install Wazuh, Prometheus + Grafana, or Zabbix to graph all VM health.
  • Domain-join the LinuxServerrealm join capstone.local from Ubuntu, single-sign-on across the lab.
  • HTTPS everywhere — set up an internal Certificate Authority on the WinSrv, issue certs to NGINX/Apache.

Other docs in this guide

Copied to clipboard