Consolidating Multi-Site Infrastructure: Migrating adamcherrycomics.dangerouscentaur.com to Shared Origin Pattern

Overview

This post documents the infrastructure consolidation work completed for adamcherrycomics.dangerouscentaur.com, including DNS correction, Lambda dependency fixes, and cleanup of legacy S3 bucket patterns. The site now follows the shared-origin architecture pattern used across the dangerouscentaur.com ecosystem.

What Was Done

  • Fixed DNS shadowing issue that broke www.adamcherrycomics subdomain routing
  • Resolved Lambda dependency missing from Stripe integration layer
  • Updated Stripe checkout UI mode from deprecated embedded to hosted_page
  • Fixed dropdown styling regression across all site pages
  • Decommissioned legacy per-site S3 bucket following bucket consolidation pattern
  • Verified end-to-end checkout flow redirects properly

Technical Details: DNS Shadowing Fix

The www.adamcherrycomics subdomain was unreachable due to RFC 1034 §4.3.3 DNS shadowing behavior. At Namecheap, the wildcard CNAME *.dangerouscentaur.com → dclu4nl5nln98.cloudfront.net was shadowing the explicit www CNAME record.

Root Cause: When a subdomain query matches both a wildcard and an explicit record at the same level, the explicit record should take precedence. However, the original configuration had only the wildcard in place.

Resolution: Added explicit CNAME record at Namecheap:

Host: adamcherrycomics
Type: CNAME
Value: dclu4nl5nln98.cloudfront.net
TTL: 3600

This ensures adamcherrycomics.dangerouscentaur.com resolves directly without relying on wildcard fallback. The wildcard continues to handle any other subdomains added in the future.

Technical Details: Stripe Checkout Integration Fix

The site uses Stripe's hosted checkout redirect flow. Two issues were blocking the checkout flow:

Issue 1: Missing Dependency

The Lambda function that initializes Stripe sessions was missing the typing_extensions package, causing import failures in stripe-python 15.1.0+. The fix required rebuilding the deployment zip to include the dependency in the layer or inline.

Issue 2: Deprecated UI Mode

The frontend was calling Stripe's embedded checkout with ui_mode="embedded", which stripe-python 15.1.0 deprecated in favor of Payment Element or hosted checkout. This caused Stripe API validation errors.

Resolution: Updated the Lambda session initialization to use ui_mode="hosted_page" and redirected the frontend to session.url instead of attempting to embed the checkout form. This shifts the user to Stripe's hosted checkout page, then back to the site upon completion.

# Pseudo-code: Lambda session creation
session = stripe.checkout.Session.create(
    ui_mode="hosted_page",
    line_items=[...],
    success_url=f"{domain}/checkout/success",
    cancel_url=f"{domain}/checkout/cancel",
)
# Frontend redirects to session.url

Technical Details: CSS Dropdown Regression

Navigation dropdowns had a visual gap between the trigger and the submenu, caused by incorrect use of calc() in the top positioning rule. The fix was applied consistently across four HTML pages in the site root.

Before:

.dropdown-menu {
  top: calc(100% + Npx);  /* Large gap */
}

After:

.dropdown-menu {
  top: 100%;  /* Flush with trigger */
  margin-top: 0;  /* Ensure no extra spacing */
}

Infrastructure: S3 Bucket Consolidation

The site originally followed a per-site bucket pattern where each domain had its own S3 bucket (e.g., s3://adamcherrycomics.dangerouscentaur.com/). This pattern has been deprecated in favor of a shared-origin architecture.

Current Architecture:

  • Origin bucket: s3://dc-sites.us-east-1.amazonaws.com/
  • CloudFront distribution: E2Q4UU71SRNTMB (serving all *.dangerouscentaur.com sites)
  • Request routing: CloudFront Function dc-sites-router rewrites incoming requests from adamcherrycomics.dangerouscentaur.com/path to dc-sites/adamcherrycomics.dangerouscentaur.com/path
  • DNS: CNAME to dclu4nl5nln98.cloudfront.net (the distribution alias)

Why the Legacy Bucket is Safe to Delete:

  • Not on serving path: CloudFront origin is dc-sites, not adamcherrycomics.dangerouscentaur.com. The legacy bucket is never accessed.
  • No DNS binding: The domain's CNAME points to CloudFront, not to an S3 website endpoint.
  • Verified empty: Bucket contained zero objects before deletion.
  • No lifecycle data: No versioning, replication, or event subscriptions dependent on it.

The legacy bucket was deleted. This reduces account clutter and eliminates any risk of accidental content uploads to the wrong location.

Key Architectural Decisions

1. Shared Origin Over Per-Site Buckets

Consolidating all *.dangerouscentaur.com sites into a single dc-sites bucket with a CloudFront routing function reduces operational complexity, simplifies IAM policies, and centralizes cache invalidation. Each site's content is namespaced by its hostname within the bucket.

2. CloudFront Function for Routing

Using CloudFront Functions (not Lambda@Edge) to rewrite the origin path keeps routing logic at the edge, eliminates cold-start latency, and costs significantly less than Lambda@Edge for high-volume request rewriting.

3. Stripe Hosted Checkout Over Embedded

Moving to hosted checkout simplifies PCI compliance scope, reduces frontend complexity, and ensures access to the latest Stripe features without tight version coupling. The tradeoff is a brief redirect away from the site, which is acceptable for a commerce flow.

4. Explicit DNS Records Over Wildcard Alone

Adding explicit CNAME records for each site removes ambiguity and ensures predictable DNS resolution without rel