Deploying a Hedgerules site requires five stages. Stages 1 and 4 are initial setup (CloudFormation); stages 2, 3, and 5 run on every content update.
| Stage | Object | Notes |
|---|---|---|
| 1. CloudFormation stack | S3 content bucket | Static file storage; no website hosting needed |
| S3 bucket policy | Grants CloudFront OAC read access | |
| Origin Access Control | Grants CloudFront access to S3 | |
| ACM Certificate | DNS validation for custom domain | |
| ACM validation DNS record | CNAME proving domain ownership; can be Route53 or out-of-band | |
| CloudFront KVS: redirects | Empty store; entries managed in stage 3 | |
| CloudFront KVS: headers | Empty store; entries managed in stage 3 | |
| IAM deployment group | Permissions for S3, CloudFront, KVS, and Function APIs | |
2. hugo |
_hedge_redirects.txt |
Alias redirects; hedgeredirects output format |
_hedge_headers.json |
Path–header map; hedgeheaders output format |
|
| Directory structure | Scanned by hedgerules to produce /path → /path/ redirects |
|
| Site files (HTML, CSS, JS, images) | Used by stage 5 | |
3. hedgerules deploy |
Viewer-request function | Created on first deploy, code updated on each subsequent deploy |
| Viewer-response function | Created on first deploy, code updated on each subsequent deploy | |
| Redirects KVS entries | Convergent sync against KVS from stage 1 | |
| Headers KVS entries | Convergent sync against KVS from stage 1 | |
| 4. CloudFormation stack | CloudFront Distribution | References S3 bucket from stage 1 and functions from stage 3 |
| Route53 DNS record | Alias to distribution | |
5. hugo deploy |
S3 objects | Uploaded to bucket from stage 1 |
| CloudFront cache invalidation | Invalidates distribution from stage 4 |
We recommend CloudFormation for stages 1 and 4,
but anything that can deploy resources to AWS works fine:
the AWS web console,
the aws commandline program,
Terraform, etc.
For the purposes of most of our docs,
we assume CloudFormation.
CloudFormation cannot own the CloudFront Functions because hedgerules deploy updates their code on every deploy,
which would cause stack drift.
The same is true for any other declarative approach like Terraform.
The KVS resources are safe in CloudFormation because CloudFormation does not track individual KVS entries.
The Distribution is in a separate stack (stage 4) because it references the function ARNs,
which don’t exist until hedgerules deploy creates them in stage 3.
Out-of-band DNS#
The table above includes DNS records in stages 1 and 4, but you may want to manage DNS outside of your CloudFormation stacks. Reasons to do this include:
- Credential separation. DNS changes can redirect all traffic for a domain. Keeping DNS credentials separate from deployment credentials limits the blast radius of a compromised deploy pipeline.
- Different AWS account. The DNS zone may live in a shared infrastructure account while the site resources live in an application account.
- External DNS provider. The domain may be hosted outside of Route53 entirely.
When DNS is out of band, the two DNS-related items become manual steps:
- Stage 1: After CloudFormation creates the ACM certificate,
look up the validation CNAME
(
aws acm describe-certificate --certificate-arn <ARN>) and add it to your DNS provider. CloudFormation will pause until validation completes. - Stage 4: After CloudFormation creates the distribution,
CNAME your domain to the
DistributionDomainNameoutput.
The infra/prod/
templates use this approach:
they create the ACM certificate but expect DNS records to be managed externally.
Initial setup#
# Stage 1: base infrastructure
aws cloudformation deploy \
--template-file infra.cfn.yml \
--stack-name mysite-infra \
--capabilities CAPABILITY_NAMED_IAM
# Stage 2: build
hugo
# Stage 3: create functions + sync edge data
hedgerules deploy --site public/
# Stage 4: distribution (references functions from stage 3)
aws cloudformation deploy \
--template-file distribution.cfn.yml \
--stack-name mysite-distribution
# Stage 5: upload content
hugo deploy --target mysiteSee examples/micahrlweb/ for a complete CloudFormation template.
Each content update#
hugo # Stage 2
hedgerules deploy --site public/ # Stage 3
hugo deploy --target mysite # Stage 5The order matters:
hugomust run first because it generates_hedge_redirects.txt,_hedge_headers.json, and the directory structure thathedgerules deployreads.hedgerules deployshould probably run beforehugo deployso that redirects and headers are in place before new content goes live. This avoids a window where new pages are served without their headers or where old redirects point to not-yet-uploaded content.hugo deployruns last, uploading content to S3 and invalidating the CloudFront cache.
Re-running hedgerules deploy is always safe.
The KVS sync is convergent: it computes a diff against the existing state and only applies changes.