cfn-forge
Version:
CloudFormation deployment automation tool with git-based workflows
360 lines (317 loc) • 10.5 kB
YAML
name: static-website
description: Static website hosting with S3, CloudFront, and custom domain support
version: 1.0.0
author: CFN-Forge
cfnForgeVersion: 1.0.0
variables:
projectName:
prompt: "Project name"
default: "my-static-site"
description:
prompt: "Project description"
default: "A static website hosted on AWS"
domainName:
prompt: "Custom domain name (optional, press enter to skip)"
default: ""
enableSPA:
prompt: "Enable Single Page Application routing?"
default: "false"
type: "boolean"
files:
include:
- "**/*"
exclude:
- "template.yaml"
- ".git/**"
- "node_modules/**"
structure:
cloudformation.yaml: |
AWSTemplateFormatVersion: '2010-09-09'
Description: {{description}}
Parameters:
Environment:
Type: String
Default: dev
AllowedValues: [dev, staging, prod]
Description: Environment name
Conditions:
HasCustomDomain: !Not [!Equals ["{{domainName}}", ""]]
IsSPA: !Equals ["{{enableSPA}}", "true"]
Resources:
# S3 Bucket for website hosting
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${AWS::StackName}-website-${Environment}"
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: !If [IsSPA, "index.html", "error.html"]
PublicReadPolicy:
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal: "*"
Action: s3:GetObject
Resource: !Sub "${WebsiteBucket}/*"
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt WebsiteBucket.RegionalDomainName
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${OriginAccessIdentity}"
Enabled: true
DefaultRootObject: index.html
DefaultCacheBehavior:
AllowedMethods: [GET, HEAD]
Compress: true
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # Managed caching optimized
CustomErrorResponses:
- !If
- IsSPA
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
- !Ref AWS::NoValue
Aliases: !If [HasCustomDomain, [{{domainName}}], !Ref AWS::NoValue]
ViewerCertificate: !If
- HasCustomDomain
- AcmCertificateArn: !Ref SSLCertificate
SslSupportMethod: sni-only
- CloudFrontDefaultCertificate: true
PriceClass: PriceClass_100
# Origin Access Identity
OriginAccessIdentity:
Type: AWS::CloudFront::OriginAccessIdentity
Properties:
OriginAccessIdentityConfig:
Comment: !Sub "Access identity for ${AWS::StackName}"
# SSL Certificate (only if custom domain)
SSLCertificate:
Type: AWS::CertificateManager::Certificate
Condition: HasCustomDomain
Properties:
DomainName: {{domainName}}
ValidationMethod: DNS
Outputs:
WebsiteURL:
Description: Website URL
Value: !If
- HasCustomDomain
- !Sub "https://{{domainName}}"
- !Sub "https://${CloudFrontDistribution.DomainName}"
Export:
Name: !Sub "${AWS::StackName}-WebsiteURL"
CloudFrontDomainName:
Description: CloudFront Distribution Domain Name
Value: !GetAtt CloudFrontDistribution.DomainName
Export:
Name: !Sub "${AWS::StackName}-CloudFrontDomain"
S3BucketName:
Description: S3 Bucket Name
Value: !Ref WebsiteBucket
Export:
Name: !Sub "${AWS::StackName}-S3Bucket"
.cfn-forge.yaml: |
project:
name: {{projectName}}
description: {{description}}
type: static-website
environments:
dev:
stackName: "{{projectName}}-dev"
template: cloudformation.yaml
region: us-east-1
parameters:
Environment: dev
staging:
stackName: "{{projectName}}-staging"
template: cloudformation.yaml
region: us-east-1
parameters:
Environment: staging
prod:
stackName: "{{projectName}}-prod"
template: cloudformation.yaml
region: us-east-1
parameters:
Environment: prod
deployment:
packagingBucket: "{{projectName}}-deployment-artifacts"
createBucket: true
git:
watchBranches: ["main", "develop"]
deployOnPush: true
package.json: |
{
"name": "{{projectName}}",
"version": "1.0.0",
"description": "{{description}}",
"scripts": {
"build": "echo 'Add your build command here'",
"deploy": "cfn-forge deploy",
"watch": "cfn-forge watch",
"validate": "cfn-forge validate",
"sync": "aws s3 sync ./dist s3://$(cfn-forge config get bucket) --delete",
"invalidate": "aws cloudfront create-invalidation --distribution-id $(cfn-forge config get distribution) --paths '/*'"
},
"devDependencies": {
"live-server": "^1.2.2"
},
"keywords": ["static", "website", "aws", "s3", "cloudfront"],
"author": "{{author}}",
"license": "MIT"
}
public/index.html: |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{projectName}}</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 2rem;
line-height: 1.6;
color: #333;
}
.hero {
text-align: center;
padding: 3rem 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 10px;
margin-bottom: 2rem;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin: 2rem 0;
}
.feature {
padding: 1.5rem;
border: 1px solid #ddd;
border-radius: 8px;
text-align: center;
}
</style>
</head>
<body>
<div class="hero">
<h1>Welcome to {{projectName}}</h1>
<p>{{description}}</p>
</div>
<div class="features">
<div class="feature">
<h3>🚀 Fast Deployment</h3>
<p>Deploy your site to AWS with a single command using CFN-Forge</p>
</div>
<div class="feature">
<h3>⚡ Global CDN</h3>
<p>Your site is served through CloudFront for lightning fast load times</p>
</div>
<div class="feature">
<h3>🔒 HTTPS Enabled</h3>
<p>SSL certificate automatically provisioned for secure connections</p>
</div>
</div>
<footer style="text-align: center; margin-top: 3rem; color: #666;">
<p>Built with ❤️ using CFN-Forge</p>
</footer>
</body>
</html>
public/error.html: |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Not Found - {{projectName}}</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 2rem;
text-align: center;
color: #333;
}
.error-code {
font-size: 4rem;
font-weight: bold;
color: #e74c3c;
margin-bottom: 1rem;
}
</style>
</head>
<body>
<div class="error-code">404</div>
<h1>Page Not Found</h1>
<p>The page you're looking for doesn't exist.</p>
<a href="/">← Go back home</a>
</body>
</html>
README.md: |
# {{projectName}}
{{description}}
## Quick Start
1. Build your site (if needed):
```bash
npm run build
```
2. Deploy to AWS:
```bash
cfn-forge deploy
```
3. Start local development:
```bash
cfn-forge watch
```
## Project Structure
```
{{projectName}}/
public/
index.html # Main page
error.html # 404 error page
cloudformation.yaml # AWS infrastructure
.cfn-forge.yaml # CFN-Forge configuration
package.json
```
## Features
- ✅ S3 static website hosting
- ✅ CloudFront CDN for global performance
- ✅ SSL certificate (HTTPS)
- ✅ Custom domain support
- ✅ Single Page Application routing (optional)
- ✅ Automatic deployment with CFN-Forge
## Deployment
The site is automatically deployed using AWS CloudFormation through CFN-Forge.
### Environments
- **dev**: Development environment
- **staging**: Staging environment
- **prod**: Production environment
### Custom Domain
If you specified a custom domain during setup, make sure to:
1. Update your domain's DNS to point to the CloudFront distribution
2. Verify the SSL certificate in AWS Certificate Manager
### Content Updates
After deploying infrastructure, sync your content:
```bash
# Sync files to S3
npm run sync
# Invalidate CloudFront cache
npm run invalidate
```
hooks:
postInstall:
- type: message
content: "Static website template created! Add your content to the 'public' directory."