跳到正文
DEV Community· Abhishek Vasisht·· 2 小時前AI 評分59

作者展示如何以每月低於 US$5 在 AWS 運行專業級診所網站

A professional-grade website for under $5 a month

AI 導讀

Abhishek Vasisht 將妻子的天然護膚診所網站由 Base44 重建至 AWS,估算月費為 US$2–5,並加入安全控制及自動化部署。網站把報名、預約和付款轉為事件,經 SQS 重試電郵平台同步,失敗 5 次後移入保留 14 日的死信佇列,並向作者發出電郵警報。相較原先每月 US$40 的 Base44,作者估算每年節省約 US$420,並選擇不使用 AWS WAF 以控制成本。

正文

How I run my wife's clinic website https://naturlaskin.clinic on AWS with security, automation and the Well-Architected Framework built in from day one

My wife runs a natural skin clinic. Her first website lived on Base44, an AI app builder, for US$40 a month. It worked, but it lost leads silently, every condition shared one URL, and I couldn't see inside it.

So I did what I do for a living: I rebuilt it on AWS. It now runs for an estimated US$2–5 a month, ships through a fully automated pipeline, and was designed against all six pillars of the AWS Well-Architected Framework.

Here's how, in three diagrams.


What "professional grade" means here

This is not a brochure. It's a small sales funnel for a real business:

  • 20+ pages, condition guides and a blog, all with their own SEO-friendly URLs
  • A free-guide signup that feeds an email welcome sequence
  • Bookings (TidyCal) and payments (Stripe) that tag the contact automatically
  • A password-protected /admin editor so my wife can publish without me
  • 5-minute uptime checks and alarms that email me before a customer notices

The stack: Astro static site · S3 + CloudFront · API Gateway + Lambda (Node 22 on Graviton) · DynamoDB · EventBridge + SQS · Cognito · Route 53. Everything is AWS CDK in TypeScript, in Sydney.


1. Security is job zero

As a technical leader, I don't treat a small site as a reason to cut corners. Small sites get scanned and spammed just like big ones. The difference is that nobody's watching them.

So security was the first design decision, not the last. Follow one signup through the stack:

sequenceDiagram
    autonumber
    actor V as Visitor
    participant CF as CloudFront (edge)
    participant S3 as S3 bucket (private)
    participant API as API Gateway
    participant L as Subscribe Lambda
    participant DB as DynamoDB
    participant CW as CloudWatch

    V->>CF: Open the site (HTTP is redirected to HTTPS)
    Note over V,CF: TLS 1.2+ only, HSTS for 1 year,<br/>CSP and X-Frame-Options DENY
    CF->>S3: Fetch the page via Origin Access Control
    Note over S3: All public access blocked
    S3-->>V: Static HTML
    V->>CF: Submit the guide form
    CF->>API: Forward /api/* only
    Note over API: Throttled to 10 req/s (burst 20),<br/>5 routes and nothing else
    API->>L: Invoke
    Note over L: Validates input, honeypot field,<br/>least-privilege IAM role
    L->>DB: Save subscriber and consent record
    Note over DB: Encrypted, point-in-time recovery,<br/>deletion protection
    L-->>CW: Log the event with the email masked
    L-->>V: "Check your inbox"

Beyond the request path:

  • No long-lived keys anywhere. GitHub Actions assumes an IAM role through OIDC. Credentials last one hour, and only the main branch can deploy. Pull requests get a read-only role that can only run cdk diff.
  • Secrets live in SSM Parameter Store as SecureStrings. Each Lambda can read only the parameters it needs.
  • The editor has no GitHub account. It signs in through Cognito (no self sign-up, 12+ character passwords, optional authenticator MFA). A GitHub App installed on one repo issues 8-hour tokens.
  • Webhooks are verified. Stripe signatures are checked with a constant-time compare and a 5-minute replay window.
  • Data is protected by default. S3 blocks all public access. DynamoDB has point-in-time recovery and deletion protection. Every queue rejects non-TLS traffic.
  • Dependencies stay fresh. Dependabot opens updates weekly, and they ship through the same gates as everything else.

A deliberate trade-off: I don't run AWS WAF, the web application firewall. A single web ACL starts at US$5 a month plus US$1 per rule, which would more than double the bill. For a static site with only five API routes, throttling and input validation cover the risk. If traffic or threats grow, it's one CDK construct away.


2. Reliability: never lose a lead

Base44 had a quiet bug. One signup form saved emails but never sent them to the email platform, so those people never got their free guide. Nobody noticed.

On AWS, every signup, booking and payment becomes an event. The event sits in a queue until the email platform confirms it.

sequenceDiagram
    participant Src as Signup, Stripe, TidyCal
    participant EB as EventBridge
    participant Q as SQS queue
    participant L as Kit sync Lambda
    participant Kit as Kit (email)
    participant DLQ as Dead-letter queue

    Src->>EB: Publish an event (signup, booking or payment)
    EB->>Q: Rule routes it to the queue
    loop Up to 5 attempts
        Q->>L: Deliver a batch of up to 5
        L->>Kit: Tag the contact
        alt Kit is up
            Kit-->>L: OK, welcome emails start
            L-->>Q: Done, delete the message
        else Kit is down
            Kit--xL: Error
            L-->>Q: Report the failure, retry later
        end
    end
    Q->>DLQ: Still failing after 5 attempts
    Note over DLQ: Kept for 14 days,<br/>an alarm emails me

If Kit (the email platform) is down, messages wait and retry. After five failures they park in a dead-letter queue for 14 days and I get an email. An outage delays a welcome email. It never loses a lead.

One more reliability win: the move from Base44 to AWS used a single atomic Route 53 change. Production was built and tested on its CloudFront URL first, then the DNS swap happened in one batch. There was never a moment without a DNS record, and rollback is one script.


3. Automation: no hands on the console

No infrastructure change goes through the AWS console. Every change, whether it's my code or my wife's blog post, takes the same path:

sequenceDiagram
    actor A as Abhi or Pallavi
    participant GH as GitHub Actions
    participant IAM as AWS IAM (OIDC)
    participant CDK as AWS CDK
    participant Site as Live site

    A->>GH: Open a pull request, or save in /admin
    Note over A: /admin sign-in is Cognito,<br/>with optional MFA
    GH->>GH: Compliance lint, typecheck, 106 tests
    GH->>GH: Build, Playwright, Lighthouse, link check
    alt Any check fails
        GH-->>A: Blocked, nothing ships
    else Every check passes
        GH->>IAM: Exchange the GitHub OIDC token
        IAM-->>GH: 1-hour credentials, main branch only
        GH->>CDK: Deploy preview, then production
        CDK->>Site: Update stacks, sync S3, refresh the cache
        GH->>Site: Smoke tests (home, redirects, API)
        Site-->>GH: Healthy
    end
    Note over Site: An uptime probe checks it every 5 minutes

The quality gates block a release if any of these fail:

  1. Compliance lint. Health advertising has rules, so words like "cure" or "guaranteed" fail the build.
  2. Typecheck and 106 automated tests, covering Lambdas, CDK stacks, redirects and pages
  3. Playwright on desktop and mobile, including accessibility and SEO checks
  4. Lighthouse budgets: performance ≥ 0.90, accessibility ≥ 0.95
  5. A broken-link check across every page

A blog post saved in /admin is live in about 5–8 minutes, already tested. If something slips through, the S3 bucket is versioned and a git revert redeploys the previous version.


The six pillars, one table

Pillar What I did
Operational excellence Everything in CDK. CI/CD on every merge. A runbook entry for every alarm. Architecture decisions recorded as ADRs.
Security OIDC instead of access keys, least-privilege IAM, private S3 behind CloudFront, TLS 1.2+ and HSTS, Cognito MFA, signed webhooks, secrets in SSM
Reliability EventBridge → SQS → DLQ, uptime probe every 5 minutes, versioned S3, DynamoDB PITR, atomic DNS cutover with a rollback script
Performance efficiency Static HTML from CloudFront edges with HTTP/3. Almost no JavaScript shipped. Lighthouse ≥ 0.90 enforced in CI.
Cost optimization Pay-per-use serverless, no NAT gateways or idle servers. A US$20 budget alert at 80%. Polling TidyCal instead of paying for Zapier.
Sustainability Nothing runs when nobody visits. ARM (Graviton) Lambdas, 1-month log retention, old S3 versions expire after 30 days.

What it costs

Item Est. US$/month
Route 53 hosted zone 0.50
CloudFront + S3 0–1.00
CloudWatch (11 alarms, logs) 0.10–1.00
Lambda, API Gateway, DynamoDB, SQS, EventBridge cents (free tier)
Cognito, ACM certificate, SSM 0
Total ~2–5

Before: US$40/month on Base44. After: under US$5. That's a saving of about US$420 a year, with better security, monitoring and SEO than before.

Email, booking and payment tools cost the same on either platform, so they're left out.


Lessons for technical leaders

  • Small doesn't mean sloppy. The same habits that protect a bank protect a clinic: no stored keys, least privilege, alarms, tests. Most of them cost nothing.
  • Spend where it matters. I skipped AWS WAF and Synthetics canaries, and spent the effort on a queue and a DLQ instead. That's where the business risk actually was.
  • Automate the people, not just the servers. The best feature I built is the /admin editor. My wife publishes on her own, and the pipeline keeps her safe.
  • Write decisions down. Seven short ADRs mean future me knows why polling beat Zapier and why the DNS cutover took two phases.

If you're paying a no-code platform for something that's mostly static pages, take a look at the bill. A weekend of CDK might pay for itself within a month.

Questions or want the CDK patterns? Find me in the AWS Community.

來源:DEV Community · dev.to