Windows DNS/DHCP/IIS + Linux NGINX/MariaDB on a segmented, NAT-bridged network.
Verify network
Windows services
Linux services
Cross-VM tests
Foundation from Week 1: ML350p Gen8 · Proxmox VE 8.2.2 live at https://10.10.10.10:8006
Verification snapshot 2026-05-05 → week2-verification.html
tctmachine · vmbr0/1/2 all UP192.168.0.15 ✓192.168.0.20 · SSH up⚠ DHCP coordination: pfSense2 currently serves DHCP for 192.168.0.0/24 (pool .100–.200). Before activating Windows DHCP, either (a) disable pfSense LAN DHCP, or (b) split the pool so the two don't overlap. Don't run two DHCP servers on the same broadcast domain.
Prove the internal network works via the NAT bridge and Jump Box, then stand up the core services both teams depend on downstream.
By Friday, any VM should be able to:
winserver.teamx.local via your own DNScapstone_db from CLI| Zone | CIDR | Gateway |
|---|---|---|
| School LAN | 10.10.0.0/16 | 10.10.10.1 |
| DMZ (vmbr1) | 172.16.0.0/24 | 172.16.0.1 (pfSense) |
| LAN (vmbr2) | 192.168.0.0/24 | 192.168.0.1 (pfSense) |
pfSense2 (VM 103) sits on all three bridges: WAN 10.10.110.10, DMZ .1, LAN .1. It does NAT, DHCP, and DNS resolution (Unbound + DNSSEC).
| VM | IP | Role |
|---|---|---|
| WinSrv (102) | 192.168.0.15 static | DNS · DHCP · IIS · AD |
| LinuxServer (105) | 192.168.0.20 static | NGINX · MariaDB |
| Jumpbox (101) | 172.16.0.100 DHCP | SSH gateway · DMZ |
| pfSense LAN DHCP scope | 192.168.0.100 – 192.168.0.200 | |
| pfSense DMZ DHCP scope | 172.16.0.100 – 172.16.0.200 | |
⚠ Statics .2–.99 and .201–.254 are safe — outside the DHCP pool.
192.168.0.15192.168.0.20Every step has a paired live capture from the running build (2026-05-06 verification pass). The next 7 slides walk through each step with the matching screenshot beside it.
For full step-by-step procedure with all 21 screenshots zoomable: week2-verification.html
/etc/network/interfaces# SSH or web shell to the host: ssh root@10.10.10.10 nano /etc/network/interfaces # add these blocks (after 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 # reload networking: ifreload -a ip -br addr
Both bridges are bridge_ports none — they're VM-only switches, no physical NIC backing.
Fig 01 · qm list + pveversion · all 6 VMs accounted for after build
PFsense2 (VMID 103) · 2 vCPU · 2 GB RAM · 20 GB disknet0 → vmbr0 (WAN side)net1 → vmbr1 (DMZ)net2 → vmbr2 (LAN)netgate-installer-v1.1.1-RELEASE-amd64.iso on ide2After install, at the blue menu: option 2 → Set interface(s) IP address WAN vtnet0 → DHCP from school LAN DMZ vtnet1 → 172.16.0.1/24 LAN vtnet2 → 192.168.0.1/24
Fig 09 · pfSense dashboard · WAN 10.10.110.10 · DMZ .1 · LAN .1
172.16.0.100 – 172.16.0.200172.16.0.1 (pfSense)192.168.0.100 – 192.168.0.200, DNS 192.168.0.1Mode: Automatic outbound NAT — pfSense auto-MASQUERADEs both internal subnets out the WAN address.
Fig 10 + 11 · DMZ + LAN scopes (172.16/24 and 192.168/24, both .100–.200)
Fig 12 + 13 · DNS Resolver (DNSSEC on) + NAT Outbound (Automatic mode)
Order matters. Top-down, first match wins. Add rules in this exact order:
| # | Action | Source → Dest | Description |
|---|---|---|---|
| 1 | PASS | LAN → This Firewall (ICMP) | Ping gateway only |
| 2 | PASS | LAN → This Firewall (UDP/123) | NTP local |
| 3 | PASS | LAN → This Firewall (UDP/53) | DNS local |
| 4 | BLOCK | LAN → This Firewall (any) | No mgmt |
| 5 | BLOCK | LAN → DMZ_NET | No DMZ pivot |
| 6 | BLOCK | LAN → RFC1918 | No lateral |
| 7 | PASS | LAN → OUTBOUND_WEB | Web/DNS/NTP only |
| 8 | PASS | LAN → 5985–5986 | WinRM |
| 9 | PASS | LAN → 445 | SMB |
Aliases needed: OUTBOUND_WEB = ports {80, 443, 53, 123} · RFC1918 = standard 10/8 + 172.16/12 + 192.168/16 · DMZ_NET = 172.16.0.0/24.
Fig 14a · LAN ruleset · all 9 rules in order
Fig 14b · OUTBOUND_WEB = {80, 443, 53, 123}
jumpbox) · admin user tct_jumpboxsudo 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 192.168.0.0/24 to any port 22 sudo ufw allow from 172.16.0.0/24 to any port 22 sudo ufw enable sudo ufw status verbose
Edit /etc/ssh/sshd_config · change Port 2222 · PermitRootLogin no · PasswordAuthentication no after key auth · AllowUsers tct_jumpbox
Fig 06 · ping google.com + 1.1.1.1 · 0% loss
Fig 07 · hostnamectl + ip + UFW status
.15e1000 on vmbr2 · ✓ Proxmox firewallWin + R → ncpa.cpl → Network Connections192.168.0.15255.255.255.0192.168.0.1192.168.0.1
Fig 16 · ipconfig /all · IPv4 192.168.0.15(Preferred) · DHCP No
Fig 17 · Settings · Win Srv 2025 Eval · 24H2 · installed 4/27/2026
.20ens18 IPv4 → Manual:
192.168.0.0/24192.168.0.20192.168.0.1192.168.0.1linuxserver · admin user · passwordProxmox UI → VM 105 → Hardware → CD/DVD Drive → Edit → "Do not use any media" → OK. Otherwise the VM loops back into the installer.
sudo systemctl enable ssh # confirm static .20 took effect: ip -br addr ping -c 2 192.168.0.1
Fig 22 · hostnamectl tctlinuxserver · Ubuntu 26.04 · static 192.168.0.20 · sshd active
192.168.0.15 · DHCP No · DNS pfSense192.168.0.20 · sshd active.25 · Firefox client testingpfsense)The next slides walk through the service installs, in order.
| From → To | Record |
|---|---|
| Proxmox host → pfSense2 (DMZ) | ______ ms |
| Proxmox host → Jumpbox (DMZ) | ______ ms |
| Proxmox host → WinSrv (LAN) | ______ ms |
| Proxmox host → LinuxServer (LAN) | ______ ms |
# from the Proxmox host shell: ping -c 4 172.16.0.1 # pfSense DMZ ping -c 4 172.16.0.100 # Jumpbox ping -c 4 192.168.0.15 # WinSrv ping -c 4 192.168.0.20 # LinuxServer
From WinSrv cmd:
curl -v -m 5 https://www.microsoft.com expect HTTP 200 in <1 s
From LinuxServer bash:
curl -s https://ifconfig.me → returns the school's public IP
If outbound fails: check VM gateway = 192.168.0.1 (pfSense LAN), pfSense's Firewall → NAT → Outbound shows Mode = Automatic, and the LAN allow rule at Firewall → Rules → LAN permits the destination port.
⚠ ping 1.1.1.1 from LAN won't reach the internet — by design, the LAN firewall only allows ICMP echoreq to the gateway. Use curl against an OUTBOUND_WEB-listed port (80/443/53/123) instead.
| VM | Gateway | VM IP | DNS Server | Working? (Y/N) |
|---|---|---|---|---|
| WinSrv (LAN) | 192.168.0.1 | 192.168.0.15 | 192.168.0.1 (pfSense) | ___ |
| LinuxServer (LAN) | 192.168.0.1 | 192.168.0.20 | 192.168.0.1 (pfSense) | ___ |
| Jumpbox (DMZ) | 172.16.0.1 | 172.16.0.100 | 172.16.0.1 (pfSense) | ___ |
ipconfig /all look for: Default Gateway . . : 192.168.0.1 DNS Servers . . . . : 192.168.0.1
ip route | grep default default via 192.168.0.1 dev ens18 resolvectl status | grep "DNS Servers" DNS Servers: 192.168.0.1
📸 Screenshot ipconfig /all and ip route + resolv.conf for the report.
teamx.local (replace x with your team letter/number)winserver192.168.0.15nslookup winserver.teamx.local Server: localhost Address: 127.0.0.1 Name: winserver.teamx.local Address: 192.168.0.15
📸 Screenshot the DNS Manager tree showing the zone + A record, and the nslookup output.
⚠ Two DHCPs would fight. pfSense2 currently leases .100–.200 on the LAN. Before activating Windows DHCP, go to pfSense → Services → DHCP Server → LAN → uncheck "Enable DHCP server on LAN" + Save + Apply. Then Windows owns the scope.
| Name | CapstoneScope |
| Start IP | 192.168.0.100 |
| End IP | 192.168.0.200 |
| Subnet Mask | 255.255.255.0 |
| Default Gateway | 192.168.0.1 |
| DNS Server | 192.168.0.15 WinSrv (your DNS) |
| DNS suffix | teamx.local |
| Lease duration | 8 days (default) |
.10–.100Windows client: ipconfig /release ipconfig /renew ipconfig /all Linux client: sudo dhclient -r && sudo dhclient ip -4 addr
📸 Screenshot the DHCP Manager scope + Address Leases panel showing at least 1 active lease.
C:\inetpub\wwwroot\iisstart.htm + iisstart.pngindex.html<html>
<body>
<h1>Welcome to Week 2!</h1>
</body>
</html>
Browser: http://192.168.0.15 Or by hostname (DNS working): http://winserver.teamx.local
You should see Welcome to Week 2! rendered as an H1.
📸 Screenshot the browser showing the welcome page — URL bar visible.
sudo apt update sudo apt install nginx -y sudo systemctl enable nginx sudo systemctl start nginx sudo systemctl status nginx ● nginx.service - A high performance web server Active: active (running)
echo "<h1>Welcome to Linux Week 2</h1>" \ | sudo tee /var/www/html/index.html # confirm file: cat /var/www/html/index.html <h1>Welcome to Linux Week 2</h1>
Browser on Windows / Jump Box: http://192.168.0.20
📸 Screenshot the browser with URL + rendered heading.
If it fails, check: sudo ufw status (allow port 80 if firewall up), NIC IP is actually .3, and gateway is .1.
sudo apt install mariadb-server -y sudo systemctl enable mariadb sudo systemctl start mariadb sudo mysql MariaDB [(none)]>
Optional but recommended: sudo mysql_secure_installation — set root password, remove anon users & test DB.
CREATE DATABASE capstone_db;
CREATE USER 'capuser'@'localhost'
IDENTIFIED BY 'securepass';
GRANT ALL PRIVILEGES ON capstone_db.*
TO 'capuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
mysql -u capuser -p -e "SHOW DATABASES;" password: securepass +--------------------+ | Database | +--------------------+ | capstone_db | | information_schema | +--------------------+
📸 Screenshot the SHOW DATABASES; output with capstone_db listed.
| From → To | Latency |
|---|---|
| Win → Linux | ___ ms |
| Linux → Win | ___ ms |
Win cmd: ping 192.168.0.20 Linux bash: ping -c 4 192.168.0.15
Linux terminal: nslookup winserver.teamx.local Server: 192.168.0.15 Address: 192.168.0.15#53 Name: winserver.teamx.local Address: 192.168.0.15
If this fails but ping 192.168.0.15 works, the client is still pointed at pfSense (192.168.0.1) for DNS — switch its DNS to the WinSrv address (192.168.0.15) so it queries your zone, then re-test.
Spin up a fresh Windows 10/Kali/Ubuntu VM on vmbr1 → set NIC to DHCP.
Record the leased IP: ipconfig /all | findstr IPv4 IPv4 Address . . . . : 192.168.0.101
📸 Screenshot the DHCP Address Leases on the Windows server showing the client's MAC & IP.
| Test | Expected | Actual | Pass / Fail | Screenshot |
|---|---|---|---|---|
| Ping Proxmox host → Jump Box | < 5 ms | ___ ms | ☐ | ☐ |
| Ping Jump Box → Win VM | < 5 ms | ___ ms | ☐ | ☐ |
| Ping Jump Box → Linux VM | < 5 ms | ___ ms | ☐ | ☐ |
| Win VM ping 8.8.8.8 | < 30 ms | ___ ms | ☐ | ☐ |
Linux VM curl ifconfig.me | School public IP | _________ | ☐ | ☐ |
nslookup winserver.teamx.local | 192.168.0.15 | _________ | ☐ | ☐ |
| DHCP lease issued to client | IP in .10–.100 range | _________ | ☐ | ☐ |
Browse http://192.168.0.15 | "Welcome to Week 2!" | rendered Y/N | ☐ | ☐ |
Browse http://192.168.0.20 | "Welcome to Linux Week 2" | rendered Y/N | ☐ | ☐ |
SHOW DATABASES; via capuser | capstone_db listed | _________ | ☐ | ☐ |
SHOW DATABASES; showing capstone_dbvmbr1)?ufw up? → sudo ufw allow from 192.168.0.0/24192.168.0.x IP? (ipconfig/ip a)sysctl net.ipv4.ip_forward should say 1iptables -t nat -L POSTROUTING -n -v192.168.0.1?8.8.8.8 pingable from host)?192.168.0.15 (your Win server)?winserver.teamx.local not just winserver?services.msc or systemctl status)telnet <ip> 80 to confirm listening'capuser'@'localhost'? Remote clients need 'capuser'@'%'FLUSH PRIVILEGES; after GRANT?securepass)?/etc/mysql/mariadb.conf.d/50-server.cnfPhase 0 → 1 → 2 → 3 · screenshot everything · fill the tables
Questions? Back to the retrospective or main guide.