serverless-application-model icon indicating copy to clipboard operation
serverless-application-model copied to clipboard

Proposal: Static Websites

Open brettstack opened this issue 5 years ago • 18 comments

SAM should provide a way to easily create static websites hosted on S3 and CloudFront. The purpose of this Issue is to gather requirements from the community to ensure we address primary use-cases.

Requirements:

  1. Create an S3 Bucket configured with WebsiteConfiguration
    1. Option for enabling S3 redirect configuration for clean SPA routes
    2. Allow specifying CodeUri which points to the assets directory to upload to S3.
      1. Currently, Lambda Functions get uploaded to an existing S3 Bucket prior to SAM transformation, whereas the S3 bucket for websites will be created within the stack. One option is to upload to an existing S3 Bucket (the same one used for Lambda and APIs) and have a CloudFormation Custom Resource for copying to the Website S3 bucket.
      2. The same Custom Resource could be used for deployments (invalidate CloudFront cache)
      3. CodeUri should be optional to allow users to handle UI deployments external to SAM.
      4. We may decide to punt the CodeUri/Deployment story as a follow-up so that we can deliver the infrastructure story first.
  2. Create a CloudFront distribution to provide caching, edge nodes, custom domain support, etc.
    1. CloudFront distribution should provide opinionated defaults, but all properties should be configurable by end user
  3. Allow for specifying a custom domain name
    1. Route53 configuration
    2. ACM Certificate (optionally pass in your own)
    3. Support for redirecting non-www to www

Please describe your use case and let us know how SAM could make it easier for you to create websites.

brettstack avatar Oct 11 '18 20:10 brettstack

This would be very helpful currently i have already done this by using CodePipeline, CodeBuild and CFN resources with CustomResources as followed:

  • CodeBuild packages the web application and is used as OutputArtifacts
  • The template deploys with a SourceBucketName & SourceObjectKey parameter that points to the OutputArtifact
  • The templates create a bunch of resources like S3, CloudFront & Cognito stuff
  • Custom resource accept variable like: IdentityPoolId, UserPoolId, UserPoolWebClientId, AppSyncEndpoint, CloudFrontDistributionId
  • Custom resource will
    • Download the and Unzip
    • Merge/override configuration options based on the passed variable
    • Compare the "local" files with the one on S3, if there are files on S3 that are not in the local copy mark it as "toBeRemoved"
    • Upload all files except the index.html
    • Upload index.html (index.html references to specific versions are uploaded in the previous step)
    • Invalidate core files: (index.html, settings.js, etc)
    • Remove the "toBeRemoved" files

These steps are used by web applications that are build for Aurelia or Angular they have a build system that point to a specific version in the index.html file: /app.[SOME_HASH].bundle.js.

Nr18 avatar Oct 12 '18 12:10 Nr18

Ideally, for me, I'd like SAM to handle the bucket content and not any of the configuration. This has use cases past just static web content.

Something fairly simple such as:

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Resources:
  WebBucket:
    Type: AWS::S3:Bucket

  WebBucketContent:
    Type: AWS::Serverless::BucketContent
    Properties:
      BucketName: !Ref WebBucket
      ContentUri: ./path/to/content/dir
      SyncOptions: # Optional: Default behavior is to sync the Bucket's content with the artifact exactly
        - IgnoreExisting # Do not overwrite existing files in the Bucket
        - Preserve # Do not delete files in the Bucket not in the artifact

During the package process the ContentUri location would be zipped up and uploaded to the S3 Bucket SAM is sending artifacts to and the value replaced with the S3 URI - identically to how Lambda packages are handled.

Then during deployment the custom CloudFormation resource can pull in that content artifact and perform the appropriate sync operation with the target bucket.

brysontyrrell avatar Oct 12 '18 16:10 brysontyrrell

+1

bjornadolfsson avatar Oct 15 '18 06:10 bjornadolfsson

I like the spirit behind this idea! A very common task that many orgs have to do frequently and there are multiple steps involved.

I would suggest one more feature to add to your list:

  • Custom Header Injection The ability to automatically setup a L@E function on the CDN that can add headers to the response from the S3 origin prior to being cached. This is a pretty common task now for static sites and one that AWS has blogged about in the past for a lambda@edge use case: https://aws.amazon.com/blogs/networking-and-content-delivery/adding-http-security-headers-using-lambdaedge-and-amazon-cloudfront/

rmmeans avatar Oct 15 '18 19:10 rmmeans

These are great. Thanks for the input so far!

brettstack avatar Oct 22 '18 14:10 brettstack

I think a CloudFront OAI is preferrable to using a WebsiteConfiguration on an S3 bucket.

kadrach avatar Oct 30 '18 22:10 kadrach

I'd like CodeUri to be able to be either a list, overlaying multiple directories into the same space, or a map, with the keys being prefixes.

I'm on board with @brysontyrrell that web hosting is less important to me than just deployment of objects.

benkehoe avatar Nov 09 '18 19:11 benkehoe

Every single page webapp and static generators could benefit (Angular, React, Ember, Jekyll, ... )

faermanj avatar Nov 15 '18 19:11 faermanj

One of the things that i have ran into is that i needed to set the ContentType to text/html and so on else CloudFront will force download the file from S3.

@brettstack do you have a general idea how this feature will work in SAM and what we can do to help out?

Nr18 avatar Nov 16 '18 13:11 Nr18

@Nr18 I have a general idea as I've done this setup before. This repo by Eric Hammond is similar to what we have in mind https://github.com/alestic/aws-git-backed-static-website.

There was also the recently released Amplify Console https://aws.amazon.com/about-aws/whats-new/2018/11/announcing-aws-amplify-console/ so we want to consider this as an option, e.g you can set Provider to "AmplifyConsole" to use that, or leave it blank to default to having SAM create all the necessary resources for you (S3, CloudFront, Route53, etc.) if you want more control.

We're still gathering feedback and customer requirements, but I will tell you that this is one feature I'm particularly excited about and will check back in when I have an RFC.

brettstack avatar Nov 27 '18 18:11 brettstack

Would this be applicable to static content for dynamic websites? I recently ported our registration system to a "razor pages" (lightweight dotnet core) project running as a lambda. We're trialing this at the moment as it potentially provides a much simpler way of deploying some of our sites, but serving assets (images, fonts, pdfs) via lambda is a bit wasteful. It would be great if there was an in built way to split the hosting of dynamic content and static content.

AlexHarper avatar Dec 12 '18 14:12 AlexHarper

Maybe it's worth wrapping this into a serverless transform? https://github.com/serverlesspub/cloudformation-deploy-to-s3/blob/master/example/template.yml

gojko avatar Jan 25 '19 11:01 gojko

I know this is a proposal for Static Websites, elaborating further on @faermanj's suggestion, I think it could very well extend to following architecture:

  • A nested Stack to host assets from a Single Page Application (SPA) created with S3 + CloudFront
  • Another nested RESTful API / graphql stack that exports the API Endpoint created with API Gateway + Lambda.
  • A top level stack that nests the aforementioned stacks and the S3 + Cloudfront stack that DependsOn API Gateway + Lambda stack to finish and export the API Gateway Endpoint that could be passed on to the S3+Cloudfront stack. This top level stack can share S3 buckets across the nested stacks conserving.

At my organization, I am trying to push for SAM based deployment for our Full Stack SPA/MPA based Javascript Projects. IMHO a ton of projects that could easily be refactored from Ec2 /ALB based deployments to serverless if the above can be achieved.

vikikamath avatar Jul 22 '19 04:07 vikikamath

Hello! Could you elaborate on the status of this feature please? I'm looking into AWS cloud infrastructure for my next project and I'm choosing between AWS SAM and Serverless Framework to manage it. And I'm a bit surprised that SAM doesn't provide a straightforward way to deploy static content (by looking at the docs at least).

slavafomin avatar Sep 11 '19 18:09 slavafomin

Thanks for reaching out @slavafomin. We recently finalized our design for custom domains (2 and 3 in this proposal) and it will certainly help towards this feature. Please take a look at Custom Domains Project Board to track our progress on it.

praneetap avatar Sep 11 '19 20:09 praneetap

Related to this, I created a SAM project called https://github.com/smoketurner/sam-cdn and is available within the Serverless Application Repository at https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:860114833029:applications~cloudfront-cdn that aims to simplify this pattern I was repeating over and over again.

This pattern allows you to plugin API Gateway or AppSync with a custom domain fairly easily and using CloudFront + S3 for static content serving.

jplock avatar Jan 28 '20 19:01 jplock

In the API Gateway Developer Portal, we're currently copying it into a simple lambda so we can upload it to an S3 bucket, so we can support one-click install through SAR. Something like CodeUri would be far more ideal, since we could avoid the need for the intermediate lambda that just does a recursive tree walk.

amazon-meaisiah avatar Mar 24 '20 23:03 amazon-meaisiah

@praneetap thank you for looking into this feature! It would be of great help if you could please provide an update on this

rockyadi avatar Apr 30 '20 12:04 rockyadi