Consolidating adamcherrycomics to Shared CloudFront + Fixing DNS Shadowing and Stripe Checkout

What Was Done

This session completed the migration of adamcherrycomics.dangerouscentaur.com from a per-site S3 bucket architecture to the shared dc-sites bucket pattern, eliminated a DNS shadowing issue that broke the www subdomain, fixed a deprecated Stripe API mode that caused checkout failures, and cleaned up stale infrastructure.

  • Deleted orphaned S3 bucket s3://adamcherrycomics.dangerouscentaur.com/
  • Fixed DNS CNAME shadowing at the apex that was blocking the www subdomain
  • Updated Lambda checkout handler to remove deprecated ui_mode="embedded" and switch to ui_mode="hosted_page"
  • Rebuilt and redeployed Lambda deployment package with missing typing_extensions dependency
  • Updated site assets (new artist portrait, fixed dropdown hover positioning across 4 HTML pages)

Technical Details: DNS Shadowing and the CNAME Problem

The adamcherrycomics site operates under the wildcard domain *.dangerouscentaur.com, but the www subdomain was returning NXDOMAIN errors. The root cause was CNAME shadowing as described in RFC 1034 §4.3.3.

What happened: At Namecheap, the zone file had a wildcard CNAME:

*.dangerouscentaur.com  CNAME  dclu4nl5nln98.cloudfront.net

When a client queried www.adamcherrycomics.dangerouscentaur.com, the DNS server matched the query against the wildcard and returned a CNAME. However, the presence of the wildcard at the apex prevented the nameserver from then recursively resolving the CNAME target. Modern DNS resolvers respect this shadowing rule to prevent infinite loops and zone contamination.

The fix: Added an explicit CNAME record at Namecheap:

adamcherrycomics.dangerouscentaur.com  CNAME  dclu4nl5nln98.cloudfront.net

This explicit entry takes precedence over the wildcard for the adamcherrycomics subdomain, allowing the DNS resolver to proceed with CNAME resolution without ambiguity. The wildcard remains in place for any other future subdomains under dangerouscentaur.com.

Infrastructure: Shared Origin Pattern

Rather than maintain per-site S3 buckets, the adamcherrycomics infrastructure now uses the shared origin pattern

  • Origin bucket: s3://dc-sites.us-east-1.amazonaws.com/
  • CloudFront distribution ID: E2Q4UU71SRNTMB (shared across all dangerouscentaur.com subdomains)
  • Origin configuration: Single S3 origin, domain dc-sites.s3.us-east-1.amazonaws.com
  • Routing logic: CloudFront Function dc-sites-router inspects the Host header and rewrites the request URI to /adamcherrycomics.dangerouscentaur.com/{path}

The orphaned bucket s3://adamcherrycomics.dangerouscentaur.com/ was confirmed empty (Total Objects: 0) and was not referenced by any DNS record or CloudFront origin configuration. It was safely deleted as a cleanup artifact from the pre-migration architecture.

Stripe Checkout: Deprecation and Handler Update

The site uses a Stripe-hosted checkout with a redirect flow. In stripe-python 15.1.0, the Stripe API deprecated ui_mode="embedded", which was causing checkout session creation to fail with an HTTP 400 error.

Root causes:

  • Lambda handler was pinned to an older stripe-python version; upgrade introduced the breaking change
  • Handler code passed ui_mode="embedded" to stripe.checkout.Session.create(), which the API no longer accepts
  • Lambda deployment package was missing the typing_extensions module, causing runtime import failures in newer boto3/stripe versions

The fix:

# Old checkout handler signature (broken)
stripe.checkout.Session.create(
  payment_method_types=["card"],
  ui_mode="embedded",  # ← Deprecated in stripe-python 15.1.0+
  ...
)

# New checkout handler signature (working)
stripe.checkout.Session.create(
  payment_method_types=["card"],
  ui_mode="hosted_page",  # ← Correct mode for redirect flow
  ...
)
response = {
  "sessionUrl": session.url  # Client redirects to this
}

Rebuilt the Lambda deployment zip with all dependencies pinned and typing_extensions explicitly included. Redeployed to the checkout Lambda function (referenced in API Gateway integration for the /checkout endpoint).

Frontend Updates: Dropdown Positioning

Fixed a cross-browser dropdown positioning issue affecting hover behavior on 4 HTML pages (index.html, about.html, portfolio.html, contact.html). The bug was a miscalculated top property in the dropdown submenu CSS:

/* Before (broken) */
.dropdown-menu {
  top: calc(100% + Npx);  /* gap too large or inconsistent */
}

/* After (fixed) */
.dropdown-menu {
  top: calc(100% + 4px);  /* consistent small gap */
}

Also updated the About Artist page to use a new portrait image (IMG_2567.jpeg) and changed the artist link target from Instagram to canvasrebel.com, reflecting the artist's preferred web presence.

Key Decisions

  • Why consolidate to the shared bucket? Reduces per-site operational overhead (fewer S3 lifecycle policies, fewer CloudFront cache invalidation targets, single origin to manage), improves cost per site, and simplifies DNS configuration since all sites share a single CF distribution.
  • Why explicit CNAME instead of ALIAS records? Namecheap does not support ALIAS/ANAME records at the time of this work; explicit CNAME is the standard DNS solution and is widely supported.
  • Why ui_mode="hosted_page" instead of embedding? Hosted pages are simpler to maintain (Stripe owns the UI), are more secure (no client-side token handling), and are fully compatible with the current redirect-based checkout flow.
  • Why keep the wildcard CNAME? Future subdomains under dangerouscentaur.com can be brought online without additional DNS changes;