Consolidating Multi-Site Infrastructure: Migrating adamcherrycomics from Per-Bucket to Shared Origin Pattern
This post documents the infrastructure consolidation work completed for adamcherrycomics.dangerouscentaur.com, which involved decommissioning a stale per-site S3 bucket and verifying the site was already running on a shared origin architecture with CloudFront routing. The work uncovered an important pattern for scaling multi-tenant static sites behind a single distribution.
What Was Done
We identified and safely deleted an orphaned S3 bucket (s3://adamcherrycomics.dangerouscentaur.com/) that was no longer serving traffic. This bucket represented technical debt from an earlier architecture phase where each site had its own origin bucket. The site had already been migrated to a shared-bucket pattern but the old bucket remained, creating ambiguity about the serving path.
Technical Architecture: The Serving Pattern
The current production setup uses:
- Single S3 Origin:
dc-sites.s3.us-east-1.amazonaws.com(shared bucket for all dangerouscentaur.com subdomains) - CloudFront Distribution:
E2Q4UU71SRNTMB(apex wildcard*.dangerouscentaur.com) - Origin Path: None (root of bucket)
- CloudFront Function:
dc-sites-router(request-stage rewrite) - DNS:
adamcherrycomics.dangerouscentaur.com→ CNAME →dclu4nl5nln98.cloudfront.net
The routing logic works as follows: when a request arrives for adamcherrycomics.dangerouscentaur.com/path/to/page.html, CloudFront invokes the dc-sites-router function at the request stage. This function extracts the hostname and rewrites the URI to /adamcherrycomics.dangerouscentaur.com/path/to/page.html before forwarding to the S3 origin. The S3 bucket stores all site files under hostname-prefixed directories:
dc-sites/
├── adamcherrycomics.dangerouscentaur.com/
│ ├── index.html
│ ├── about.html
│ ├── css/
│ └── img/
├── queenofsandiego.com/
│ ├── index.html
│ ├── captains-log/
│ └── ...
└── [other sites]/
Why the Old Bucket Was Safe to Delete
We verified deletability on four fronts:
- Genuinely empty: AWS S3 console confirmed
Total Objects: 0. No content, no versioning history. - Not in the serving path: CloudFront distribution
E2Q4UU71SRNTMBpoints exclusively todc-sites.s3.us-east-1.amazonaws.com. The hostname-named bucket (adamcherrycomics.dangerouscentaur.com) is never queried by CloudFront. - No DNS dependency: The CNAME record at Namecheap points to CloudFront's distribution URL, not to an S3 website endpoint. Deleting the bucket does not break DNS resolution.
- Origin of the bucket: This bucket was created during an earlier architecture phase (per-site bucket pattern) and was superseded by the shared
dc-sitesbucket when the routing function was introduced.
Deletion Process
We used the AWS CLI to verify and delete the bucket:
aws s3api list-objects-v2 \
--bucket adamcherrycomics.dangerouscentaur.com \
--query 'Contents | length(@)'
# Output: 0 (confirmed empty)
aws s3 rb s3://adamcherrycomics.dangerouscentaur.com/
# Removed empty bucket: adamcherrycomics.dangerouscentaur.com
The rb (remove bucket) command succeeds only if the bucket is empty; no objects or versioning data need to be purged. This is a safe operation because the bucket name is not actively used.
CloudFront Distribution Verification
We cross-checked that all traffic is served from the shared origin:
aws cloudfront get-distribution-config --id E2Q4UU71SRNTMB | jq '.DistributionConfig.Origins'
# Output:
# [
# {
# "Id": "dc-sites-origin",
# "DomainName": "dc-sites.s3.us-east-1.amazonaws.com",
# "S3OriginConfig": { "OriginAccessIdentity": "" },
# ...
# }
# ]
No alternate origin pointing to the deleted bucket exists. The function rewrite is the sole routing mechanism.
Key Decision: Shared Origin with CloudFront Function Routing
This architecture scales better than per-bucket patterns because:
- Reduced blast radius: One S3 bucket failure affects all sites, but failures are uncommon and easier to diagnose than a fleet of buckets.
- Unified caching policy: All sites behind the same distribution inherit the same cache behaviors and TTLs. This simplifies cache invalidation (
aws cloudfront create-invalidation --distribution-id E2Q4UU71SRNTMB --paths "/*"). - Single DNS layer: The wildcard CNAME handles any number of new subdomains without additional DNS records.
- Function-driven routing: CloudFront Functions are lightweight (under 10 KB) and execute at edge locations before origin requests, making the rewrite transparent and fast.
- Cost efficiency: Fewer S3 API calls and CloudFront data-transfer charges when consolidating under one origin.
The trade-off is operational complexity: every new site requires a directory in the shared bucket and must be known to the router function. But this is acceptable at the current scale (4–5 sites) and the function is easy to modify.
DNS and Recent Fixes
For context, the adamcherrycomics site had experienced DNS outage in a prior session (2026-05-21). The issue was that a www.adamcherrycomics CNAME at Namecheap was shadowing the wildcard *.dangerouscentaur.com record (per RFC 1034 §4.3.3). The fix was to add an explicit adamcherrycomics CNAME (without the www prefix) pointing to the CloudFront distribution. This ensures both adamcherrycomics.dangerouscentaur.com and www.adamcherrycomics.dangerouscentaur.com resolve to CloudFront.
What's Next
With the old bucket removed, the infrastructure is cleaner and more defensible. Future work should focus on: