Deploying a Multi-Tenant Receipt Management Page: CloudFront 404 Handling and S3 Pretty URLs

This post covers the technical challenges and solutions encountered while deploying a new receipt upload page for a trailer rental business operating under the quickdumpnow.com domain. The work involved understanding CloudFront's custom error responses, managing S3 object key naming conventions for pretty URLs, and coordinating multiple deployment steps across S3, CloudFront invalidation, and robots.txt updates.

The Problem: Landing Page Instead of Receipt Manager

The https://quickdumpnow.com/books endpoint was returning the site's homepage instead of the newly built receipt management page. This happened despite the local file existing at /Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html. Investigation revealed a two-part root cause:

  • The S3 object for the books page had never been deployed to the origin bucket
  • CloudFront's custom error response configuration was redirecting all 404 errors to the homepage, masking the missing S3 object

Technical Approach: S3 Pretty URLs and CloudFront Invalidation

The solution required understanding how S3 and CloudFront interact when serving directory-style URLs without file extensions. Here's the technical architecture:

S3 Object Key Strategy

To serve https://quickdumpnow.com/books as a pretty URL (without exposing index.html in the request), we deployed the HTML file under two S3 object keys:

  • s3://quickdumpnow-prod/books/index.html — The canonical location, following local directory structure
  • s3://quickdumpnow-prod/books — A duplicate object targeting the bare path, ensuring S3/CloudFront resolves the request correctly

This dual-key approach accounts for browser request behavior and S3's object model. When a user requests /books, CloudFront checks the origin S3 bucket. Without the bare /books key, S3 returns 404, which CloudFront's error response handler converts to a redirect—not ideal. By uploading to both keys, we ensure at least one matches the request pattern.

Robots.txt Configuration

The receipt upload page was added to robots.txt to prevent search engine indexing of user-uploaded receipts:

Disallow: /books

This is a standard SEO practice for internal business tools that shouldn't appear in search results.

Deployment Steps and Commands

The deployment involved a sequence of AWS CLI and Google Sheets API calls orchestrated through local scripts:

1. S3 Upload

aws s3 cp /Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html s3://quickdumpnow-prod/books/index.html --content-type text/html
aws s3 cp /Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html s3://quickdumpnow-prod/books --content-type text/html
aws s3 cp /Users/cb/Documents/repos/sites/quickdumpnow.com/robots.txt s3://quickdumpnow-prod/robots.txt --content-type text/plain

Note the explicit --content-type flags. S3's auto-detection can fail for files without standard extensions, causing CloudFront to serve them as application/octet-stream instead of the correct MIME type.

2. CloudFront Cache Invalidation

aws cloudfront create-invalidation --distribution-id E1A2B3C4D5E6F7 --paths /books /books/ /robots.txt

We invalidated three paths:

  • /books — Bare path for the pretty URL
  • /books/ — Trailing slash variant (browsers may request either)
  • /robots.txt — Global site file with new disallow rule

CloudFront invalidations typically propagate to all edge locations within 30–60 seconds. Without this step, users would receive stale cached responses even though the origin had been updated.

Infrastructure and Configuration Details

CloudFront Distribution Setup

The quickdumpnow.com domain uses a CloudFront distribution (ID: E1A2B3C4D5E6F7, placeholder for actual ID) configured with:

  • Origin: S3 bucket quickdumpnow-prod
  • Custom Error Response: 404 errors redirected to /index.html with HTTP 200 status
  • Default Root Object: index.html
  • Caching Behavior: Query string forwarding enabled for future receipt filtering

The custom error response is crucial for single-page application (SPA) behavior but complicates nested static pages. This trade-off works well for the current architecture because the books page is a distinct route that should be served from S3 without SPA routing logic.

Route53 Configuration

The quickdumpnow.com zone maintains an A record with alias target pointing to the CloudFront distribution. No changes were required for this deployment since we were modifying origin content, not the distribution itself.

Key Decisions and Rationale

Why Dual S3 Keys?

S3 is an object store, not a file system. Directory navigation (/books → /books/index.html) is a web server feature that must be explicitly configured. CloudFront's origin request forwarding doesn't perform this translation; it expects exact key matches. Uploading to both keys is simpler and more reliable than configuring Lambda@Edge for rewriting, especially for a small number of static pages.

Why Not Just Fix the Error Response?

Removing or modifying the 404→homepage redirect would break existing SPA routing for other parts of the site. The custom error response is intentional for the main site. Instead, we worked within the constraint by ensuring the S3 object exists before the error handler is invoked.

Why Invalidate Multiple Paths?

CloudFront doesn't guarantee exact path matching for invalidations. By invalidating /books, /books/, and related paths, we ensure all possible request variants are cleared from the cache. This is a defensive approach for low-traffic endpoints where over-invalidation has minimal cost.

Related Work: Port Sheet Integration

In parallel with this deployment, receipt entries are being integrated with an automated port sheet maintained in Google Sheets. The receipt management page will eventually feed charter data (like yesterday's $1,845.72 payment from Joseph Zurek) directly into the Port Log sheet via the Google Sheets API. This requires:

  • Apps Script manifest configuration in the ExpenseTracker project
  • Access tokens for programmatic sheet updates
  • Validation of sheet tab IDs and column headers before appending entries

The receipt page and port sheet automation form a complete business workflow—capturing payments on the web and synchronizing them to financial records without manual data entry.