Consolidating Multi-Site Infrastructure: Migrating adamcherrycomics from Per-Site to Shared S3 + CloudFront Router Pattern

This post details the infrastructure consolidation work completed for adamcherrycomics.dangerouscentaur.com, including DNS fixes, bucket cleanup, and validation of the shared origin + routing function pattern used across the dangerouscentaur.com ecosystem.

Status Summary

adamcherrycomics.dangerouscentaur.com is live and serving 200 responses. The site uses:

  • Shared S3 origin: dc-sites bucket in us-east-1
  • Shared CloudFront distribution: E2Q4UU71SRNTMB (wildcard *.dangerouscentaur.com)
  • Content routing: CloudFront Function dc-sites-router rewrites request paths
  • DNS: CNAME at Namecheap pointing to CloudFront origin
  • Checkout flow: Stripe-hosted (redirect mode) via Lambda backend

The Per-Site Bucket Problem

Auditing the AWS account revealed a stale, empty S3 bucket: s3://adamcherrycomics.dangerouscentaur.com/. This bucket was a remnant from an earlier architecture where each site had its own bucket. The bucket contained zero objects and was not referenced in any CloudFront origin, Lambda code, or DNS records.

Why this was safe to delete:

  • Not on the serving path: CloudFront distribution E2Q4UU71SRNTMB defines a single origin pointing to dc-sites.s3.us-east-1.amazonaws.com. The dc-sites-router CloudFront Function intercepts all requests and rewrites them as /adamcherrycomics.dangerouscentaur.com/<original-path> before forwarding to the shared bucket. The hostname-named bucket is never consulted.
  • DNS does not reference it: The DNS CNAME for adamcherrycomics.dangerouscentaur.com points directly to the CloudFront distribution alias, not to an S3 website endpoint.
  • No code dependencies: Lambda functions, static site generators, and deployment scripts all target dc-sites, not the per-site bucket.
  • Verified empty: AWS console inspection showed Total Objects: 0 and no versioning or lifecycle policies.

The bucket was deleted. If needed in the future, a new bucket of the same name can be created—the name is still globally unique to the AWS account.

DNS Fix: CNAME Shadowing and RFC 1034

In a previous session, a DNS outage was caused by a subtle RFC 1034 §4.3.3 violation. The domain dangerouscentaur.com had a wildcard CNAME (*.dangerouscentaur.com) but the specific subdomain www.adamcherrycomics.dangerouscentaur.com was missing an explicit CNAME. This caused:

  • Browsers querying www.adamcherrycomics.dangerouscentaur.com
  • Resolver matching the wildcard first, applying incorrect routing
  • CNAME shadowing preventing other record types (like the needed A record via CloudFront alias)

Fix: Added an explicit CNAME at Namecheap:

adamcherrycomics.dangerouscentaur.com  CNAME  dclu4nl5nln98.cloudfront.net

This explicit record takes precedence over the wildcard and correctly routes traffic to the CloudFront distribution.

CloudFront + Router Function Architecture

The shared infrastructure pattern used here is elegant for low-to-medium-traffic multi-site hosting:

  • Single S3 bucket: dc-sites contains all site content organized by hostname prefix: /adamcherrycomics.dangerouscentaur.com/index.html, /queenofsandiego.com/index.html, etc.
  • Single CloudFront distribution: E2Q4UU71SRNTMB handles all *.dangerouscentaur.com subdomains via a single origin.
  • CloudFront Function for routing: Deployed at the viewer request stage to rewrite incoming paths. For example:
    • Request: GET /index.html (host: adamcherrycomics.dangerouscentaur.com)
    • Function output: GET /adamcherrycomics.dangerouscentaur.com/index.html
    • S3 serves the rewritten path from dc-sites

Advantages: Reduced operational overhead (one distribution, one bucket, one set of edge caching rules), centralized logging, unified SSL certificate management.

Trade-offs: All sites share caching headers and rate-limit quotas; debugging routing issues requires understanding the function logic.

Recent Site Updates

Beyond infrastructure, the session also addressed several functional issues on the site:

  • Stripe checkout flow: Lambda code was missing the typing_extensions dependency and was using a deprecated Stripe UI mode (ui_mode="embedded", removed in stripe-python 15.1.0). Updated to ui_mode="hosted_page" with a redirect-based flow.
  • About Artist page: Updated portrait image and changed artist social link from Instagram to canvasrebel.com.
  • Dropdown hover bug: Fixed top: calc(100% + Npx) gap calculations across all four HTML pages, ensuring proper spacing when dropdowns open.

Deployment and Validation

All changes were validated end-to-end:

  • Verified CloudFront distribution E2Q4UU71SRNTMB returns 200 responses for adamcherrycomics.dangerouscentaur.com
  • Confirmed the dc-sites-router function is rewriting paths correctly by inspecting CloudFront request/response headers
  • Spot-checked that the old per-site bucket was not referenced anywhere in Lambda, Route53, or other AWS services
  • Tested Stripe redirect flow end-to-end in a staging environment

What's Next

Pending items include:

  • End-to-end validation by the site owner of the full Buy Now → Stripe → return flow in production
  • Optional future work: regist