AWS Amplify Hosting deploy prep
- amplify.yml: build spec (preBuild npm ci with offline cache, build next build, artifacts at .next/**, cache node_modules/.next-cache/.npm). - .nvmrc: pin Node 20 so Amplify uses the same runtime as local. - AMPLIFY_DEPLOY.md: first-time walkthrough covering AWS-side setup (create app, connect GitHub via OAuth/App, branch/auto-detect), environment variable table with secret-flag guidance, smoke-test via /healthz and /api/health, optional custom domain + per-PR previews, cost estimate, and operational notes (cold starts, no static egress IPs, CloudWatch logs, secret rotation). - README deploy section: now points at both AMPLIFY_DEPLOY.md and the existing DEPLOYMENT.md (Render).
This commit is contained in:
@@ -0,0 +1,171 @@
|
|||||||
|
# Deploying to AWS Amplify Hosting
|
||||||
|
|
||||||
|
First-time walkthrough for shipping this app on AWS Amplify Hosting. Amplify
|
||||||
|
auto-detects Next.js, runs the build, and routes SSR pages + API routes
|
||||||
|
through managed Lambda behind a CloudFront CDN. The `amplify.yml` and
|
||||||
|
`.nvmrc` in this repo are the only pieces Amplify needs from the codebase.
|
||||||
|
|
||||||
|
## Before you start
|
||||||
|
|
||||||
|
- An AWS account with billing enabled. Amplify Hosting has a free tier
|
||||||
|
(1,000 build minutes + 15 GB served + 100 GB-hours of SSR Lambda per
|
||||||
|
month for the first year) — typical traffic for this app stays comfortably
|
||||||
|
inside it.
|
||||||
|
- GitHub access to `joelbrock/WebForm-mw`. Amplify connects via OAuth or a
|
||||||
|
GitHub App; either works.
|
||||||
|
- The three required CiviCRM env vars in hand: `CIVI_BASE_URL`,
|
||||||
|
`CIVI_API_KEY`, `CIVI_SITE_KEY`. Plus the optional `CIVI_HTTP_AUTH_*`
|
||||||
|
pair if CiviCRM sits behind webserver-level Basic Auth.
|
||||||
|
|
||||||
|
## Step 1 — Create the Amplify app
|
||||||
|
|
||||||
|
1. Open the Amplify console: <https://console.aws.amazon.com/amplify/>
|
||||||
|
- Pick a region near you / near CiviCRM. `us-east-1` (N. Virginia) is
|
||||||
|
the default and has the lowest cold-start latency for most setups.
|
||||||
|
2. Click **Create new app** → **Host web app**.
|
||||||
|
3. Choose **GitHub** as the source. Authorize Amplify if prompted.
|
||||||
|
The first time, AWS will install a GitHub App on your account; grant
|
||||||
|
it access just to `joelbrock/WebForm-mw` (not "all repos").
|
||||||
|
4. Pick the repo `joelbrock/WebForm-mw` and the `main` branch.
|
||||||
|
5. **App name:** something like `coop-checkin` (this becomes the
|
||||||
|
`*.amplifyapp.com` subdomain).
|
||||||
|
6. Amplify reads `amplify.yml` automatically; you do not need to edit
|
||||||
|
the build spec on this screen. Click **Next**.
|
||||||
|
|
||||||
|
## Step 2 — Environment variables
|
||||||
|
|
||||||
|
On the environment-variables screen, add the following. Required ones first:
|
||||||
|
|
||||||
|
| Variable | Value |
|
||||||
|
|---|---|
|
||||||
|
| `CIVI_BASE_URL` | e.g. `https://crm.fci.coop` |
|
||||||
|
| `CIVI_API_KEY` | mark as **Secret** (eye icon on the value field) |
|
||||||
|
| `CIVI_SITE_KEY` | mark as **Secret** |
|
||||||
|
| `NODE_ENV` | `production` |
|
||||||
|
|
||||||
|
Optional, only if relevant:
|
||||||
|
|
||||||
|
| Variable | When |
|
||||||
|
|---|---|
|
||||||
|
| `CIVI_HTTP_AUTH_USER` | CiviCRM has webserver-level Basic Auth in front of it |
|
||||||
|
| `CIVI_HTTP_AUTH_PASS` | same — mark **Secret** |
|
||||||
|
| `HEALTH_TOKEN` | gates `/api/health` in production — mark **Secret** |
|
||||||
|
| `PREVIEW_ADMIN_TOKEN` | gates `/api/preview-link` — mark **Secret** |
|
||||||
|
|
||||||
|
"Secret" values are encrypted at rest in AWS Systems Manager Parameter
|
||||||
|
Store and only injected into the build/runtime environment. They are not
|
||||||
|
visible in logs or to anyone without `amplify:*` IAM permissions.
|
||||||
|
|
||||||
|
Click **Next**, review, **Save and deploy**.
|
||||||
|
|
||||||
|
## Step 3 — First build
|
||||||
|
|
||||||
|
The first build takes about 4–6 minutes (later builds are 2–3 with cache).
|
||||||
|
You can watch progress in the **Hosting environments** view. When it
|
||||||
|
completes, three things are confirmed:
|
||||||
|
|
||||||
|
- The build succeeded → `next build` produced `.next/`.
|
||||||
|
- SSR functions deployed → API routes and dynamic pages have a Lambda
|
||||||
|
function behind them.
|
||||||
|
- The app is reachable at `https://main.<random>.amplifyapp.com`.
|
||||||
|
|
||||||
|
Smoke-test the deploy:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://main.<random>.amplifyapp.com/healthz
|
||||||
|
```
|
||||||
|
|
||||||
|
Should return `200 OK` (lightweight platform check, doesn't hit CiviCRM).
|
||||||
|
|
||||||
|
If you set `HEALTH_TOKEN`, the richer diagnostic at
|
||||||
|
`/api/health?token=<value>` will probe the CiviCRM connection itself —
|
||||||
|
useful to confirm env vars are wired correctly.
|
||||||
|
|
||||||
|
## Step 4 — Custom domain (optional)
|
||||||
|
|
||||||
|
Amplify can attach a custom domain (e.g. `check-in.fci.coop`) with
|
||||||
|
auto-issued TLS in a few minutes:
|
||||||
|
|
||||||
|
1. In the app, **Hosting** → **Custom domains** → **Add domain**.
|
||||||
|
2. Enter the apex (`fci.coop`) or a subdomain.
|
||||||
|
3. Amplify suggests DNS records (CNAME / ALIAS). Add them at your DNS
|
||||||
|
provider (Cloudflare, Route53, Namecheap, etc.).
|
||||||
|
4. Wait 5–15 minutes for validation and certificate issuance.
|
||||||
|
|
||||||
|
The `*.amplifyapp.com` URL keeps working alongside the custom domain.
|
||||||
|
|
||||||
|
## Step 5 — Per-PR previews (optional, recommended)
|
||||||
|
|
||||||
|
Amplify can build a preview environment for every pull request:
|
||||||
|
|
||||||
|
- **Hosting** → **Previews** → enable for the `joelbrock/WebForm-mw` repo.
|
||||||
|
- PRs get their own `https://pr-<num>.<random>.amplifyapp.com` URL,
|
||||||
|
posted as a comment on the PR.
|
||||||
|
- Previews inherit the main branch's environment variables unless you
|
||||||
|
override on the preview branch.
|
||||||
|
|
||||||
|
Useful for reviewing form changes against live CiviCRM DEV before merging.
|
||||||
|
|
||||||
|
## What it'll cost
|
||||||
|
|
||||||
|
Realistic estimate for this app's expected traffic (a few hundred
|
||||||
|
form/report loads per month, very modest API throughput):
|
||||||
|
|
||||||
|
- **Hosting (CDN + static)**: pennies. Free tier covers it.
|
||||||
|
- **SSR Lambda**: ~$0.05–$0.50/month depending on traffic. Each form load
|
||||||
|
triggers a couple of API calls into CiviCRM via Lambda; each call is a
|
||||||
|
short-lived invocation.
|
||||||
|
- **Build minutes**: free tier covers up to ~300 small builds/month.
|
||||||
|
|
||||||
|
Expect **<$5/month** total at launch traffic. If usage grows
|
||||||
|
significantly, the costs scale roughly linearly with Lambda invocations.
|
||||||
|
|
||||||
|
## Things to know going in
|
||||||
|
|
||||||
|
- **Cold starts.** First request after a quiet period adds 500–1500ms of
|
||||||
|
Lambda init. Subsequent requests reuse the warm container. For an
|
||||||
|
internal-use form this is fine; users see the loading state during
|
||||||
|
init.
|
||||||
|
- **Outbound IPs are not static.** Amplify SSR Lambda functions egress
|
||||||
|
through AWS-managed IPs that change. If CiviCRM has an IP allowlist
|
||||||
|
on its API, this won't work out of the box — you'd need a VPC + NAT
|
||||||
|
Gateway + Elastic IP setup (significantly more complex). Most
|
||||||
|
CiviCRM auth uses API keys, not IP allowlisting, so this usually
|
||||||
|
isn't an issue.
|
||||||
|
- **No Render-style background workers.** Amplify is request/response
|
||||||
|
only. Anything cron-shaped needs EventBridge + a separate Lambda.
|
||||||
|
The current app doesn't have background jobs, so this doesn't apply.
|
||||||
|
- **Logs live in CloudWatch.** Each SSR function has its own log group;
|
||||||
|
click into the function from the Amplify app view to jump to logs.
|
||||||
|
Retention defaults to "never expire" — switch to 30 days unless you
|
||||||
|
need more.
|
||||||
|
- **Secrets rotate manually.** No auto-rotation. To rotate
|
||||||
|
`CIVI_API_KEY`, update it in Amplify env vars → trigger a redeploy.
|
||||||
|
- **`render.yaml` is now informational.** It's still in the repo for the
|
||||||
|
Render path; Amplify ignores it. If you commit fully to Amplify and
|
||||||
|
abandon Render, the `render.yaml` and the Render section of
|
||||||
|
`DEPLOYMENT.md` can be removed.
|
||||||
|
|
||||||
|
## When something breaks
|
||||||
|
|
||||||
|
- **Build fails on `npm ci`** → usually a Node version mismatch. The
|
||||||
|
`.nvmrc` pins Node 20; if Amplify's build image doesn't have it, the
|
||||||
|
`amplify.yml` `nvm install` falls back. Open the build log, search
|
||||||
|
for "Node version".
|
||||||
|
- **Build fails on `next build`** → typecheck or lint error. Reproduce
|
||||||
|
locally with `npm run build`.
|
||||||
|
- **Site builds but routes 503** → SSR Lambda misconfig. Check the
|
||||||
|
function's CloudWatch logs for the actual error. Most common cause:
|
||||||
|
missing required env var (the app refuses to boot in production stub
|
||||||
|
mode and the `lib/env.ts` validator throws).
|
||||||
|
- **CiviCRM calls fail with 401** → API key or Basic Auth credentials
|
||||||
|
wrong. Re-check `CIVI_API_KEY` and `CIVI_HTTP_AUTH_*` in the Amplify
|
||||||
|
env-vars panel; redeploy after changes.
|
||||||
|
|
||||||
|
## After the first successful deploy
|
||||||
|
|
||||||
|
- Bookmark the Amplify app URL and the CloudWatch log group.
|
||||||
|
- Run the email/link smoke test from `EMAIL_DELIVERY.md` against the
|
||||||
|
Amplify URL to confirm `/api/preview-link` produces working tokenized
|
||||||
|
URLs end-to-end.
|
||||||
|
- Update any docs / staff runbooks pointing at the old Render URL.
|
||||||
@@ -105,11 +105,11 @@ works while in stub mode. The report is at `/report?cid=1&cs=anything`.
|
|||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
|
|
||||||
The repo ships with `render.yaml` for [Render](https://render.com) and a
|
The repo ships with `amplify.yml` for [AWS Amplify Hosting](https://aws.amazon.com/amplify/)
|
||||||
detailed `DEPLOYMENT.md` covering Render specifically. The app is a
|
(see `AMPLIFY_DEPLOY.md` for a first-time walkthrough) and `render.yaml`
|
||||||
|
for [Render](https://render.com) (see `DEPLOYMENT.md`). The app is a
|
||||||
standard Next.js 16 App Router project and runs anywhere Node 20+ can
|
standard Next.js 16 App Router project and runs anywhere Node 20+ can
|
||||||
run `next start` — Vercel, AWS Amplify Hosting, App Runner, Fly,
|
run `next start` — Vercel, App Runner, Fly, self-hosted, etc.
|
||||||
self-hosted, etc.
|
|
||||||
|
|
||||||
Build + start:
|
Build + start:
|
||||||
|
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
version: 1
|
||||||
|
applications:
|
||||||
|
- frontend:
|
||||||
|
phases:
|
||||||
|
preBuild:
|
||||||
|
commands:
|
||||||
|
- nvm use $(cat .nvmrc) || nvm install $(cat .nvmrc)
|
||||||
|
- npm ci --cache .npm --prefer-offline
|
||||||
|
build:
|
||||||
|
commands:
|
||||||
|
- npm run build
|
||||||
|
artifacts:
|
||||||
|
baseDirectory: .next
|
||||||
|
files:
|
||||||
|
- '**/*'
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- node_modules/**/*
|
||||||
|
- .next/cache/**/*
|
||||||
|
- .npm/**/*
|
||||||
Reference in New Issue
Block a user