Building The Queen's Fleet Hub: Multi-Destination Site Orchestration via CloudFront and Automated Infrastructure

What Was Done

In a single session, we registered a new apex domain (thequeensfleet.com), provisioned TLS infrastructure, deployed a dynamic hub that routes to 16 existing destination sites, and connected the entire architecture through DNS aliasing and CloudFront distributions. This replaced a fragmented set of queenof[city].com sites with a unified entry point while preserving all downstream site independence.

Domain Registration & TLS

Domain acquisition was handled via the Namecheap API from a Lightsail bastion box rather than the browser, automating contact validation and avoiding credential leakage into session logs. The domain was registered with existing organizational contacts in our Namecheap account.

After registration, we immediately requested an ACM certificate for thequeensfleet.com in the us-east-1 region (required for CloudFront origin certificates). Validation used CNAME records written directly to Namecheap DNS via API, avoiding manual DNS panel access. The certificate was ready within minutes.

Hub Infrastructure & Deployment

The hub itself is a static HTML page served from CloudFront with S3 origin. The page contains:

  • A hero section with copy pulled from the site registry
  • 16 destination cards, each rendering as a link to queenof[city].com
  • Card images served from the qos-city-sites S3 bucket at path /{city}/0.jpg

The hub builder lives at /Users/cb/icloud-repos/sites/queenof-cities/build/build_hub.py and regenerates the page from the site registry each deployment. Registry data is housed in a separate Python dict imported at build time, avoiding database calls at request time.

The page was deployed to a new CloudFront distribution with origin pointing to https://qos-city-sites.s3.us-west-2.amazonaws.com. The distribution was assigned alias thequeensfleet.com (and www.thequeensfleet.com for HTTPS redirect compatibility).

DNS & Host Routing

Route53 A and AAAA records for thequeensfleet.com and www.thequeensfleet.com alias directly to the CloudFront distribution. This gives us apex-level HTTPS without a separate www subdomain.

Downstream, the 16 city sites (thepacific.com, theatlantic.com, mazatlan.com, etc.) are served by a single CloudFront distribution (ID: E176JRMB92GPAJ) using host-based routing. A CloudFront function (deployed to viewer-request) reads the Host header and rewrites the origin request path to /{city}/index.html, pulling content from the S3 bucket. This eliminates the need for 16 separate distributions while keeping cache keys per-host.

Infrastructure Details

S3 Bucket: qos-city-sites (us-west-2), contains:

  • /{city}/index.html — each destination site (16 total)
  • /{city}/assets/ — per-site static assets
  • /{city}/0.jpg — card image shown on hub

CloudFront Distributions:

  • New distribution for thequeensfleet.com hub (separate from city routing)
  • E176JRMB92GPAJ for city sites, configured with:
    • CloudFront function at viewer-request that rewrites paths based on host header
    • Origin pointing to qos-city-sites.s3.us-west-2.amazonaws.com
    • Cache behaviors for index.html (short TTL) and assets/* (long TTL)

ACM Certificates: Issued for thequeensfleet.com with DNS validation via Namecheap, renewed automatically by AWS. All distributions use the same certificate.

Key Architectural Decisions

Why CloudFront function instead of Lambda@Edge? Functions are faster (no cold starts), simpler to deploy, and sufficient for host-header rewriting. Lambda@Edge would add unnecessary latency for a stateless routing decision.

Why separate hub distribution? The hub changes frequently and needs aggressive cache invalidation; city sites are static. Separate distributions let us optimize cache policies independently. Hub uses Cache-Control: no-cache on index.html (validate before serving), city index.html uses a 30-minute TTL.

Why Route53 aliases instead of CNAME? Aliases let us point the apex (thequeensfleet.com, not just www) to CloudFront. CNAMEs cannot be used at zone apex.

Why registry-driven hub build? The hub is generated once at build time from a Python dict (site registry), not queried dynamically. This keeps the hub HTML a simple static file with no runtime dependencies, zero cold starts, and trivial edge caching.

Deployment Workflow

The hub is built locally:

python build_hub.py

Output lands in build/hub.html, then synced to S3:

aws s3 cp build/hub.html s3://qos-city-sites/hub.html --cache-control "no-cache"

CloudFront distribution is invalidated to purge old versions:

aws cloudfront create-invalidation --distribution-id E176JRMB92GPAJ --paths "/index.html"

Deployment is verified by checking ETag on the S3 object and confirming CloudFront returns the new version over HTTPS.

Testing & Validation

Test suite in /Users/cb/icloud-repos/sites/queenof-cities/tests/test_hub.py verifies:

  • All 16 city cards are present in rendered HTML
  • Card links point to correct queenof[city].com URLs
  • S3 objects exist for all destination index.html and 0.jpg files
  • HTTP/HTTPS endpoints return 200 and serve correct content

After each deployment, tests run against live endpoints to catch propagation delays or misconfigured cache behaviors.

Site Registry Integration

The hub entry was added to the site registry (a centralized Python dict mapping domain → metadata). The registry now includes:

  • thequeensfleet.com as the venture hub
  • All 16 queenof[city].com sites as destinations
  • Metadata: hero copy, card images, destination links

This single source of truth drives hub generation, test fixtures, and infrastructure validation.

What's Next

The hub is live and fully functional. Future work includes:

  • Implementing the avatar generation pipeline (Phase 1 of the broader Jada initiative)
  • Integrating avatar assets into the hub hero section
  • Adding dynamic product catalog linking to destination sites
  • Monitoring CloudFront cache hit ratio and optimizing TTLs based on traffic patterns