GithubHelp home page GithubHelp logo

endor / terraform-aws-next-js Goto Github PK

View Code? Open in Web Editor NEW

This project forked from millihq/terraform-aws-next-js

0.0 0.0 0.0 5.22 MB

Terraform module for building and deploying Next.js apps to AWS. Supports SSR (Lambda), Static (S3) and API (Lambda) pages.

Home Page: https://registry.terraform.io/modules/dealmore/next-js/aws

License: Apache License 2.0

HCL 12.73% TypeScript 71.11% JavaScript 12.41% Shell 3.75%

terraform-aws-next-js's Introduction

Terraform Next.js module for AWS

CI status

A zero-config Terraform module for self-hosting Next.js sites serverless on AWS Lambda.

Features

Some features are still under development, here is a list of features that are currently supported and what we plan to bring with the next releases:

Architecture

The Next.js Terraform module is designed as a full stack AWS app. It relies on multiple AWS services and connects them to work as a single application:

Architecture overview diagram

  • I. CloudFront

    This is the main CloudFront distribution which handles all incoming traffic to the Next.js application. Static assets with the prefix /_next/static/* (e.g. JavaScript, CSS, images) are identified here and served directly from a static content S3 bucket (II). Other requests are delegated to the proxy handler Lambda@Edge function (III).

  • II. S3 bucket for static content

    This bucket contains the pre-rendered static HTML sites from the Next.js build and the static assets (JavaScript, CSS, images, etc.).

  • III. Lambda@Edge proxy handler

    The proxy handler analyzes the incoming requests and determines from which source a request should be served. Static generated sites are fetched from the S3 bucket (II) and dynamic content is served from the Next.js Lambdas (V).

  • IV. API Gateway

    The HTTP API Gateway distributes the incoming traffic on the existing Next.js Lambdas (V). It uses a cost efficient HTTP API for this.

  • V. Shared Next.js Lambda functions

    These are the Next.js Lambdas which are doing the server-side rendering. They are composed, so a single lambda can serve multiple SSR-pages.

  • Terraform Next.js Image Optimization

    The image optimization is triggered by routes with the prefix /_next/image/*. It is a serverless task provided by our Terraform Next.js Image Optimization module for AWS.

  • Static Content Deployment

    This flow is only triggered when a Terraform apply runs to update the application. It consists of a dedicated S3 bucket and a single Lambda function. The bucket is only used by Terraform to upload the static content from the tf-next build command as a zip archive. The upload then triggers the Lambda which unzips the content and deploys it to the static content S3 bucket (II). Static assets from previous deployments are then marked to be expired in a certain amount of days (default 30, configurable via expire_static_assets variable). After the successful deployment a CloudFront invalidation is created to propagate the route changes to every edge location.

  • Proxy Config Distribution

    This is a second CloudFront distribution that serves a special JSON file that the Proxy (III) fetches as configuration (Contains information about routes).

  • CloudFront Invalidation Queue

    When updating the app, not the whole CloudFront cache gets invalidated to keep response times low for your customers. Instead the paths that should be invalidated are calculated from the updated content. Depending on the size of the application the paths to invalidate could exceed the CloudFront limits for one invalidation. Therefore invalidations get splitted into chunks and then queued in SQS from where they are sequentially sent to CloudFront.

Usage

Add to your Next.js project

First add our custom builder to your Next.js project. It uses the same builder under the hood as Vercel does:

npm i -D tf-next     # npm or
yarn add -D tf-next  # yarn

Then you should add a new script to your package.json (Make sure it is not named build):

{
  ...
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
+   "tf-next": "tf-next build"
  }
  ...
}

tf-next build runs in a temporary directory and puts its output in a .next-tf directory in the same directory where your package.json is. The output in the .next-tf directory is all what the Terraform module needs in the next step.

Setup the Next.js Terraform module

Note: Make sure that the AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY environment variables are set when running the Terraform commands. How to create AWS Access Keys?

Adding Terraform to your existing Next.js installation is easy. Simply create a new main.tf file in the root of your Next.js project and add the following content:

# main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# Main region where the resources should be created in
# (Should be close to the location of your viewers)
provider "aws" {
  region = "us-west-2"
}

# Provider used for creating the Lambda@Edge function which must be deployed
# to us-east-1 region (Should not be changed)
provider "aws" {
  alias  = "global_region"
  region = "us-east-1"
}

module "tf_next" {
  source = "dealmore/next-js/aws"

  providers = {
    aws.global_region = aws.global_region
  }
}

output "cloudfront_domain_name" {
  value = module.tf_next.cloudfront_domain_name
}

To deploy your app to AWS simply run the following commands:

npm run tf-next   # Build the Next.js app
yarn tf-next      # Same command when using yarn

# Expose your AWS Access Keys to the current terminal session
# Only needed when running Terraform commands
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

terraform init    # Only needed on the first time running Terraform

terraform plan    # (Optional) See what resources Terraform will create
terraform apply   # Deploy the Next.js app to your AWS account

> Apply complete!
>
> Outputs:
>
> cloudfront_domain_name = "xxxxxxxxxxxxxx.cloudfront.net"

After the successful deployment your Next.js app is publicly available at the CloudFront subdomain from the cloudfront_domain_name output.

Deployment with Terraform Cloud

When using this module together with Terraform Cloud make sure that you also upload the build output from the tf-next task. You can create a .terraformignore in the root of your project and add the following line:

# .terraformignore
+  !**/.next-tf/**

Examples

  • Complete
    Complete example with SSR, API and static pages.
  • Static
    Example that uses static pages only (No SSR).
  • Next Image
    Images are optimized on the fly by AWS Lambda.
  • Existing CloudFront
    Use the module together with an existing CloudFront distribution that can be fully customized.
  • Custom Domain
    Use the module with your own domain from Route 53.

Requirements

Name Version
terraform >= 0.13
aws >= 3.43.0
random >= 2.3.0

Providers

Name Version
aws >= 3.43.0
random >= 2.3.0

Inputs

Name Description Type Default Required
cloudfront_cache_key_headers Header keys that should be used to calculate the cache key in CloudFront. list(string)
[
"Authorization"
]
no
cloudfront_create_distribution Controls whether the main CloudFront distribution should be created. bool true no
cloudfront_external_arn When using an external CloudFront distribution provide its arn. string null no
cloudfront_external_id When using an external CloudFront distribution provide its id. string null no
cloudfront_origin_headers Header keys that should be sent to the S3 or Lambda origins. Should not contain any header that is defined via cloudfront_cache_key_headers. list(string) [] no
cloudfront_price_class Price class for the CloudFront distributions (main & proxy config). One of PriceClass_All, PriceClass_200, PriceClass_100. string "PriceClass_100" no
create_image_optimization Controls whether resources for image optimization support should be created or not. bool true no
debug_use_local_packages Use locally built packages rather than download them from npm. bool false no
deployment_name Identifier for the deployment group (alphanumeric characters, underscores, hyphens, slashes, hash signs and dots are allowed). string "tf-next" no
expire_static_assets Number of days after which static assets from previous deployments should be removed from S3. Set to -1 to disable expiration. number 30 no
image_optimization_lambda_memory_size Amount of memory in MB the worker Lambda Function for image optimization can use. Valid value between 128 MB to 10,240 MB, in 1 MB increments. number 2048 no
lambda_attach_to_vpc Set to true if the Lambda functions should be attached to a VPC. Use this setting if VPC resources should be accessed by the Lambda functions. When setting this to true, use vpc_security_group_ids and vpc_subnet_ids to specify the VPC networking. Note that attaching to a VPC would introduce a delay on to cold starts bool false no
lambda_environment_variables Map that defines environment variables for the Lambda Functions in Next.js. map(string) {} no
lambda_memory_size Amount of memory in MB a Lambda Function can use at runtime. Valid value between 128 MB to 10,240 MB, in 1 MB increments. number 1024 no
lambda_policy_json Additional policy document as JSON to attach to the Lambda Function role string null no
lambda_role_permissions_boundary ARN of IAM policy that scopes aws_iam_role access for the lambda string null no
lambda_runtime Lambda Function runtime string "nodejs14.x" no
lambda_timeout Max amount of time a Lambda Function has to return a response in seconds. Should not be more than 30 (Limited by API Gateway). number 10 no
next_tf_dir Relative path to the .next-tf dir. string "./.next-tf" no
tags Tag metadata to label AWS resources that support tags. map(string) {} no
use_awscli_for_static_upload Use AWS CLI when uploading static resources to S3 instead of default Bash script. Some cases may fail with 403 Forbidden when using the Bash script. bool false no
vpc_security_group_ids The list of Security Group IDs to be used by the Lambda functions. lambda_attach_to_vpc should be set to true for these to be applied. list(string) [] no
vpc_subnet_ids The list of VPC subnet IDs to attach the Lambda functions. lambda_attach_to_vpc should be set to true for these to be applied. list(string) [] no

Outputs

Name Description
cloudfront_custom_error_response Preconfigured custom error response the CloudFront distribution should use.
cloudfront_default_cache_behavior Preconfigured default cache behavior the CloudFront distribution should use.
cloudfront_default_root_object Preconfigured root object the CloudFront distribution should use.
cloudfront_domain_name Domain of the main CloudFront distribution (When created).
cloudfront_hosted_zone_id Zone id of the main CloudFront distribution (When created).
cloudfront_ordered_cache_behaviors Preconfigured ordered cache behaviors the CloudFront distribution should use.
cloudfront_origins Preconfigured origins the CloudFront distribution should use.
static_upload_bucket_id n/a

Known issues

Under the hood this module uses a lot of Vercel's build pipeline. So issues that exist on Vercel are likely to occur on this project too.

  • Stack deletion (terraform destroy) fails on first run (terraform-provider-aws#1721)

    This is intentional because we cannot delete a Lambda@Edge function (Used by proxy module) in a synchronous way. It can take up to an hour for AWS to unbind a Lambda@Edge function from it's CloudFront distribution even when the distribution is already destroyed.

    Workaround:

    After running the initial terraform destroy command (that failed) wait ~1 hour and run the command again. This time it should run successfully and delete the rest of the stack.

  • Initial apply fails with error message Error: error creating Lambda Event Source Mapping (#138)

    There is some race condition when the permissions are created for the static deployment Lambda. This should only happen on the first deployment.

    Workaround:

    You should be able to runterraform apply again and the stack creation would progreed without this error.

License

Apache-2.0 - see LICENSE for details.

Note: All sample projects in examples/* are licensed as MIT to comply with the official Next.js examples.

terraform-aws-next-js's People

Contributors

ofhouse avatar ijjk avatar styfle avatar timer avatar andybitz avatar tootallnate avatar dependabot[bot] avatar thasophearak avatar maael avatar dav-is avatar lucleray avatar timneutkens avatar rdev avatar leo avatar jamesla avatar underyx avatar arunoda avatar flybayer avatar chamilad avatar jeantil avatar lcswillems avatar nimish-gupta avatar shuding avatar thecallsign avatar nkzawa avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.