Week 2 — Build Verification Walkthrough

Step-by-step procedure to confirm every VM's actual configuration, with verified-state captures from the 2026-05-05 lab session.

Verified: 2026-05-05 Host: tctmachine VMs: 6 (1 template + 4 active + 1 installing) Topology: pfSense2-routed

What this document is

This is the verification walkthrough for our Week 2 capstone build. Every fact below was confirmed by running a command or opening a screen on 2026-05-05. It's organized in five phases — Host first, then each VM in dependency order — so you can re-run it from a cold start and arrive at the same conclusions.

Read it as "how I would prove this build works to someone who doesn't trust me yet". That's the spirit.

Sister doc: the high-level lab walkthrough lives in Main Guide → Lab Guide. That page tells you how to build the lab; this page tells you how to prove it's built right.
Heads up — three security items found during verification. See the To-do list for the punch list. Most urgent: change pfSense admin password (still set to default pfsense).

Topology — what we actually built

The instructor's new Week 1–5 guide says NAT lives on the Proxmox host (via iptables). Our actual build delegates routing/NAT/DHCP/DNS to pfSense2 (VM 103), which has NICs on all three bridges. The host's iptables rules exist but are vestigial — pfSense2 NATs every internal packet before the host ever sees it.

🗺️ Open topology presentation → — 13-slide walkthrough for class

☁️ School LAN 10.10.0.0/16 WAN uplink 🛡️ pfSense2 (VM 103) DNS · DHCP · Firewall · NAT WAN 10.10.110.10 DMZ 172.16.0.1/24 LAN 192.168.0.1/24 vmbr0 vmbr1 vmbr2 🖥️ Proxmox Host tctmachine · PVE 8.2.2 10.10.10.10 💻 Jumpbox (VM 101) Ubuntu 26.04 · UFW 172.16.0.100 🪟 WinSrv (102) Win Srv 2025 Eval 192.168.0.15 🐧 LinuxServer (105) Ubuntu 26.04 srv 192.168.0.20 🖱️ Linux-Ubuntu (104) Ubuntu 24.04 Desktop 192.168.0.25 📦 Also in inventory VM 100 PFsense — template, clone source for VM 103 Dashed border on VM 104 = install pending
vmbr0 — School LAN / mgmt vmbr1 — DMZ 172.16.0.0/24 vmbr2 — LAN 192.168.0.0/24
running active VM with verified config created VM exists but service config pending template/stopped not currently running
1

Phase 1 — Proxmox host inspection

Verified ✓

Goal: snapshot bridges, VM inventory, NAT rules, and ip_forward state from the host without depending on any VM being reachable.

Step 1.1 — Open the Proxmox host shell

1
Web UI shell (preferred — clipboard works)

In Safari, open https://10.10.10.10:8006 → log in as root → in the left tree click the node tctmachine → top tab >_ Shell. A web terminal opens with prompt root@tctmachine:~#.

Alternative: from your Mac Terminal, ssh root@10.10.10.10. Same result, but the web shell pastes more reliably from macOS.

Step 1.2 — Run the host inspection block

2
Paste this single block, hit Enter
# prints host info, all bridges, /etc/network/interfaces, qm list, then every VM config
echo "=== HOST ==="
hostname
pveversion
ip -br addr
echo
echo "=== BRIDGES (/etc/network/interfaces) ==="
cat /etc/network/interfaces
echo
echo "=== VM LIST ==="
qm list
echo
for id in 100 101 102 103 104; do
  echo
  echo "=========================================="
  echo "  VM $id"
  echo "=========================================="
  qm config $id 2>&1
done

Step 1.3 — Run the NAT / iptables follow-up block

3
Resolves "where do the NAT rules actually live"
echo "=== NAT / iptables — where do the rules live? ==="
ls -la /etc/network/interfaces.d/ 2>/dev/null
echo "--- interfaces.d contents ---"
cat /etc/network/interfaces.d/* 2>/dev/null || echo "(empty or missing)"
echo
echo "--- /etc/iptables/rules.v4 ---"
cat /etc/iptables/rules.v4 2>/dev/null || echo "(no persistent file)"
echo
echo "--- live nat table ---"
iptables -t nat -L -n -v
echo
echo "--- ip_forward sysctl ---"
sysctl net.ipv4.ip_forward
grep -H ip_forward /etc/sysctl.conf /etc/sysctl.d/*.conf 2>/dev/null

Verified state — host

FieldValue
Hostnametctmachine
Proxmox versionpve-manager 8.2.2 · kernel 6.8.4-2-pve
Physical NIC in useeno1 (UP) — eno2/3/4 down, unused
vmbr010.10.10.10/16 · gw 10.10.10.1 · bridges eno1
vmbr1172.16.0.10/24 · bridge_ports none (VM-only)
vmbr2192.168.0.10/24 · bridge_ports none (VM-only)
IP forwardingnet.ipv4.ip_forward = 1 (set in /etc/sysctl.conf + /etc/sysctl.d/99-sysctl.conf; duplicated, harmless)
iptables-persistent rulesPresent — see findings below
VMs in inventory100 (template), 101 (running), 102 (running), 103 (running), 104 (stopped)

Findings — host

✓ Bridges configured per spec

vmbr0/1/2 all UP, on correct subnets, with correct host-side IPs. Matches the new Week 1–5 ODT guide.

⚠ NAT MASQUERADE rule has a stray /32

/etc/iptables/rules.v4 contains -A POSTROUTING -s 10.10.110.10/32 -o vmbr0 -j MASQUERADE. 10.10.110.10 is pfSense2's WAN IP — the rule is redundant (pfSense2 already NATs internally) and matched only 1 packet ever. Functionally inert. Can be deleted or left.

⚠ Internal-subnet MASQUERADE missing

The host has no MASQUERADE rule for 172.16.0.0/24 or 192.168.0.0/24. Doesn't matter — pfSense2 routes/NATs all internal traffic. But if you later switch to host-iptables NAT (the canonical guide topology), you'll need to add them.

ℹ Forward-chain ACL rules ARE persisted

rules.v4 has -A FORWARD -s 172.16.0.0/24 -d 192.168.0.0/24 -j ACCEPT and a port-22 forward — leftover from earlier topology work. Harmless. Document or remove during Week 3 cleanup.

Screenshots

Proxmox host shell at root@tctmachine showing pveversion 8.2.2/9355359cd7afbae4 kernel 6.8.4-2-pve, qm list output with all 6 VMs (100 PFsense stopped, 101 jumpbox running, 102 WinSrv running, 103 PFsense2 running, 104 Linux-Ubuntu running, 105 LinuxServer running) with their memory and disk sizes
Phase 1 · Fig 01 ✓Host shell · pveversion + full qm list table — all 6 VMs accounted for (note: VM 104 + VM 105 both running). Captured 2026-05-06.
qm config 100 (PFsense template, template: 1, three vmbr NICs, ide2 netgate-installer ISO) and qm config 101 (jumpbox, Ubuntu 26.04 ISO, single net0 on vmbr1, scsi0 vm-101-disk-0 25G)
Phase 1 · Fig 02 ✓VM 100 (template) + VM 101 (jumpbox) configs · confirms template: 1 on the PFsense base disk and single-NIC on vmbr1 for jumpbox.
Proxmox host shell showing live iptables nat table with PREROUTING, INPUT, OUTPUT, POSTROUTING chains. POSTROUTING has 1 MASQUERADE rule for source 10.10.110.10 out vmbr0. cat /etc/iptables/rules.v4 returned Permission denied (needed sudo)
Phase 1 · Fig 03 ✓Live iptables -t nat -L -n -v · only one MASQUERADE rule, source 10.10.110.10/32 (pfSense WAN IP) — vestigial double-NAT, only matched 1 packet ever. Note: cat /etc/iptables/rules.v4 needs sudo — that error is expected on the screenshot.
2

Phase 2 — Jumpbox (VM 101)

Verified ✓

Goal: confirm the jumpbox runs Ubuntu, has a healthy DHCP lease, can reach the internet, has SSH up, and has UFW restricting SSH to the lab subnets.

Step 2.1 — Find the jumpbox IP from the host

1
ARP cache lookup

The Proxmox web console doesn't accept clipboard paste, so we SSH in from the host shell instead. First find the jumpbox IP from the host's ARP table on vmbr1:

ip neigh show dev vmbr1

Look for the line whose MAC matches the jumpbox's net0 from VM 101's config (BC:24:11:12:5A:69). That's your IP. In our build it landed on 172.16.0.100 via DHCP from pfSense2.

Watch out: stale ARP entries can show old IPs. If you see two entries for the same MAC, the more recent one is current. Run ping -c1 172.16.0.100 first to refresh.

Step 2.2 — SSH from host into jumpbox

2
Use the host shell as the SSH origin
ssh tct_jumpbox@172.16.0.100

Type yes on the first connection to accept the host key. Enter the password you set at install. Now you're inside the jumpbox and in a paste-friendly terminal (because the host's web shell carried the paste support through the SSH session).

Common gotcha: typing 10.1o.10.10 (letter O instead of zero) gives "Could not resolve hostname". Always copy/paste IPs.

Step 2.3 — Run the jumpbox inspection block

3
Network, OS, SSH config, UFW, gateway test
echo "=== JUMPBOX (VM 101) ==="
hostnamectl
echo
echo "--- network ---"
ip -br addr
ip route
resolvectl status | grep -E "DNS Servers|Current DNS|Link "
echo
echo "--- OS / packages ---"
lsb_release -a 2>/dev/null
uname -r
echo
echo "--- SSH config status ---"
sudo grep -E '^(Port|PermitRootLogin|PasswordAuthentication|AllowUsers|MaxAuthTries|PubkeyAuthentication)' /etc/ssh/sshd_config
sudo grep -rE '^(Port|PermitRootLogin|PasswordAuthentication)' /etc/ssh/sshd_config.d/ 2>/dev/null
sudo systemctl is-active ssh
sudo systemctl is-enabled ssh
echo
echo "--- UFW ---"
sudo ufw status verbose
echo
echo "--- who is the gateway really? ---"
ip route get 8.8.8.8
Important: use single quotes (') around the regex in the grep -E calls. Double quotes get the parens eaten by bash and the grep fails with "Unmatched (".

Verified state — jumpbox

FieldValueStatus
OSUbuntu 26.04 LTS "resolute" · kernel 7.0.0-14-genericverified
Hostnametctmachine (matches Proxmox host name — confusing)to fix
NICens18 on vmbr1 · MAC BC:24:11:12:5A:69verified
IPv4172.16.0.100/24 via DHCP from pfSense2DHCP not static
Gateway172.16.0.1 = pfSense2 DMZ interfaceroutes through pfSense2
DNS172.16.0.1 = pfSense2 Unbound resolververified
SSH serviceactive + enabled (default port 22, default config)not hardened yet
UFW statusactive · default deny in / allow out · port 22 ALLOW from 10.10.10.0/24, 192.168.0.0/24, 172.16.0.0/24matches Part 7 step 4
Internet reachabilityping google.com + ping 1.1.1.1 both 0% loss, ~9–10 ms RTTverified

Findings — jumpbox

✓ Outbound connectivity proven

DNS resolves, ICMP works, latency normal. Confirms pfSense2 is doing NAT correctly and pushing healthy DNS via DHCP.

⚠ Hostname collision with host

Both Proxmox host and jumpbox identify as tctmachine. Confusing in logs and SSH banners. Fix: sudo hostnamectl set-hostname jumpbox, then update /etc/hosts and reboot.

⚠ DHCP not static

Lab guide spec is 172.16.0.2 static. We're at 172.16.0.100 dynamic. Two ways to fix: (a) static IP via netplan, (b) DHCP reservation in pfSense2 (Services → DHCP → DMZ → Static Mappings).

⚠ SSH not hardened

Default port 22, root login + password auth still permitted. Lab guide Part 7 step 3 prescribes: change port (e.g. 2222), PermitRootLogin no, PasswordAuthentication no (after key-based login is set up), AllowUsers tct_jumpbox, MaxAuthTries 3.

Screenshots

ip neigh show dev vmbr1 output on Proxmox host showing 172.16.0.20 lladdr bc:24:11:76:3e:4b STALE (pfSense2 alias), 172.16.0.1 lladdr bc:24:11:76:3e:4b STALE (pfSense2 DMZ), 172.16.0.100 lladdr bc:24:11:12:5a:69 STALE (jumpbox)
Phase 2 · Fig 04 ✓Host ARP cache for vmbr1 · pfSense2 at .1 (gateway) + .20, jumpbox at .100. Confirms MAC bc:24:11:12:5a:69 = jumpbox.
📸
Screenshot pending
photos/verification/05-jumpbox-ssh-prompt.png
Capture: SSH session showing tct_jumpbox@tctmachine:~$ prompt right after login from the host shell.
Phase 2 · Fig 05SSH from host → jumpbox successful
Jumpbox terminal showing successful pings to google.com and 1.1.1.1
Phase 2 · Fig 06 ✓Jumpbox internet test — ping google.com (0% loss) + ping 1.1.1.1 (0% loss). Captured 2026-05-05 5:48 PM CDT.
Jumpbox SSH session showing hostnamectl Ubuntu 26.04, ens18 at 172.16.0.100, ip route default via 172.16.0.1, ping 1.1.1.1 success
Phase 2 · Fig 07 ✓Jumpbox SSH session — hostnamectl + ip -br addr + ping 1.1.1.1 with 0% loss. Captured 2026-05-06.
3

Phase 3 — pfSense2 (VM 103)

Verified ✓

Goal: confirm pfSense2 is the live router/firewall/DHCP/DNS for both internal subnets, document version/IPs/scopes/NAT mode, and flag the security-critical default password.

Step 3.1 — Open the Proxmox console for VM 103

1
Quick check via the FreeBSD-style menu

Proxmox UI → click VM 103 (PFsense2) in the left tree → top-right tab >_ Console. The noVNC window opens to pfSense's blue text menu. Press Enter once to refresh the header — that prints the welcome banner with all three interface IPs without typing a single command.

What you should see at the top:

*** Welcome to pfSense 2.8.1-RELEASE (amd64) on pfSense ***

  WAN (wan)  -> vtnet0  -> v4: 10.10.110.10/16
  DMZ (lan)  -> vtnet1  -> v4: 172.16.0.1/24
  LAN (opt1) -> vtnet2  -> v4: 192.168.0.1/24
Naming oddity: pfSense's internal "lan" handle is mapped to our DMZ interface, and "opt1" is our LAN. That's just an artifact of how the interfaces were assigned at install. Functionally fine, but rename them in Interfaces → Assignments to match labels for clarity later.

Step 3.2 — Open pfSense web UI via SSH tunnel

2
Tunnel through the Proxmox host

From your Mac Terminal (not the Proxmox web shell), run:

ssh -L 8443:172.16.0.1:443 root@10.10.10.10

That forwards localhost:8443 on your Mac → through the Proxmox host (which has 172.16.0.10 on vmbr1) → to pfSense2's web UI on its DMZ interface. Leave the SSH session open. Then in Safari open:

https://localhost:8443

Accept the self-signed cert warning. Log in as admin with whatever password you set (or pfsense if you haven't changed it — and you should).

🚨 Security finding right at the top of every pfSense page:
"WARNING: The password for this account is insecure. Password is currently set to the default value (pfsense)."
Fix immediately in System → User Manager → admin → set strong password. Anyone on the school LAN (10.10.0.0/16) can otherwise log in to https://10.10.110.10 and own your firewall.

Step 3.3 — Capture the verification pages

3
Six screenshots, in this order
  1. Status → Dashboard — version, uptime, interfaces, DNS servers
  2. Services → DHCP Server → DMZ tab — General Settings + Primary Address Pool
  3. Services → DHCP Server → LAN tab — same sections
  4. Services → DNS Resolver → General Settings — interfaces, DNSSEC, listen ports
  5. Firewall → NAT → Outbound — confirms automatic NAT mode
  6. Status → DHCP Leases — current leases (jumpbox + WinSrv)

Verified state — pfSense2

FieldValue
BuildpfSense Community Edition 2.8.1-RELEASE (amd64), built 2025-12-15, FreeBSD 15.0-CURRENT
HostnamepfSense.home.arpa (default — change before AD install)
Netgate Device IDe1878a207e806ad04215 (registered CE install)
Resources2 vCPU @ 2.49 GHz · 1991 MiB RAM (12% in use) · 1024 MiB swap (0%)
WAN10.10.110.10/16 on vtnet0 (vmbr0) · uplink to school LAN
DMZ (labeled "lan")172.16.0.1/24 on vtnet1 (vmbr1)
LAN (labeled "opt1")192.168.0.1/24 on vtnet2 (vmbr2)
DMZ DHCP scopeISC DHCP · pool 172.16.0.100 – .200 · pushed DNS 172.16.0.1 · allow all clients
LAN DHCP scopeISC DHCP · pool 192.168.0.100 – .200 · pushed DNS 192.168.0.1 · allow all clients
DNS ResolverUnbound · enabled · listens DMZ + LAN (not WAN) · egresses WAN · DNSSEC on · upstream 1.1.1.1
Outbound NAT modeAutomatic — both 172.16/24 + 192.168/24 auto-MASQUERADEd out WAN address
Active DHCP leases1 active (172.16.0.100 = tctmachine/jumpbox) · 1 stale offline (192.168.0.100 = TCT-WinSrv pre-static — clean up via Status→DHCP Leases→Delete)
Admin passwordDEFAULT (pfsense) — change immediately

Findings — pfSense2

🚨 Default admin password

WebGUI displays a red banner on every page. Anyone reachable on 10.10.0.0/16 can log in. Highest-priority fix.

✓ NAT mode = Automatic

Both internal subnets get auto-MASQUERADE. No manual rules needed. Confirmed live by the jumpbox successfully reaching the internet via gateway 172.16.0.1.

✓ DNSSEC validation enabled

Unbound validates DNSSEC and only listens on internal interfaces — nothing exposed to WAN. Solid baseline.

⚠ Default hostname / domain

pfSense.home.arpa — the .arpa TLD is RFC-reserved for reverse-DNS infrastructure and is poor choice for an AD domain. Set to something like pfsense2.capstone.local in System → General Setup before promoting WinSrv.

⚠ Interface label mismatch

pfSense calls 172.16/24 "lan" and 192.168/24 "opt1". Internal handles only — relabel as DMZ / LAN in Interfaces → Assignments for clarity.

ℹ ISC DHCP end-of-life banner

pfSense's leases page warns ISC DHCP is deprecated; future versions will use Kea. Migration path: System → Advanced → Networking → DHCP Backend. Not blocking, document for Week 5.

✓ LAN firewall ruleset is hardened (defense-in-depth)

Discovered during VM 105 verification: the LAN interface has a deliberately tight 9-rule policy, not the default "allow LAN to any". Strong Week 3 evidence as-is. Detail in the table below.

LAN firewall rules — verified 2026-05-05

Order matters in pfSense (top-to-bottom, first match wins). This ruleset implements: ICMP only to gateway · DNS+NTP only to local resolver · no lateral movement to DMZ/RFC1918 · web/DNS/NTP outbound only via curated alias · WinRM/SMB allowed for Windows admin.

#ActionProtocolSource → DestinationDescription
1PASSICMP echoreqLAN_NET → This FirewallPing outbound (gateway only)
2PASSUDP/123LAN_NET → This FirewallNTP to pfSense
3PASSUDP/53LAN_NET → This FirewallDNS to pfSense (Unbound)
4BLOCKanyLAN_NET → This FirewallBlock servers → pfSense management (web GUI, SSH)
5BLOCKanyLAN_NET → DMZ_NETBlock LAN-initiated traffic to DMZ (no return-initiated)
6BLOCKanyLAN_NET → RFC1918 aliasBlock lateral movement to other private ranges
7PASSTCP/UDPLAN_NET → OUTBOUND_WEB aliasOutbound web/DNS/NTP only · alias = ports {80, 443, 53, 123}
8PASSTCPLAN_NET → port 5985–5986WinRM (Windows remote mgmt)
9PASSTCPLAN_NET → port 445SMB (file sharing) — note: rule label says "WinRM", actually MS-DS

OUTBOUND_WEB alias — verified contents

PortServiceNotes
80HTTPPlain web (often used for redirect to 443, package mirrors)
443HTTPSTLS-encrypted web (apt mirrors, GitHub, Microsoft Update, etc.)
53DNSFor DNS-over-TCP fallback to upstream resolvers (UDP/53 is already covered by rule 3)
123NTPTime sync to pool.ntp.org and similar — though VMs should prefer pfSense's NTP via rule 2

Alias entries created Sat, 02 May 2026 21:20:31 -0500.

What this means in practice: from any LAN VM (WinSrv, LinuxServer), curl https://anything.com works (rule 7 + 1 covers TLS handshake), apt update works (HTTP/HTTPS to mirrors), Windows Update works (HTTPS to Microsoft + WinRM ports). What doesn't work: ping 1.1.1.1 from LAN (only ICMP to gateway is allowed — by design), SSH outbound to arbitrary internet hosts, arbitrary outbound TCP. This is a feature, not a bug.

Screenshots

📸
Screenshot pending
photos/verification/08-pfsense-console-menu.png
Capture: pfSense's Proxmox-console main menu. Should show WAN/DMZ/LAN banner with all three IPs.
Phase 3 · Fig 08pfSense2 console menu — interface IPs
pfSense Status Dashboard showing System Information (Version 2.8.1-RELEASE, FreeBSD 15.0-CURRENT, uptime 3d 20h, DNS 127.0.0.1 + 1.1.1.1) and Interfaces panel (WAN 10.10.110.10, DMZ 172.16.0.1, LAN 192.168.0.1)
Phase 3 · Fig 09 ✓pfSense2 web UI dashboard — version, uptime, DNS, interface IPs. Captured 2026-05-06.
DMZ DHCP scope showing subnet 172.16.0.0/24, pool 172.16.0.100 to 172.16.0.200, allow all clients, ISC DHCP backend, DNS server 172.16.0.1
Phase 3 · Fig 10 ✓DMZ DHCP scope · subnet 172.16.0.0/24 · pool .100–.200 · DNS 172.16.0.1.
LAN DHCP scope showing subnet 192.168.0.0/24, pool 192.168.0.100 to 192.168.0.200, allow all clients, ISC DHCP backend, DNS server 192.168.0.1
Phase 3 · Fig 11 ✓LAN DHCP scope · subnet 192.168.0.0/24 · pool .100–.200 · DNS 192.168.0.1.
pfSense DNS Resolver General Settings — Unbound enabled on port 53, listen interfaces DMZ and LAN selected, outgoing interface WAN, DNSSEC support enabled, system domain local zone Transparent
Phase 3 · Fig 12 ✓DNS Resolver (Unbound) — listen DMZ+LAN, egress WAN, DNSSEC on. Captured 2026-05-06.
Firewall NAT Outbound page — red password warning at top, Mode set to Automatic outbound NAT rule generation, automatic rules listing 127.0.0.0/8, 172.16.0.0/24, 192.168.0.0/24 with NAT Address WAN address
Phase 3 · Fig 13 ✓Outbound NAT · Mode = Automatic · auto-rules cover both internal subnets · 🚨 default-password warning at top.
DHCP Leases page showing 172.16.0.100 = tctmachine (jumpbox) and 192.168.0.101 = ubuntu (LinuxServer or similar), with ISC DHCP end-of-life banner at top
Phase 3 · Fig 14 ✓Active DHCP leases — jumpbox at 172.16.0.100 and second host at 192.168.0.101. ISC-DHCP EOL banner visible.
Firewall Rules LAN tab showing the 9-rule defense-in-depth ruleset: PASS ICMP/NTP/DNS to This Firewall, BLOCK other to firewall, BLOCK to DMZ_NET, BLOCK to RFC1918, PASS TCP/UDP to OUTBOUND_WEB, PASS TCP to 5985-5986 (WinRM), PASS TCP to 445 (SMB)
Phase 3 · Fig 14a ✓LAN firewall ruleset — 9 rules · defense-in-depth · the Week 3 evidence centerpiece.
OUTBOUND_WEB alias edit page showing Type Port(s) with ports 80, 443, 53, 123 each entry added Sat 02 May 2026 21:20:31 -0500
Phase 3 · Fig 14b ✓OUTBOUND_WEB alias = ports {80, 443, 53, 123}. The destination set rule 7 allows.
pfSense Firewall Aliases IP tab listing DMZ_NET (172.16.0.0/24), JUMP_HOSTS, LAN_NET (192.168.0.0/24), RFC1918 with values 10.0.0.o 172.16.0.0/12 192.168.0.0/16, SRV_HOSTS
Phase 3 · Fig 14c ✓Network aliases — DMZ_NET, LAN_NET, RFC1918, plus host aliases JUMP_HOSTS + SRV_HOSTS. ⚠ RFC1918 alias shows 10.0.0.o — looks like a typo (should be 10.0.0.0/8); verify and fix.
4

Phase 4 — WinSrv (VM 102)

Verified ✓ (fresh OS — no Week 2 services yet)

Goal: confirm Windows Server 2025 Eval install, network config, eval license clock, and current installed roles (= baseline only).

Step 4.1 — Open WinSrv console + sign in

1
Proxmox noVNC console

Click VM 102 (WinSrv) in the Proxmox tree → >_ Console. Click in the console area, press a key, sign in as Administrator. Server Manager opens automatically on first login.

Why not RDP? RDP is currently disabled on this server (verified — see findings). To switch to RDP later: in Server Manager → Local Server, click the word "Disabled" next to Remote Desktop → enable. Then RDP via SSH tunnel (ssh -L 3389:192.168.0.100:3389 root@10.10.10.10 + connect to localhost from Microsoft Remote Desktop).

Step 4.2 — Capture Server Manager → Local Server

2
One-shot view of all server properties

Server Manager → Local Server in the left sidebar. The right pane shows Properties (firewall state, RDP state, time zone, edition, etc.) and at the very bottom the ROLES AND FEATURES panel listing every installed component.

Screenshot the top of Local Server, then scroll down and screenshot the Roles and Features panel.

Step 4.3 — Run ipconfig /all

3
Authoritative IP/DNS/DHCP info

Press Win key → type cmd → Enter. Then:

ipconfig /all

Screenshot the entire window. Confirms host name, MAC, IPv4, subnet, gateway, DNS servers, DHCP server, lease window — straight from Windows.

Step 4.4 — Capture Settings → System → About

4
Eval install date and version

Win+I → System → scroll to bottom → About. Records edition, version (24H2), OS build, and most importantly Installed on date. Add 180 days to compute the eval expiration.

Verified state — WinSrv

FieldValueStatus
HostnameTCT-WinSrvverified
EditionWindows Server 2025 Datacenter Evaluationeval
Version24H2 · build 10.0.26100.32230current
Installed on2026-04-27eval expires ~2026-10-24
Memory4.00 GB allocated, ~3.96 GB usableverified
ProcessorQEMU Virtual CPU 2.5+ @ 2.49 GHz · 2 vCPU (2 sockets × 1 core)verified
NICIntel(R) PRO/1000 MT (e1000) · MAC BC-24-11-D7-70-2D on vmbr2 with Proxmox firewall enabledverified
IPv4192.168.0.15/24 · static (changed from DHCP .100 on 2026-05-05 evening) — team chose .15 instead of lab-guide's .10static · verified
Subnet / Gateway / DNS255.255.255.0 / 192.168.0.1 / 192.168.0.1verified
DNS suffixhome.arpa (inherited from pfSense default)change before AD
Time zone(UTC−08:00) Pacific TimeWRONG · should be Central
Microsoft Defender FirewallPublic profile: Onon
Microsoft Defender AntivirusReal-Time Protection: Onon
Remote ManagementEnabledon
Remote DesktopDisabledenable for RDP
Roles installed1 — File and Storage Services (default)AD/DNS/DHCP/IIS pending
Features installed13 — baseline only (PowerShell, .NET 4.8, Defender AV, etc.)fresh OS baseline
Pending Windows Updates"Attention needed" banner shownrun before AD install

Findings — WinSrv

✓ Network reachable, DHCP healthy

IP/DNS/Gateway all consistent with pfSense2's lease record. Lease renews automatically.

🔴 Time zone is Pacific, not Central

You're in Austin TX. Kerberos/AD authentication requires accurate time. Fix before AD install: Settings → Time & language → Date & time → Time zone → (UTC−06:00) Central Time.

⚠ DHCP IP must go static for AD-DS

DONE 2026-05-05 evening: WinSrv moved to static 192.168.0.15/24, gateway 192.168.0.1, DNS 192.168.0.1. Team chose .15 over the lab-guide's .10 — both work; .15 is still outside the DHCP pool .100–.200. Original DHCP lease on .100 still showing as offline in pfSense — clean up at Status → DHCP Leases.

⚠ DNS suffix is home.arpa

RFC 8375 reserves this for residential networks; not appropriate for an AD domain. Plan: rename pfSense system domain (System → General Setup) to capstone.local, then promote WinSrv with that domain.

ℹ Eval expires ~2026-10-24

180 days from 2026-04-27. ~172 days remaining as of capture. Capstone ends well before. If you ever need more, run slmgr /rearm (admin) — extends eval by 60 days, up to 5 times.

ℹ Windows Update attention

Pending updates flagged on the Settings home screen. Run them before AD-DS install — DC promotion fails on certain unpatched builds.

ℹ DNS Client warning event 1014

One Warning in the System log (5/4/2026 6:11 PM, source Microsoft-Windows-DNS Client Events). Typically a transient DNS lookup timeout. Re-test after services are installed; ignore if non-recurring.

Screenshots

Server Manager Local Server panel on TCT-WinSrv showing Properties — firewall, RDP, NIC teaming, ethernet, time zone, OS version Windows Server 2025 Datacenter Eval, with Events list at bottom
Phase 4 · Fig 15 ✓Server Manager · Local Server — Defender FW Public On, RDP Disabled, time zone Pacific (TODO Central), OS Win Srv 2025 Eval.
WinSrv Command Prompt running ipconfig /all — Host Name TCT-WinSrv, Ethernet adapter Intel PRO/1000 MT, MAC BC-24-11-D7-70-2D, DHCP Enabled No, IPv4 Address 192.168.0.15 Preferred, Subnet Mask 255.255.255.0, Default Gateway 192.168.0.1, DNS Servers 192.168.0.1
Phase 4 · Fig 16 ✓ipconfig /all · static 192.168.0.15(Preferred) · DHCP Enabled: No · gateway + DNS = pfSense.
WinSrv Settings System About — Device name TCT-WinSrv, Processor QEMU Virtual CPU 2.5+ 2.49 GHz 2 procs, Installed RAM 4 GB, System type 64-bit, Edition Windows Server 2025 Datacenter Evaluation, Version 24H2, Installed on 4/27/2026, OS build 26100.32230
Phase 4 · Fig 17 ✓Settings · About — Win Srv 2025 Datacenter Eval · 24H2 · build 26100.32230 · installed 4/27/2026 (eval expires ~10/24/2026).
Server Manager Roles and Features panel showing 14 total — XPS Viewer, WoW64 Support, Microsoft Defender Antivirus, Wireless LAN Service, System Data Archiver, Windows PowerShell, Windows PowerShell 5.1
Phase 4 · Fig 18 ✓Server Manager · Roles and Features (1/2). 14 items total — first 7 visible. All baseline OS features.
Server Manager Roles and Features panel showing the second half — Windows PowerShell 5.1, .NET Framework 4.8 Features, .NET Framework 4.8, WCF Services, TCP Port Sharing, Windows Admin Center Setup, File and Storage Services
Phase 4 · Fig 19 ✓Server Manager · Roles and Features (2/2). Bottom 7 — only File and Storage Services is a Role; everything else is a default Feature.
5

Phase 5 — LinuxServer (VM 105)

Install in progress

Status as of 2026-05-05 evening: VM 105 created and Ubuntu Server install actively running. Sibling VM 104 (Ubuntu 24.04 Desktop) stays in the build as the Linux GUI client workstation — see "Sibling — VM 104" section below for the install plan.

Why a new VM (105) instead of VM 104

Decision: VM 104 was scaffolded earlier with the wrong ISO (ubuntu-24.04.4-desktop-amd64.iso — Desktop edition) and never booted. Rather than swap the ISO and risk inheriting half-configured settings, we created a clean VM 105 with the Server ISO. VM 104 stays in inventory for now as a sandbox / clean-up candidate (see to-do).

VM 105 build settings (target spec)

SettingValue
VMID / Name105 / LinuxServer
OSUbuntu Server (24.04 LTS or 26.04 LTS — confirm post-install)
Hardware2 vCPU · 2 GB RAM · ~32 GB disk · BIOS (SeaBIOS), Q35 or i440fx
NICvirtio · MAC BC:24:11:68:E3:09 on vmbr2 (LAN side)
Static IP192.168.0.20/24 (set during installer · outside DHCP pool .100–.200)
Gateway192.168.0.1 (pfSense2 LAN)
DNS192.168.0.1 (pfSense2 Unbound)
Search domains(empty — set when AD domain is chosen)
StorageUse entire disk + LVM (default)
SSHOpenSSH server installed during setup ✓
SnapsNone (services installed manually for the lab)

Step 5.1 — Detach the install ISO before first reboot

1
Prevent the VM from rebooting back into the installer

While the installer is still running its curtin install phase (or right after, before clicking Reboot Now):

  1. Proxmox UI → click VM 105 (LinuxServer) → left tab Hardware
  2. Find the row CD/DVD Drive (ide2) with the Ubuntu ISO
  3. Double-click → change "ISO image" to Do not use any media → OK

That ensures the next boot goes to scsi0 (the freshly installed disk) instead of looping back into the installer.

Step 5.2 — First-boot login + verification block

2
Sanity-check the install

After reboot, log in at the console with the username/password set during install. Then paste:

echo "=== LINUXSERVER (VM 105) ==="
hostnamectl
echo
echo "--- network ---"
ip -br addr
ip route
resolvectl status | grep -E "DNS Servers|Current DNS|Link "
echo
echo "--- internet test (proves NAT through pfSense2) ---"
ping -c 2 192.168.0.1
ping -c 2 1.1.1.1
ping -c 2 google.com
echo
echo "--- SSH service ---"
sudo systemctl is-active ssh
sudo systemctl is-enabled ssh
sudo ss -tlnp | grep ssh
echo
echo "--- OS version ---"
lsb_release -a 2>/dev/null
uname -r

Expected: 192.168.0.20/24 on ens18, default route via 192.168.0.1, all three pings succeed, sshd active+enabled+listening on :22.

Step 5.3 — SSH from jumpbox (proves cross-subnet routing)

3
The realistic admin workflow

From the jumpbox, SSH to the LinuxServer via its LAN IP:

ssh <your-username>@192.168.0.20

This proves pfSense2's firewall is allowing DMZ (172.16.0.0/24) → LAN (192.168.0.0/24) on port 22. If it fails with "Connection timed out", the issue is pfSense's firewall rules — Firewall → Rules → DMZ — by default pfSense allows DMZ-net traffic out, but if you've tightened the rules, you may need an explicit "DMZ → LAN port 22 ALLOW".

Step 5.4 — Snapshot before installing services

4
Insurance for the rest of Week 2

Before NGINX/MariaDB/syslog/etc., take a Proxmox snapshot so you can roll back cleanly if anything breaks:

  1. Proxmox UI → VM 105 → left tab SnapshotsTake Snapshot
  2. Name: fresh-install
  3. Description: "Ubuntu Server installed, static IP set, SSH up. No services yet."
  4. ✓ Include RAM = unchecked (the VM is in a known stable state, no need)
  5. Click Take Snapshot

Step 5.5 — Service install plan (Week 2 deliverables)

5
Roles per the lab guide
  1. System update firstsudo apt update && sudo apt upgrade -y
  2. NGINXsudo apt install -y nginx · place a custom index.html in /var/www/html/ · test from WinSrv: curl http://192.168.0.20
  3. MariaDBsudo apt install -y mariadb-server · run sudo mysql_secure_installation · create test database capstoneDB
  4. NTP — already handled by systemd-timesyncd on Ubuntu Server; verify with timedatectl. Optional: install chrony if a stricter NTP daemon is required.
  5. rsyslog forwarder (Week 3 prep) — edit /etc/rsyslog.conf to forward to a central collector when one exists
  6. UFWsudo ufw allow 22 · sudo ufw allow 80 · sudo ufw allow 443 · sudo ufw enable (mirrors jumpbox UFW posture)
Don't install AD/Samba on this box — that role belongs on WinSrv. This box is a web/DB/syslog/general Linux services server.

Verified state — LinuxServer (post-install — to be filled)

FieldTarget valueStatus
VMID / Display name105 / LinuxServercreated
OSUbuntu Server (LTS) — confirm version post-installinstalling
Hostname (in OS)To confirm via hostnamectlpending
Interfaceens18 on vmbr2 · MAC BC:24:11:68:E3:09verified
IPv4192.168.0.20/24 static (set in installer)verify post-boot
Gateway192.168.0.1verify post-boot
DNS192.168.0.1verify post-boot
Internet reachabilityping google.com + ping 1.1.1.1verify post-boot
SSH serviceactive + enabled (port 22)verify post-boot
UFWnot yet configured (Step 5.5 #6)to do
Services installedNGINX · MariaDB · NTP (post-snapshot)future

Sibling — VM 104 (Linux-Ubuntu Desktop · client workstation)

VM 104 keeps its Ubuntu Desktop ISO mount and gets installed as a Linux GUI client on the LAN. It's the "user perspective" tester — open Firefox, browse to http://192.168.0.20 (NGINX) and http://192.168.0.15 (IIS once installed) to validate the services from a real desktop session, not just curl. Also good for verifying DNS/DHCP behavior visually.

FieldValue
Statusinstall pending · ISO mounted, never booted yet
NICvirtio · MAC BC:24:11:02:24:2B on vmbr2 (LAN)
ISO mountedubuntu-24.04.4-desktop-amd64.iso (LTS · GNOME desktop)
Target hostnamelinuxdesktop (or your team's preferred name)
Target IP192.168.0.25/24 static · gateway 192.168.0.1 · DNS 192.168.0.1
Gateway / DNS192.168.0.1 (pfSense2 LAN)
Role in labLinux GUI client · web browser tester · DHCP/DNS validation · packet-capture endpoint

Install plan for VM 104

Same procedure as VM 105, with the GUI option
  1. Boot VM 104 (already has the Desktop ISO on ide2)
  2. Walk through the GNOME-style installer · timezone Central · install third-party drivers if prompted
  3. Set hostname (suggest linuxdesktop) · pick admin user · enable login automatically (optional, lab-only)
  4. After install: detach ISO via Hardware tab (same as VM 105 Step 5.1)
  5. Boot · open Settings → Network → Wired → ⚙ → IPv4 tab → Manual · address 192.168.0.25 · netmask 255.255.255.0 · gateway 192.168.0.1 · DNS 192.168.0.1 · Apply
  6. Toggle the switch off+on to apply, then test: open Firefox → http://192.168.0.20 (NGINX welcome page once installed)
  7. Optional: install openssh-server for remote testing — sudo apt install -y openssh-server

Screenshots

📸
Screenshot pending
photos/verification/20-linuxserver-installer-network.png
Capture: Ubuntu Server installer "Network configuration" screen showing ens18 static 192.168.0.20/24, gateway 192.168.0.1, DNS 192.168.0.1 after Save.
Phase 5 · Fig 20VM 105 installer · static network configured
📸
Screenshot pending
photos/verification/21-linuxserver-installing.png
Capture: Ubuntu Server installer "Installing system" screen — curtin partition + LVM + extract steps. Confirms install actually ran.
Phase 5 · Fig 21VM 105 installer · curtin install in progress
LinuxServer (VM 105) terminal output — hostnamectl tctlinuxserver Ubuntu 26.04 LTS kernel 7.0.0-15-generic, ip -br addr ens18 192.168.0.20/24, default via 192.168.0.1 dev ens18 proto static, ssh active and enabled
Phase 5 · Fig 22 ✓VM 105 first-boot verification — hostname tctlinuxserver, Ubuntu 26.04, static 192.168.0.20, gateway via pfSense, sshd active. Captured 2026-05-06.

Verified state — entire build snapshot

One-page reference for status meeting / instructor demo / Week 2 report appendix.

VMIDNameStateRoleOSIPBridgeNotes
tctmachine (host)runningHypervisorPVE 8.2.210.10.10.10/16eno1→vmbr0+ vmbr1 .10/24, vmbr2 .10/24
100PFsensetemplateClone sourcepfSense CE 2.8.1n/avmbr0/1/2template:1 — base disk for VM 103
101jumpboxrunningSSH gateway · DMZ entryUbuntu 26.04 LTS172.16.0.100 (DHCP)vmbr1UFW on, SSH active, internet OK
102WinSrvrunning, fresh OS(future) AD/DNS/DHCP/IISWin Srv 2025 Datacenter Eval (24H2)192.168.0.15 (static)vmbr2Eval expires ~2026-10-24 · TZ Pacific (fix)
103PFsense2runningRouter · DHCP · DNS · firewallpfSense CE 2.8.1WAN 10.10.110.10 · DMZ 172.16.0.1 · LAN 192.168.0.1vmbr0/1/2Default admin password 🚨
104Linux-Ubunturunning · install state TBDLinux GUI client · web/DHCP/DNS testerUbuntu 24.04 LTS Desktop192.168.0.25 (static · planned)vmbr2MAC BC:24:11:02:24:2B · booted 2026-05-06 (per Fig 01)
105LinuxServerrunning, fresh OSNGINX · MariaDB · NTP · Syslog (Week 2)Ubuntu Server 26.04 LTS192.168.0.20 (static)vmbr2MAC BC:24:11:68:E3:09 · hostname tctlinuxserver

Topology lock-in

pfSense2 (VM 103) is the canonical router. It does NAT (Automatic mode), DHCP for both internal subnets, and DNS resolution (Unbound + DNSSEC). The Proxmox host's iptables rules are vestigial. If we later switch to host-iptables NAT (per the new instructor guide), we'll need to (a) remove the broken 10.10.110.10/32 MASQUERADE, (b) add 172.16.0.0/24 + 192.168.0.0/24 MASQUERADE rules, (c) point internal VMs at 172.16.0.10 / 192.168.0.10 as their gateway instead of pfSense2's .1 addresses.

Outstanding tasks (the punch list)

Ordered by urgency. Fix top items before any service work.

🚨 Critical — fix tonight

  1. Change pfSense2 admin password. System → User Manager → admin → set strong password. Default pfsense is exposed on 10.10.0.0/16.

⚠ High — fix this week

  1. Finish VM 105 install + verify — detach ISO, let it reboot, run Step 5.2 verification block, confirm static 192.168.0.20 took effect, take "fresh-install" snapshot.
  2. SSH from jumpbox to VM 105 — proves DMZ → LAN port-22 firewall path works.
  3. Install Week 2 services on VM 105 — NGINX, MariaDB, NTP, UFW (per Phase 5 Step 5.5).
  4. Set WinSrv time zone to Central (Settings → Time & language → Time zone → UTC−06:00). Required for AD/Kerberos.
  5. Move WinSrv to static IP before installing AD-DSDONE 2026-05-05: WinSrv now at 192.168.0.15/24 static.
  6. Run pending Windows Updates on WinSrv. AD-DS promotion fails on certain unpatched builds.
  7. Choose AD domain name (e.g., capstone.local) and update pfSense's system domain (System → General Setup) before promoting WinSrv. Don't reuse home.arpa.
  8. Rename jumpbox hostname from tctmachine to jumpbox (sudo hostnamectl set-hostname jumpbox) to avoid confusion with Proxmox host.
  9. Harden jumpbox SSH per Lab Guide Part 7 step 3: change port, disable root login, disable password auth (after key auth), AllowUsers tct_jumpbox, MaxAuthTries 3.

ℹ Medium — Week 3 cleanup

  1. Install Ubuntu Desktop on VM 104 as the LAN client workstation · static 192.168.0.25 · use Firefox to validate IIS + NGINX from a GUI session.
  2. Decide topology: keep pfSense2-routed (current) or switch to host-iptables (canonical). Document the decision.
  3. Delete or document the broken 10.10.110.10/32 MASQUERADE on the host.
  4. Rename pfSense interface labels from "lan/opt1" to "DMZ/LAN" in Interfaces → Assignments.
  5. Rename pfSense hostname from pfSense.home.arpa to something like pfsense2.capstone.local.
  6. Convert jumpbox + WinSrv from DHCP to static (or DHCP static-mappings) for stability.
  7. Deduplicate net.ipv4.ip_forward=1 in /etc/sysctl.conf and /etc/sysctl.d/99-sysctl.conf (each appears twice).
  8. Plan ISC-DHCP → Kea migration in pfSense (Week 5 doc note).

✓ Done

  1. Hardware discovery + RAID 5 build (Week 1)
  2. Proxmox VE 8.2.2 install on RAID 5
  3. vmbr0/1/2 created with correct IP scheme
  4. 5 VMs created; 3 running stably (jumpbox, WinSrv, pfSense2)
  5. pfSense2 routing/NAT/DHCP/DNS for both internal subnets
  6. Jumpbox UFW configured per Part 7 step 4
  7. Outbound internet from internal subnets verified

Screenshot index

25 screenshots planned for full Week 2 documentation (added 3 for VM 105 build, 2 for the LAN-firewall finding, 1 for IP aliases). 21 captured (Fig 01, 02, 03, 04, 06, 07, 09, 10, 11, 12, 13, 14, 14a, 14b, 14c, 15, 16, 17, 18, 19, 22) · 4 pending. Remaining: Fig 05 (SSH login prompt), Fig 08 (pfSense console main menu), Fig 20–21 (VM 105 installer recaptures, optional), Fig 23–25 (VM 104 once installed).

FigFilenameDescriptionStatus
0101-host-overview.pngHost shell · pveversion + qm list (all 6 VMs)captured
0202-host-vm-configs.pngHost shell · qm config 100 (template) + 101 (jumpbox)captured
0303-host-iptables.pngHost shell · live iptables nat table (MASQUERADE rule)captured
0404-jumpbox-arp.pngHost shell · ip neigh show dev vmbr1captured
0505-jumpbox-ssh-prompt.pngSSH from host → jumpbox promptpending
0606-jumpbox-internet-test.pngJumpbox · ping google.com + 1.1.1.1captured
0707-jumpbox-network-and-ufw.pngJumpbox · hostnamectl + ip + ping successcaptured
0808-pfsense-console-menu.pngpfSense2 console main menu (interface IPs)pending
0909-pfsense-dashboard.pngpfSense2 web UI · Status → Dashboardcaptured
1010-pfsense-dhcp-dmz.pngpfSense2 · DHCP Server DMZ tabcaptured
1111-pfsense-dhcp-lan.pngpfSense2 · DHCP Server LAN tabcaptured
1212-pfsense-dns-resolver.pngpfSense2 · DNS Resolver General Settingscaptured
1313-pfsense-nat-outbound.pngpfSense2 · Firewall → NAT → Outbound (+ password warning)captured
1414-pfsense-dhcp-leases.pngpfSense2 · Status → DHCP Leases (active leases)captured
14a14a-pfsense-rules-lan.pngpfSense2 · Firewall → Rules → LAN (9-rule hardened set)captured
14b14b-pfsense-alias-outbound-web.pngpfSense2 · OUTBOUND_WEB alias = {80, 443, 53, 123}captured
14c14c-pfsense-aliases-ip.pngpfSense2 · IP aliases (DMZ_NET, LAN_NET, RFC1918, host aliases)captured
1515-winsrv-server-manager.pngWinSrv · Server Manager Local Servercaptured
1616-winsrv-ipconfig.pngWinSrv · ipconfig /all output (static .15 verified)captured
1717-winsrv-about.pngWinSrv · Settings → System → Aboutcaptured
1818-winsrv-roles-pt1.pngWinSrv · Roles and Features (1/2)captured
1919-winsrv-roles-pt2.pngWinSrv · Roles and Features (2/2)captured
2020-linuxserver-installer-network.pngVM 105 installer · static network configuredpending
2121-linuxserver-installing.pngVM 105 installer · curtin install in progresspending
2222-linuxserver-firstboot-verify.pngVM 105 first-boot network + service verificationcaptured
How macOS handles screenshots: when you press Cmd+Shift+4 to capture a region, the file is staged in /var/folders/.../TemporaryItems/ first, then dropped on the Desktop. If you drag the floating thumbnail directly into Claude before it lands on Desktop, the file is never saved — that's why most of our originals are gone. To make sure files persist: let the thumbnail settle, then drag from the Desktop file (or use Cmd+Shift+5 → Options → "Save to: Desktop").