Last active
June 27, 2020 07:57
-
-
Save alexnederlof/809680a2a2fdb59ed6339db3c7e67ab3 to your computer and use it in GitHub Desktop.
Cloudformation template for S3, Cloudfront, Letsencrypt stack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Deploy with | |
# aws cloudformation update-stack --stack-name your-static-site --template-body file://cloudfront.yaml | |
AWSTemplateFormatVersion: 2010-09-09 | |
Description: Stack for static website hosting | |
Parameters: | |
IamCertificateId: | |
Type: String | |
Description: Use the ID from from the create-certificate.sh script | |
Default: xslidfjlskdfj | |
DomainName: | |
Type: String | |
Default: yoursite.yourdomain.com. | |
Route53HostedZone: | |
Type: String | |
Default: yourdomain.com. | |
Resources: | |
# Demo bucket | |
WebsiteBucket: | |
Type: AWS::S3::Bucket | |
Properties: | |
BucketName: !Ref DomainName | |
AccessControl: "PublicRead" | |
WebsiteConfiguration: | |
# If you do javascript routing | |
# the URLs do exist on the server, so | |
# we always return index.html for any route | |
# the server doesn't have as a file | |
ErrorDocument: index.html | |
IndexDocument: index.html | |
BucketPolicy: | |
Type: AWS::S3::BucketPolicy | |
Properties: | |
PolicyDocument: | |
Statement: | |
- Sid: PublicReadForGetBucketObjects | |
Effect: Allow | |
Principal: "*" | |
Action: "s3:GetObject" | |
Resource: !Join | |
- "" | |
- - "arn:aws:s3:::" | |
- !Ref WebsiteBucket | |
- /* | |
Bucket: !Ref WebsiteBucket | |
CloudFront: | |
Type: AWS::CloudFront::Distribution | |
DependsOn: | |
- WebsiteBucket | |
Properties: | |
DistributionConfig: | |
Origins: | |
- DomainName: | |
!Join [".", [!Ref DomainName, "s3.amazonaws.com"]] | |
Id: !Ref DomainName | |
S3OriginConfig: {} | |
Enabled: "true" | |
HttpVersion: "http2" | |
DefaultRootObject: index.html | |
# This price class is enough for EU and US, but not the rest of the world | |
PriceClass: "PriceClass_100" | |
Aliases: | |
- !Ref DomainName | |
DefaultCacheBehavior: | |
# Disclaimer: probably, there's better ways to configure cloudformation | |
# But I'm not cloudformtion expert. If you have any recommendations, | |
# please leave them in the comments! | |
Compress: true | |
AllowedMethods: | |
- GET | |
- HEAD | |
TargetOriginId: !Ref DomainName | |
ForwardedValues: | |
QueryString: "true" | |
Cookies: | |
Forward: none | |
# Make the world a better place: force the usage of HTTPS: | |
ViewerProtocolPolicy: redirect-to-https | |
ViewerCertificate: | |
IamCertificateId: !Ref IamCertificateId | |
SslSupportMethod: sni-only | |
MinimumProtocolVersion: TLSv1.2_2018 | |
CustomErrorResponses: | |
- ErrorCachingMinTTL: 86400 | |
# again, setup the 404 paths to return | |
# a 200 with index.html to allow javascript routing | |
ErrorCode: 404 | |
ResponseCode: 200 | |
ResponsePagePath: "/index.html" | |
WebsiteDNSName: | |
Type: AWS::Route53::RecordSetGroup | |
Properties: | |
HostedZoneName: !Ref Route53HostedZone | |
RecordSets: | |
- Name: !Ref DomainName | |
Type: A | |
AliasTarget: | |
HostedZoneId: Z2FDTNDATAQYW2 # This means Cloudfront | |
DNSName: !GetAtt [CloudFront, DomainName] | |
Outputs: | |
BucketLocation: | |
Description: Sync the web-ui code here | |
Value: !Ref WebsiteBucket | |
Domain: | |
Value: !Ref DomainName | |
CloudFrontName: | |
Description: "Cloudfront's internal URL" | |
Value: !GetAtt [CloudFront, DomainName] | |
CloudFrontId: | |
Description: "Cloudfront ID" | |
Value: !Ref CloudFront |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# For this script to work you need the python packages: | |
# pip install certbot certbot-dns-route53 | |
# If you don't have python/pip installed, or if you are | |
# on windows, you can also just run this from a python | |
# docker container! Just don't forget to add your .aws | |
# credentials to the docker container so you can deploy | |
# the script | |
domain=your.website.com # Or whatever domain you desire | |
[email protected] # You will receive domain expire messages on this email | |
# This command will take a couple of minutes, because it uses | |
# DNS from route-53 to prove you own the domain | |
certbot certonly \ | |
--config-dir /tmp/cert/config \ | |
--work-dir /tmp/cert/work \ | |
--logs-dir /tmp/cert/logs \ | |
-n --agree-tos --email $email \ | |
--dns-route53 \ | |
-d $domain | |
# Upload the certificate to AWS. Save the response! You'll need the ServerCertificateId! | |
aws iam upload-server-certificate \ | |
--server-certificate-name $domain \ | |
--certificate-body file:///tmp/cert/config/live/$domain/cert.pem \ | |
--private-key file:///tmp/cert/config/live/$domain/privkey.pem \ | |
--certificate-chain file:///tmp/cert/config/live/$domain/chain.pem \ | |
--path /cloudfront/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
target=/path/to/your/website | |
bucket=s3://your-bucket-name | |
distribution=distirbutionid # Is returned by the cloudformation stack | |
# This script assumes a `create-react-app` where static resources | |
# (resources that can be cached "forever" are in the /static/ folder. | |
# Other resources should not be cached forever, hence we deploy like this: | |
# First the non-static assets. Clients should not cache these. | |
aws s3 sync $target/ $bucket \ | |
--cache-control "no-cache" \ | |
--exclude "static/*" \ | |
--exclude ".DS_Store" \ | |
--delete | |
# The static assests can be cached for a long time | |
aws s3 sync $target/static $bucket/static \ | |
--cache-control "public, max-age=2.592000, must-revalidate" \ | |
--exclude ".DS_Store" \ | |
--delete | |
# CloudFront has an internal cache as well, to be sure people get the latest | |
# Index.html, force cloudformation to evict its caches for index.html. | |
# You can add other resources here if you notice any caching problems. | |
aws cloudfront create-invalidation --distribution-id $distribution --paths / /index.html |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment