MFranklin LLC
December 2024

mfsecurities.org - Defense in Depth Architecture

Cloudflare Pages DNS Configuration GitHub CI/CD DevOps Security Strategy

The Challenge

As a cybersecurity professional building a personal brand and business presence, I faced a critical architectural decision: should my business services, personal portfolio, mentorship platform, and professional network all live under a single domain?

The answer was clear — no. In cybersecurity, we preach defense in depth. It was time to practice what I teach.

Why Domain Separation Matters

  • Attack Surface Isolation: A vulnerability in one site shouldn't compromise the other
  • Credential Separation: Different origins prevent session and cookie sharing across domains
  • Infrastructure Independence: Updates, deployments, and configurations remain isolated
  • Professional Compartmentalization: Business services separate from personal mentorship content
  • Deployment Risk Management: Experimental changes to personal site won't affect business operations
Core Principle: In security architecture, assume breach. When (not if) one asset is compromised, the blast radius should be minimized.

The Solution

I architected a dual-domain strategy leveraging modern DevOps tooling and cloud infrastructure:

Architecture Overview

  • mfranklin.org: Personal portfolio, mentorship, career content, community building
  • mfsecurities.org: Business cybersecurity services, client-facing offerings, professional consulting
  • Hosting Platform: Cloudflare Pages for both domains (separate projects)
  • Version Control: Separate GitHub repositories for complete isolation
  • Deployment Pipeline: GitHub Actions → Cloudflare Pages automatic deployments
  • Security Headers: CSP, X-Frame-Options, X-Content-Type-Options configured via _headers file

Technology Stack

  • Static HTML/CSS (no build process required)
  • Cloudflare Pages for hosting and CDN
  • Cloudflare DNS for domain management
  • GitHub for version control and CI/CD trigger
  • Custom security headers for hardening

Implementation Journey

What seemed straightforward on paper became a masterclass in reading documentation and troubleshooting deployment pipelines.

Step 1: Repository Setup

Created a completely separate repository for the business site to ensure infrastructure isolation:

# Create new repository directory mkdir -p /home/mfranklin/mfsecurities-website cd /home/mfranklin/mfsecurities-website # Initialize git git init git branch -m main # Create GitHub repository gh repo create mfsecurities-website --public --source=. --remote=origin # Initial commit and push git add . git commit -m "Initial commit: Business services site" git push -u origin main

Step 2: Cloudflare Pages Deployment (First Attempt - Failed)

My first deployment attempt hit a critical error. I had unknowingly created a Cloudflare Worker project instead of a Pages project.

Critical Learning: Cloudflare Workers and Cloudflare Pages are fundamentally different products. Workers require entry points and build processes; Pages is designed for static sites.

The error message was unmistakable:

✘ [ERROR] Missing entry-point to Worker script or to assets directory Your configuration file must have either a 'main' field, which points to the Worker script, or an 'assets.directory' field.

Step 3: Cloudflare Pages Deployment (Second Attempt - Success)

I deleted the Worker project and recreated it as a Pages project with these exact settings:

  • Project Type: Pages (not Workers)
  • Connection Method: Connect to Git (selected GitHub repository)
  • Framework Preset: None
  • Build Command: (left completely empty)
  • Build Output Directory: /
  • Branch: main
Key Insight: For pure static HTML/CSS sites, no build command is required. Cloudflare Pages serves files directly from the repository root.

Step 4: DNS Configuration

With the site deployed successfully to mfsecurities.pages.dev, I configured custom domain DNS:

# Cloudflare DNS Settings Type: CNAME Name: mfsecurities.org Target: mfsecurities.pages.dev Proxy Status: Proxied (orange cloud) # SSL/TLS Certificate Mode: Full (strict) Provisioning: Automatic (5-30 minutes)

Step 5: Security Headers Configuration

Created a _headers file to enforce security policies:

/* X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: geolocation=(), microphone=(), camera=() Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'

Step 6: Cross-Site Navigation

Updated both sites to link to each other with proper security attributes:

<!-- On mfranklin.org --> <li> <a href="https://mfsecurities.org" target="_blank" rel="noopener noreferrer"> Business Services </a> </li> <!-- On mfsecurities.org --> <a href="https://mfranklin.org" target="_blank" rel="noopener noreferrer"> <img src="images/2mfranklin,llc.png" alt="MFranklin LLC"> </a>

Lessons Learned

1. Workers vs Pages: Know the Difference

Cloudflare Workers are for serverless functions and edge computing. Cloudflare Pages is for static site hosting with automatic deployments. Choosing the wrong product wastes time and creates confusion.

2. Documentation During Implementation, Not After

Writing this case study while implementing (rather than weeks later) captured authentic troubleshooting steps, error messages, and decision points that would have been forgotten.

3. DNS Propagation Requires Patience

SSL certificate provisioning and DNS propagation can take 5-30 minutes. Testing immediately after configuration often leads to false negatives. Give the infrastructure time to settle.

4. Branch Naming Conventions Matter

Modern platforms default to main, not master. Mismatched branch names between repository and deployment settings cause silent failures.

5. Defense in Depth Is More Than Theory

Implementing domain separation isn't just a security best practice — it's a forcing function for better architecture. Separate repositories, isolated credentials, independent deployments, and compartmentalized risk all emerged naturally from the decision to separate domains.

Final Thought: The best security architectures are the ones you can explain in a blog post. If you can't articulate why you made a decision, you probably haven't thought it through.
Copied to clipboard!