Division 01 — Cherwood Health — Live Build

A segmented enterprise network, built on real hardware, tested against real attacks.

Cherwood Health is a fictional regional clinic group used as the operating scenario for a hands-on network engineering and security portfolio project — physical Fortinet and Cisco gear, no simulator, every bug documented as it actually happened.

4Segmented VLANs
2Sites (HQ + Branch, RIP-routed)
21/21Build parts complete
0Inbound ports besides VPN

Live network topology

Trusted Guest Servers DMZ Branch
Internet wan1 FortiGate 60E 10.10.x.1 / core Cisco 3560E Trunk: 10,20,30,40 VLAN10 · Trusted Staff AP · 10.10.10.0/24 VLAN20 · Guest Portal + 10Mbps cap VLAN30 · Servers Proxmox · Prometheus · Grafana VLAN40 · DMZ cherwood-dmz container Cloudflare Tunnel (outbound only) Cisco 1921 (Branch) RIPv2 · 10.10.99.0/30 Branch LAN 10.20.0.0/24 · internet-only Remote Client SSL-VPN :10443
What this proves

Not just configured — monitored, automated, and attacked on purpose.

Every layer below was built, then verified with real traffic, real logs, or a real deliberately-induced failure — not assumed to work because the config looked right.

Segmentation 4 VLANs

Trusted, Guest, Servers, and DMZ — each with explicit, logged firewall policy, not just implicit default-deny. Guest→Trusted isolation proven with real log evidence.

Remote access SSL-VPN

Non-default port, dynamic DNS via DuckDNS, tested end-to-end from real cellular data — including a 5-cause bug chain to get there.

Site-to-site routing RIPv2

A physically separate branch office, dynamically routed back to HQ, isolated from internal VLANs by policy, internet-only.

Monitoring Prometheus + Grafana

SNMP polling of every core device, live dashboards, host metrics — with a documented, honestly-labeled limitation on containerized memory accounting.

Automation Bash + cron

Nightly diffing config backups on all three core devices, plus a config-drift isolation checker — validated by deliberately breaking a real policy and confirming it got caught.

Detection Packet capture

A real reconnaissance simulation from the DMZ, confirmed blocked using a live FortiGate packet sniffer when standard log views came up empty.

Chronological record

Build log

Every part, in the order it was actually built. Full command-by-command detail lives in the repo's COMMAND-REFERENCE.md.

PART 00Foundation

Domain, DNS & brand structure

tarunc.com registered, nameservers moved to Cloudflare. Cherwood Corporation established as a parent holding brand, with Cherwood Health as its first division — reusable for future homelab projects.

Done
PART 01–03Foundation

Physical wiring & FortiGate admin access

FortiGate, switch, AP all cabled. Admin GUI secured, internal1/internal2 split out of the default hardware switch to become independently configurable.

Done
PART 04–05Segmentation

VLANs on the firewall & switch

VLAN 10/20/30 created on the FortiGate; matching VLANs and trunk ports configured on the 3560E. Diagnosed a native-VLAN mismatch and a "trunk allowed list ≠ VLAN database entry" gotcha along the way.

Done
PART 06Wireless

Dual-SSID wireless on Autonomous Cisco APs

Staff and Guest SSIDs mapped to VLANs 10/20. Hit a hard vendor limit — one guest-mode slot per radio — and split the SSIDs across both radio bands to resolve it.

Done
PART 07–09Enforcement

Firewall policy, captive portal, full segmentation testing

Explicit ACCEPT and DENY policies for every zone. Guest captive portal live. Isolation proven — not assumed — with a real blocked-traffic log entry before touching any production system.

Done
PART 10Production

Live migration + public DMZ site

Production Proxmox host and its Kindle/RSS pipeline moved onto the segmented network. DMZ stood up serving cherwood.tarunc.com via Cloudflare Tunnel — zero open inbound ports for the public site.

Done
PART 11Remote Access

SSL-VPN, tested from real cellular data

A five-cause bug chain — cipher self-conflict, a silently-unsaved port forward, a missing firewall policy, and a client-side VPN client conflict — before a clean connection from outside the network.

Done
PART 12–13Site-to-site

Branch office, routed over RIPv2

A second physical site, dynamically routed back to HQ, isolated by policy the same way Guest is. Planned AP hardware turned out to be Lightweight firmware with unrecoverable credentials — documented and substituted honestly.

Done
PART 14Observability

Prometheus + Grafana monitoring

SNMP polling of the firewall, switch, and branch router every 15 seconds. Live dashboards for interface throughput and host metrics.

Done
PART 15–16Automation

Config backups & drift detection

Nightly SSH-based config pulls with diffing on all three core devices. A custom isolation-check script, validated by deliberately disabling a real firewall policy and confirming the script caught it.

Done
PART 17Validation

Simulated attack & detection

A real reconnaissance attempt from the DMZ against the Trusted VLAN. Standard logs showed nothing — resolved with a live packet capture proving the traffic was actually being silently denied.

Done
PART 18Hardening

Guest bandwidth shaping

A shared 10 Mbps cap on Guest traffic, deprioritized under contention, verified via CLI against the saved config.

Done
PART 19–20Documentation

Architecture, command reference & troubleshooting log

Full write-up of the design rationale, every command used across the build, and every real bug encountered with its root cause and fix — documented honestly rather than cleaned up to look flawless.

Done
PART 21GitHub Packaging

Sanitized configs, scripts & repo publication

Real device configs pulled and sanitized for all four network devices, working automation scripts, and a full screenshot set — audited for accidental credential or key exposure before publishing.

Done
The real work

A few incidents, in brief

The full record — every bug, every root cause — lives in TROUBLESHOOTING-LOG.md. Four representative ones below.

Part 11 · SSL-VPN

A cipher list that banned its own requirements

SSL-VPN failed with a generic "SSL exit error," visible in no abbreviated config view. show full-configuration revealed the firewall had banned SHA256/SHA384 while its own configured cipher suite required them — zero valid ciphers left to negotiate.

Fix: selectively un-banned the two hashes actually needed, leaving the genuinely weak SHA1 excluded.

Part 11 · Client-side

The firewall wasn't the problem — a VPN client was

After every server-side fix, connections still failed. The actual dominant cause: Tailscale running on the test phone, competing with FortiClient for the device's own VPN routing.

Fix: disabled the competing client. Immediate, clean connection.

Part 15/16 · Automation

A drift-detection script that couldn't detect drift

The isolation-checker passed every test — until deliberately validated against a real, intentionally-disabled policy. It missed it. The field that mattered was written before the anchor point the script searched from.

Fix: rewrote to parse whole policy blocks, re-tested against the same real fault, confirmed caught.

Part 17 · Detection

Silence in the logs isn't proof of nothing happening

A real port scan from DMZ into Trusted was clearly blocked — but produced zero entries in Forward Traffic, Local Traffic, or Security Events.

Fix: diagnose sniffer packet directly on the FortiGate CLI proved packets were arriving and being silently denied — a logging-category distinction the GUI never surfaces.

Design reference

Addressing scheme

Full rationale for every design decision lives in ARCHITECTURE.md, including an honest section on what would change for real production use.

SegmentSubnetGatewayPurpose
VLAN 10 — Trusted10.10.10.0/2410.10.10.1Staff devices, network admin access
VLAN 20 — Guest10.10.20.0/2410.10.20.1Public WiFi — isolated, bandwidth-capped
VLAN 30 — Servers10.10.30.0/2410.10.30.1Proxmox host, all internal service containers
VLAN 40 — DMZ10.10.40.0/2410.10.40.1Public-facing services only, fully isolated
Branch transit link10.10.99.0/30FG: .1 · 1921: .2Point-to-point HQ↔Branch routing
Branch LAN10.20.0.0/2410.20.0.1Branch office local network, internet-only
Tooling

The stack

FortiGate 60E Cisco Catalyst 3560E Cisco 1921 ISR Cisco Autonomous APs Proxmox VE Debian LXC Prometheus Grafana SNMP Exporter Node Exporter Bash + cron Cloudflare Tunnel SSL-VPN / FortiClient RIPv2

Full documentation, every command, every bug.

The complete repo includes a command-by-command reference, the full troubleshooting log, and an interview-ready walkthrough of every design decision.