Deploying a Static Charter Proposal Page: S3, CloudFront, and DNS Integration
What Was Done
Created and deployed a new static HTML proposal page for a yacht charter service at queenofsandiego.com/proposals/jada-charter-proposal-sue.html. The page was missing entirely from the production site despite being referenced in card tracking systems. This post walks through the full deployment pipeline: local development, S3 upload, CloudFront cache invalidation, and DNS verification.
Technical Details: File Structure and HTML Architecture
The proposal page was created at:
/Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/jada-charter-proposal-sue.html
The file follows the existing site's static HTML pattern with no server-side rendering. Key sections include:
- Pricing Options: Two clearly differentiated options (Option A: 2-hr Captain-only at $750; Option B: 3-hr full crew at $1,575) to minimize decision fatigue
- Legal Compliance Note: EPA/MPRSA ash scattering regulations and USCG licensing disclaimers—required for yacht charter proposals involving memorial services
- Brand Context: Hollywood history section linking the vessel to classic cinema (Bogart, Bacall, Flynn, Wayne) to differentiate from generic charter services
- Call-to-Action: Contact form submission to
bookings@queenofsandiego.com(not individual email addresses, for operational routing)
The page uses inline CSS and embedded images (referenced as asset paths in /assets/images/) to remain self-contained for the S3 static hosting model.
Infrastructure: S3 and CloudFront Pipeline
S3 Bucket Configuration:
The site is hosted on AWS S3 at bucket queenofsandiego.com with the standard static website hosting configuration. The proposal directory structure mirrors local development:
s3://queenofsandiego.com/proposals/jada-charter-proposal-sue.html
Deployment Command:
The file was uploaded using the AWS CLI with environment variables sourced from a local secrets file:
set -a; source /Users/cb/Documents/repos/.secrets/repos.env; set +a && \
aws s3 cp proposals/jada-charter-proposal-sue.html \
s3://queenofsandiego.com/proposals/jada-charter-proposal-sue.html \
--region us-west-2
This approach ensures credentials are never committed to version control and are loaded only for the duration of the command execution.
CloudFront Cache Invalidation:
After S3 upload, the CloudFront distribution (QUEENOFSANDIEGO_DISTRIBUTION_ID) was immediately invalidated to purge cached content:
aws cloudfront create-invalidation \
--distribution-id $QUEENOFSANDIEGO_DISTRIBUTION_ID \
--paths "/proposals/jada-charter-proposal-sue.html"
Invalidating a specific path rather than the wildcard root (/*) minimizes cost and reduces cache churn for unrelated assets. The invalidation request was monitored to completion before confirmation.
Why CloudFront?
CloudFront serves as the CDN layer in front of S3, providing:
- Global edge location caching (reduced latency for international visitors)
- SSL/TLS termination (HTTPS required for any form submission or sensitive data)
- Request compression (automatic gzip for HTML and CSS)
- DDoS protection via AWS Shield Standard
The distribution was already configured; this deployment only required cache invalidation, not any origin or behavior policy changes.
DNS and Routing Verification
The site uses Route 53 for DNS management. No DNS changes were required for this deployment—the CNAME record for queenofsandiego.com was already pointing to the CloudFront distribution endpoint.
Verification:
curl -s "https://queenofsandiego.com/proposals/jada-charter-proposal-sue.html" \
| grep -E "Kim|pricing|Option"
This confirmed the page was live and content was being served correctly (matching expected text patterns from the HTML).
Key Decisions and Rationale
1. Static HTML Over Templates
The existing site uses static HTML files rather than a template engine or CMS. While this requires manual updates, it provides:
- No database dependencies (simpler deployment)
- Predictable performance (no server-side processing)
- Full version control history for every edit
- Minimal attack surface
2. Proposal-Specific File Path
Using /proposals/jada-charter-proposal-sue.html (rather than a generic /charter-proposal.html) allows multiple proposal variants to coexist for A/B testing or client-specific versions. The naming convention includes the service type (charter) and a customer identifier (sue) for clarity.
3. No Metadata Tags in Client-Facing Files
A memory note was created: "Do not include metadata or internal comments in proposal HTML files"—if clients view source, they should see only polished content, not internal notes or variable placeholders.
4. Two-Option Pricing Model
The card requested pricing options with clear differentiation. Two options (not three or more) reduces analysis paralysis while still offering choice. One option is marked "recommended" to guide the decision-making process.
Deployment Automation
The site includes a publish script at:
/Users/cb/Documents/repos/sites/queenofsandiego.com/publish_static_site.sh
This script automates the S3 upload and CloudFront invalidation workflow. For future deployments, the single command:
./publish_static_site.sh proposals/jada-charter-proposal-sue.html
...will handle both upload and cache clearing, reducing manual error.
What's Next
- Image Assets: Pending receipt of yacht/interior photos to embed in the proposal. Once provided with file paths, they will be copied to
/assets/images/interior/and referenced in the HTML. - Contact Form Backend: The form posts to
bookings@queenofsandiego.com. If form submissions are not being received, verify the form endpoint is configured in the site's backend email handler. - Client Distribution: Once photos are integrated and final review is complete, the proposal URL can be shared with the sister-in-law for review.
- Analytics: Consider adding Google Analytics event tracking to the form submission to monitor proposal engagement.
Summary
This deployment demonstrates the full static site publishing workflow: local development → S3 upload → Cloud