Guide ·

An LLM built you a website. Now what?

Written by an AI. Claude, Anthropic's AI model, wrote these steps and the code they point to, working with Paul in Claude Code. The steps are confirmed working: this site, skunkyard.com, went live with them on November 1, 2026.

You have a folder of HTML, CSS, and JavaScript that an LLM wrote for you, and a domain name. This guide puts that folder on your domain with HTTPS, and redeploys it every time you push to GitHub. It runs on AWS with no servers and no database, for about $0.50 a month at hobby traffic.

Not on GitHub yet? Start with Ship your site from Claude Code, which gets your files there and sets up the routine this guide deploys from.

What you end up with

Hand it to your LLM

The code is open source in athinktank/skunkyard, under aws-static-site/. Its README is written for an LLM to follow. Open your site's repository in an AI coding tool, such as Claude Code, and give it a prompt like this:

Read https://github.com/athinktank/skunkyard/tree/main/aws-static-site
and set up this repository to deploy to AWS the same way.
My domain is example.com and my GitHub repository is me/my-site.
My static files are in the site/ folder.
Walk me through each step that needs my AWS or GitHub credentials,
and don't run AWS commands yourself.

The LLM copies the infrastructure code and workflow into your repository and fills in your domain. The steps that need your credentials stay with you.

The steps

These are the steps your LLM walks you through. You need an AWS account, a GitHub repository, the AWS CLI, and the GitHub CLI.

1. Run the bootstrap once

GitHub can't sign in to AWS until a role exists for it, so one CloudFormation template creates the role, the Route 53 hosted zone, and a bucket for Pulumi's state. Run it with credentials that can create IAM roles.

First look up the subject GitHub puts in its sign-in tokens for your repository:

gh api repos/OWNER/REPO/actions/oidc/customization/sub

If use_immutable_subject is true, then use the sub_claim_prefix value without the leading repo:, such as me@1234/my-site@5678. Otherwise use OWNER/REPO.

aws cloudformation deploy --region us-east-1 \
  --stack-name my-site-bootstrap \
  --template-file infra/bootstrap.yaml \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides DomainName=example.com GitHubRepo=me@1234/my-site@5678

2. Point your domain at Route 53

Read the stack's outputs, then set the four NameServers at your registrar.

aws cloudformation describe-stacks --region us-east-1 \
  --stack-name my-site-bootstrap --query "Stacks[0].Outputs"

Confirm the registry has them. Ask the .com servers directly, because your own network can cache the old answer for hours:

dig @a.gtld-servers.net example.com NS +norec

3. Give GitHub the outputs

gh variable set AWS_DEPLOY_ROLE_ARN --body "<DeployRoleArn>"
gh variable set PULUMI_STATE_BUCKET --body "<StateBucket>"
gh secret set PULUMI_CONFIG_PASSPHRASE

The passphrase encrypts secrets in Pulumi's state. Keep a copy in your password manager.

4. Push to main

The deploy workflow runs pulumi up, uploads your files, and clears the CloudFront cache. The first run takes about 5 minutes while CloudFront sets up. Every push to main after that redeploys.

Problems we hit, so you don't

"Not authorized to perform sts:AssumeRoleWithWebIdentity"
GitHub's token subject didn't match the role. New repositories can use an immutable subject with account and repository IDs. Step 1 shows how to look it up.
CloudFormation says "No changes to deploy"
aws cloudformation deploy keeps a parameter's earlier value unless you pass a new one with --parameter-overrides. Changing the template's default does nothing.
The site works everywhere except your house
Your router cached "no such record" from before the deploy. It expires on its own. Flushing your computer's DNS cache doesn't help, because the router asks again for you and serves the cached answer.
Your email stopped
Moving name servers drops every record at your old DNS host, including mail records. Copy them to Route 53 first, or publish a null MX record if the domain has no mail.

What it costs

Prices from AWS's pricing pages, checked November 1, 2026, for US East. They leave out the 12-month free tier new AWS accounts get. They include CloudFront's always-free tier, which doesn't expire: 1 TB of transfer, 10 million requests, and 2 million CloudFront Function runs a month.

ItemPrice
Domain nameYour registrar's yearly fee
Route 53 hosted zone$0.50 a month
Route 53 lookupsFree for the site's records, which are aliases to CloudFront; $0.40 per million for others
S3 storage$0.023 per GB a month; $0.005 per 1,000 uploads
CloudFront transferFree to 1 TB a month, then $0.085 per GB
CloudFront requestsFree to 10 million a month, then $0.01 per 10,000
CloudFront Function (clean URLs)Free to 2 million runs a month, then $0.10 per million
Cache clears after a deployFree to 1,000 paths a month; a deploy uses 1
HTTPS certificateFree
PulumiFree; its state is a file in your S3 bucket
GitHub ActionsFree on public repositories; 2,000 minutes a month on private ones, and a deploy takes 1 to 5 minutes

Monthly totals, assuming each page view loads 5 files and 200 KB:

TrafficRequestsTransferMonthly cost
10,000 page views50,0002 GB$0.50
500,000 page views2.5 million100 GB$0.55
5 million page views25 million1 TB$17.80

The CloudFront Function runs on every request, so its 2 million free runs are the first limit you pass. Past 1 TB a month, transfer becomes the largest cost.