Cherwood Health is the operating scenario for a hands-on network engineering and security build — physical FortiGate and Cisco hardware, no simulator, every bug documented as it actually happened.
Every row below was built, then tested with real traffic, real logs, or a real deliberately-induced failure — not assumed to work because the config looked right.
4 VLANs — Trusted, Guest, Servers, DMZ — each with explicit, logged firewall policy, not just implicit default-deny. Guest→Trusted isolation proven with real log evidence.
SSL-VPN on a non-default port, dynamic DNS via DuckDNS, tested end-to-end from real cellular data — including a 5-cause bug chain to get there.
A physically separate branch office, dynamically routed back to HQ over RIPv2, isolated from internal VLANs by policy, internet-only.
Prometheus + Grafana, SNMP polling of every core device, live dashboards — with a documented, honestly-labeled limitation on containerized memory accounting.
Bash + cron nightly diffing config backups on all three core devices, plus a config-drift isolation checker validated against a deliberately broken policy.
A real reconnaissance simulation from the DMZ, confirmed blocked using a live FortiGate packet sniffer when standard log views came up empty.
Every part, in the order it was actually built. Full command-by-command detail lives in the repo's COMMAND-REFERENCE.md.
tarunc.com registered, nameservers moved to Cloudflare. Cherwood Corporation established as a parent brand, Cherwood Health as its first division.
FortiGate, switch, AP cabled. Admin GUI secured, internal1/internal2 split out of the default hardware switch.
VLAN 10/20/30 on the FortiGate; matching VLANs and trunk ports on the 3560E. Diagnosed a native-VLAN mismatch and a trunk-list-vs-VLAN-database gotcha.
Staff and Guest SSIDs mapped to VLANs 10/20. Hit a hard vendor limit — one guest-mode slot per radio — split across both radio bands.
Explicit ACCEPT/DENY per zone. Guest captive portal live. Isolation proven with a real blocked-traffic log entry before touching production.
Production Proxmox host moved onto the segmented network. DMZ stood up serving cherwood.tarunc.com via Cloudflare Tunnel — zero open inbound ports.
A five-cause bug chain — cipher self-conflict, an unsaved port forward, a missing policy, a client-side VPN conflict — before a clean external connection.
A second physical site, dynamically routed back to HQ. Planned AP hardware turned out to be Lightweight firmware with unrecoverable credentials — substituted honestly.
SNMP polling of the firewall, switch, and branch router every 15 seconds. Live dashboards for interface throughput and host metrics.
Nightly SSH config pulls with diffing. A custom isolation-check script, validated by deliberately disabling a real policy and confirming it got caught.
A real reconnaissance attempt from DMZ into Trusted. Standard logs showed nothing — resolved with a live packet capture proving traffic was silently denied.
A shared 10 Mbps cap on Guest traffic, deprioritized under contention, verified via CLI against the saved config.
Design rationale, every command used, every real bug with root cause and fix — documented honestly rather than cleaned up.
Real device configs pulled and sanitized for all four devices, working scripts, a full screenshot set — audited before publishing.
The full record — every bug, every root cause — lives in TROUBLESHOOTING-LOG.md. Four representative ones below.
SSL-VPN failed with a generic "SSL exit error." show full-configuration revealed the firewall had banned SHA256/SHA384 while its own cipher suite required them — zero valid ciphers left.
Fix: selectively un-banned the two hashes actually needed, left SHA1 excluded.
Every server-side fix still failed. The dominant cause: Tailscale on the test phone, competing with FortiClient for the device's VPN routing.
Fix: disabled the competing client. Immediate, clean connection.
The isolation-checker passed every test — until validated against a real, intentionally-disabled policy. It missed it. The field that mattered was written before the anchor point it searched from.
Fix: rewrote to parse whole policy blocks, re-tested against the same real fault, confirmed caught.
A real port scan from DMZ into Trusted was blocked — but produced zero entries in Forward Traffic, Local Traffic, or Security Events.
Fix: diagnose sniffer packet on the FortiGate CLI proved packets arrived and were silently denied — a logging distinction the GUI never surfaces.
Full rationale for every design decision lives in ARCHITECTURE.md, including an honest section on what would change for real production use.
| Segment | Subnet | Gateway | Purpose |
|---|---|---|---|
| VLAN 10 — Trusted | 10.10.10.0/24 | 10.10.10.1 | Staff devices, network admin access |
| VLAN 20 — Guest | 10.10.20.0/24 | 10.10.20.1 | Public WiFi — isolated, bandwidth-capped |
| VLAN 30 — Servers | 10.10.30.0/24 | 10.10.30.1 | Proxmox host, all internal service containers |
| VLAN 40 — DMZ | 10.10.40.0/24 | 10.10.40.1 | Public-facing services only, fully isolated |
| Branch transit link | 10.10.99.0/30 | FG: .1 · 1921: .2 | Point-to-point HQ↔Branch routing |
| Branch LAN | 10.20.0.0/24 | 10.20.0.1 | Branch office local network, internet-only |
The complete repo includes a command-by-command reference, the full troubleshooting log, and an interview-ready walkthrough of every design decision.