├── .github ├── CODEOWNERS └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── README.md ├── basic-auth ├── .eslintrc.json ├── .gitignore ├── .yarnrc.yml ├── README.md ├── app │ ├── api │ │ └── route.ts │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── credentials.tpl.yaml ├── next.config.js ├── package.json ├── postcss.config.js ├── providers.tf ├── public │ ├── next.svg │ └── vercel.svg ├── tailwind.config.js ├── terragrunt.hcl ├── tsconfig.json └── yarn.lock ├── maintainance-page-default-action ├── .eslintrc.json ├── .gitignore ├── .yarnrc.yml ├── README.md ├── app │ ├── api │ │ └── route.ts │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── next.config.js ├── package.json ├── postcss.config.js ├── providers.tf ├── public │ ├── next.svg │ └── vercel.svg ├── static │ └── 503.html ├── tailwind.config.js ├── terragrunt.hcl ├── tsconfig.json └── yarn.lock ├── maintainance-page-ip-bypass ├── .eslintrc.json ├── .gitignore ├── .yarnrc.yml ├── README.md ├── app │ ├── api │ │ └── route.ts │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── ip_addresses.tpl.yaml ├── next.config.js ├── package.json ├── postcss.config.js ├── providers.tf ├── public │ ├── next.svg │ └── vercel.svg ├── static │ └── 503.html ├── tailwind.config.js ├── terragrunt.hcl ├── tsconfig.json └── yarn.lock ├── multi-zone ├── README.md ├── docs │ ├── .yarnrc.yml │ ├── README.md │ ├── app │ │ ├── api │ │ │ └── route.ts │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ ├── tailwind.config.js │ ├── tsconfig.json │ └── yarn.lock ├── home │ ├── .yarnrc.yml │ ├── README.md │ ├── app │ │ ├── api │ │ │ └── route.ts │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ ├── tailwind.config.js │ ├── tsconfig.json │ └── yarn.lock ├── providers.tf └── terragrunt.hcl ├── server-function-in-vpc ├── .npmrc ├── README.md ├── data.tf ├── eslint.config.mjs ├── main.tf ├── next.config.ts ├── outputs.tf ├── package.json ├── postcss.config.mjs ├── providers.tf ├── public │ ├── file.svg │ ├── globe.svg │ ├── next.svg │ ├── vercel.svg │ └── window.svg ├── src │ └── app │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx ├── tailwind.config.ts ├── tsconfig.json └── variables.tf ├── single-zone ├── .eslintrc.json ├── .gitignore ├── .yarnrc.yml ├── README.md ├── app │ ├── api │ │ └── route.ts │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── next.config.js ├── package.json ├── postcss.config.js ├── providers.tf ├── public │ ├── next.svg │ └── vercel.svg ├── tailwind.config.js ├── terragrunt.hcl ├── tsconfig.json └── yarn.lock └── v3-single-zone ├── .npmrc ├── README.md ├── eslint.config.mjs ├── next.config.ts ├── package.json ├── postcss.config.mjs ├── providers.tf ├── public ├── file.svg ├── globe.svg ├── next.svg ├── vercel.svg └── window.svg ├── src └── app │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── tailwind.config.ts ├── terragrunt.hcl └── tsconfig.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default owner for all pull requests 2 | * @RJPearson94 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help improve the module 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | ## Technical Details 10 | 11 | - OS: [e.g. MacOS] 12 | - Terraform Version: [e.g. 0.12.26] 13 | - Provider Version [e.g. v0.1.0] 14 | - Module Version [e.g. v0.1.0] 15 | 16 | ## Describe the bug 17 | 18 | A clear and concise description of what the bug is. Feel free to include Terraform configuration, logs, etc. 19 | 20 | ## Steps to Reproduce 21 | 22 | Steps to reproduce the behaviour: 23 | 24 | 1. Step 1 25 | 2. Step 2 26 | 3. See error 27 | 28 | ## Expected behaviour 29 | 30 | A clear and concise description of what you expected to happen. 31 | 32 | ## Logs 33 | 34 | Add logs of the error to help explain your problem. 35 | 36 | ## Additional context 37 | 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: enhancement 6 | assignees: "" 7 | --- 8 | 9 | ## Is your feature request related to a problem 10 | 11 | A clear and concise description of what the problem is. 12 | 13 | ## Describe the solution you'd like 14 | 15 | A clear and concise description of what you want to happen. Optionally you can include example terraform configuration too 16 | 17 | ```hcl 18 | copy and paste an example terraform configuration here 19 | ``` 20 | 21 | ## Additional context 22 | 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Misc 2 | .prototools 3 | 4 | # dependencies 5 | node_modules 6 | .pnp 7 | .pnp.js 8 | 9 | # testing 10 | coverage 11 | 12 | # next.js 13 | .next 14 | out 15 | 16 | # production 17 | build 18 | 19 | # misc 20 | .DS_Store 21 | .yarn 22 | *.pem 23 | *.yaml 24 | !*.tpl.yaml 25 | 26 | # debug 27 | npm-debug.log* 28 | yarn-debug.log* 29 | yarn-error.log* 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # vercel 35 | .vercel 36 | 37 | # typescript 38 | *.tsbuildinfo 39 | next-env.d.ts 40 | 41 | # Open Next 42 | .open-next 43 | 44 | # Terraform 45 | .Terraform 46 | *tfstate* 47 | *tfvars 48 | *tfbackend 49 | backend.tf 50 | .terraform.lock.hcl 51 | 52 | # Terragrunt 53 | .terragrunt-cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Next Terraform Examples 2 | 3 | This repo contains example Terraform/ Terragrunt configurations to deploy a single and multi-zone website to AWS using [Open Next](https://github.com/serverless-stack/open-next). 4 | 5 | This utilises the following module to deploy the Next.js website to AWS 6 | 7 | [Github Repo](https://github.com/RJPearson94/terraform-aws-open-next) 8 | 9 | [Terraform Registry](https://registry.terraform.io/modules/RJPearson94/open-next/aws/latest) 10 | 11 | See the module documentation for more information on the limitations, inputs, outputs, etc. 12 | 13 | ## Building the examples 14 | 15 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 16 | 17 | **NOTE:** You will need node 18 or above installed to build the applications 18 | 19 | For the multi-zone website please run the following commands 20 | 21 | ```shell 22 | cd multi-zone/docs 23 | yarn install 24 | yarn build:open-next 25 | ... 26 | cd ../home 27 | yarn install 28 | yarn build:open-next 29 | ``` 30 | 31 | For the single-zone website please run the following commands 32 | 33 | ```shell 34 | cd single-zone 35 | yarn install 36 | yarn build:open-next 37 | ``` 38 | 39 | ## Deploying the examples 40 | 41 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 42 | 43 | To deploy the examples to AWS, you will need the following 44 | 45 | - An AWS Account 46 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 47 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 48 | 49 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 50 | 51 | You will need to configure the AWS providers 4 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 52 | 53 | An example setup can be seen below 54 | 55 | ```tf 56 | provider "aws" { 57 | 58 | } 59 | 60 | provider "aws" { 61 | alias = "server_function" 62 | } 63 | 64 | provider "aws" { 65 | alias = "iam" 66 | } 67 | 68 | provider "aws" { 69 | alias = "dns" 70 | } 71 | 72 | provider "aws" { 73 | alias = "global" 74 | region = "us-east-1" 75 | } 76 | ``` 77 | 78 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 79 | 80 | ```shell 81 | terragrunt init 82 | ``` 83 | 84 | To see what changes will be made, you can run the following command: 85 | 86 | ```shell 87 | terragrunt plan 88 | ``` 89 | 90 | To deploy the website, you can run the following command: 91 | 92 | ```shell 93 | terragrunt apply 94 | ``` 95 | 96 | When you see the following 97 | 98 | ``` 99 | Do you want to perform these actions? 100 | Terraform will perform the actions described above. 101 | Only 'yes' will be accepted to approve. 102 | 103 | Enter a value: 104 | ``` 105 | 106 | type `yes` and hit the return/ enter key. 107 | 108 | 109 | ## Destroying the example 110 | 111 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 112 | 113 | ```shell 114 | terragrunt destroy 115 | ``` 116 | 117 | When you see the following 118 | 119 | ``` 120 | Do you really want to destroy all resources? 121 | Terraform will destroy all your managed infrastructure, as shown above. 122 | There is no undo. Only 'yes' will be accepted to confirm. 123 | 124 | Enter a value: 125 | ``` 126 | 127 | type `yes` and hit the return/ enter key. 128 | 129 | Then all the resources (which Terraform has state information for) should be removed. -------------------------------------------------------------------------------- /basic-auth/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /basic-auth/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .yarn 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # Open Next 39 | .open-next 40 | 41 | # Terraform 42 | .Terraform 43 | *tfstate* 44 | *tfvars 45 | *tfbackend 46 | deployments/*.tf 47 | 48 | # Terragrunt 49 | .terragrunt-cache -------------------------------------------------------------------------------- /basic-auth/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /basic-auth/README.md: -------------------------------------------------------------------------------- 1 | # Basic Auth example 2 | 3 | This example shows how you can deploy a single next.js app to AWS that uses AWS WAF to provide basic auth protection for the website 4 | 5 | This is inspired by Vercel's password-protected deployment feature - https://vercel.com/guides/how-do-i-add-password-protection-to-my-vercel-deployment 6 | 7 | Credit to Shinji Nakamatu for this idea - https://dev.to/snaka/implementing-secure-access-control-using-aws-waf-with-ip-address-and-basic-authentication-45hn 8 | 9 | ## Building the example 10 | 11 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 12 | 13 | **NOTE:** You will need node 20 or above installed to build the applications 14 | 15 | Please run the following commands 16 | 17 | ```shell 18 | yarn install 19 | yarn build:open-next 20 | ``` 21 | 22 | ## Deploying the examples 23 | 24 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 25 | 26 | To deploy the examples to AWS, you will need the following 27 | 28 | - An AWS Account 29 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 30 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 31 | - `credentials.yaml` file with the username and password set. See the [credentials template](./credentials.tpl.yaml) for the details 32 | 33 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 34 | 35 | You will need to configure the AWS providers 4 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 36 | 37 | An example setup can be seen below 38 | 39 | ```tf 40 | provider "aws" { 41 | 42 | } 43 | 44 | provider "aws" { 45 | alias = "server_function" 46 | } 47 | 48 | provider "aws" { 49 | alias = "iam" 50 | } 51 | 52 | provider "aws" { 53 | alias = "dns" 54 | } 55 | 56 | provider "aws" { 57 | alias = "global" 58 | region = "us-east-1" 59 | } 60 | ``` 61 | 62 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 63 | 64 | ```shell 65 | terragrunt init 66 | ``` 67 | 68 | To see what changes will be made, you can run the following command: 69 | 70 | ```shell 71 | terragrunt plan 72 | ``` 73 | 74 | To deploy the website, you can run the following command: 75 | 76 | ```shell 77 | terragrunt apply 78 | ``` 79 | 80 | When you see the following 81 | 82 | ``` 83 | Do you want to perform these actions? 84 | Terraform will perform the actions described above. 85 | Only 'yes' will be accepted to approve. 86 | 87 | Enter a value: 88 | ``` 89 | 90 | type `yes` and hit the return/ enter key. 91 | 92 | 93 | ## Destroying the example 94 | 95 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 96 | 97 | ```shell 98 | terragrunt destroy 99 | ``` 100 | 101 | When you see the following 102 | 103 | ``` 104 | Do you really want to destroy all resources? 105 | Terraform will destroy all your managed infrastructure, as shown above. 106 | There is no undo. Only 'yes' will be accepted to confirm. 107 | 108 | Enter a value: 109 | ``` 110 | 111 | type `yes` and hit the return/ enter key. 112 | 113 | Then all the resources (which Terraform has state information for) should be removed. 114 | -------------------------------------------------------------------------------- /basic-auth/app/api/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export async function GET() { 4 | return NextResponse.json({ name: "Test API route" }); 5 | } 6 | -------------------------------------------------------------------------------- /basic-auth/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/basic-auth/app/favicon.ico -------------------------------------------------------------------------------- /basic-auth/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /basic-auth/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /basic-auth/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Next.js app deployed using  9 | Open Next and Terraform 10 |

11 |
12 | 18 | By{" "} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{" "} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{" "} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{" "} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore the Next.js 13 playground. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{" "} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ); 113 | } 114 | -------------------------------------------------------------------------------- /basic-auth/credentials.tpl.yaml: -------------------------------------------------------------------------------- 1 | username: "" 2 | password: "" -------------------------------------------------------------------------------- /basic-auth/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /basic-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-portal", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "next": "^14.1.4", 15 | "postcss": "^8.4.38", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "tailwindcss": "^3.4.3" 19 | }, 20 | "devDependencies": { 21 | "@types/eslint": "^8.37.0", 22 | "@types/node": "^20.11.30", 23 | "@types/react": "^18.2.73", 24 | "@types/react-dom": "^18.2.23", 25 | "eslint": "^8.57.0", 26 | "eslint-config-next": "^14.1.4", 27 | "open-next": "^2.3.8", 28 | "typescript": "^5.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /basic-auth/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /basic-auth/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /basic-auth/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic-auth/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basic-auth/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /basic-auth/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | locals { 2 | credentials = yamldecode(file("${path_relative_from_include()}/credentials.yaml")) 3 | } 4 | 5 | terraform { 6 | source = "tfr://registry.terraform.io/RJPearson94/open-next/aws//modules/tf-aws-open-next-zone?version=3.0.0" 7 | include_in_copy = ["./.open-next"] 8 | } 9 | 10 | inputs = { 11 | prefix = "open-next-auth-${get_aws_account_id()}" 12 | folder_path = "./.open-next" 13 | s3_exclusion_regex = ".*\\.terragrunt*" 14 | 15 | website_bucket = { 16 | force_destroy = true 17 | } 18 | 19 | waf = { 20 | deployment = "CREATE" 21 | aws_managed_rules = [] 22 | enforce_basic_auth = { 23 | enabled = true 24 | credentials = { 25 | username = local.credentials["username"] 26 | password = local.credentials["password"] 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /basic-auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /maintainance-page-default-action/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /maintainance-page-default-action/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .yarn 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # Open Next 39 | .open-next 40 | 41 | # Terraform 42 | .Terraform 43 | *tfstate* 44 | *tfvars 45 | *tfbackend 46 | deployments/*.tf 47 | 48 | # Terragrunt 49 | .terragrunt-cache -------------------------------------------------------------------------------- /maintainance-page-default-action/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /maintainance-page-default-action/README.md: -------------------------------------------------------------------------------- 1 | # Maintainance page default action example 2 | 3 | This example shows how you can deploy a single next.js app to AWS that uses AWS WAF to block all traffic and show a maintainance page 4 | 5 | Credit to Paul L for this idea - https://repost.aws/questions/QUeXIw1g0hSxiF0BpugsT7aw/how-to-implement-the-maintenance-page-using-route-53-to-switch-between-cloudfront-distributions 6 | 7 | Credit to pitch-gist for the simple maintainance page used - https://gist.github.com/pitch-gist/2999707 8 | 9 | ## Building the example 10 | 11 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 12 | 13 | **NOTE:** You will need node 20 or above installed to build the applications 14 | 15 | Please run the following commands 16 | 17 | ```shell 18 | yarn install 19 | yarn build:open-next 20 | ``` 21 | 22 | ## Deploying the examples 23 | 24 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 25 | 26 | To deploy the examples to AWS, you will need the following 27 | 28 | - An AWS Account 29 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 30 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 31 | - `credentials.yaml` file with the username and password set. See the [credentials template](./credentials.tpl.yaml) for the details 32 | 33 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 34 | 35 | You will need to configure the AWS providers 4 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 36 | 37 | An example setup can be seen below 38 | 39 | ```tf 40 | provider "aws" { 41 | 42 | } 43 | 44 | provider "aws" { 45 | alias = "server_function" 46 | } 47 | 48 | provider "aws" { 49 | alias = "iam" 50 | } 51 | 52 | provider "aws" { 53 | alias = "dns" 54 | } 55 | 56 | provider "aws" { 57 | alias = "global" 58 | region = "us-east-1" 59 | } 60 | ``` 61 | 62 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 63 | 64 | ```shell 65 | terragrunt init 66 | ``` 67 | 68 | To see what changes will be made, you can run the following command: 69 | 70 | ```shell 71 | terragrunt plan 72 | ``` 73 | 74 | To deploy the website, you can run the following command: 75 | 76 | ```shell 77 | terragrunt apply 78 | ``` 79 | 80 | When you see the following 81 | 82 | ``` 83 | Do you want to perform these actions? 84 | Terraform will perform the actions described above. 85 | Only 'yes' will be accepted to approve. 86 | 87 | Enter a value: 88 | ``` 89 | 90 | type `yes` and hit the return/ enter key. 91 | 92 | 93 | ## Destroying the example 94 | 95 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 96 | 97 | ```shell 98 | terragrunt destroy 99 | ``` 100 | 101 | When you see the following 102 | 103 | ``` 104 | Do you really want to destroy all resources? 105 | Terraform will destroy all your managed infrastructure, as shown above. 106 | There is no undo. Only 'yes' will be accepted to confirm. 107 | 108 | Enter a value: 109 | ``` 110 | 111 | type `yes` and hit the return/ enter key. 112 | 113 | Then all the resources (which Terraform has state information for) should be removed. 114 | -------------------------------------------------------------------------------- /maintainance-page-default-action/app/api/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export async function GET() { 4 | return NextResponse.json({ name: "Test API route" }); 5 | } 6 | -------------------------------------------------------------------------------- /maintainance-page-default-action/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/maintainance-page-default-action/app/favicon.ico -------------------------------------------------------------------------------- /maintainance-page-default-action/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /maintainance-page-default-action/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /maintainance-page-default-action/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Next.js app deployed using  9 | Open Next and Terraform 10 |

11 |
12 | 18 | By{" "} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{" "} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{" "} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{" "} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore the Next.js 13 playground. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{" "} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ); 113 | } 114 | -------------------------------------------------------------------------------- /maintainance-page-default-action/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /maintainance-page-default-action/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-portal", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "next": "^14.1.4", 15 | "postcss": "^8.4.38", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "tailwindcss": "^3.4.3" 19 | }, 20 | "devDependencies": { 21 | "@types/eslint": "^8.37.0", 22 | "@types/node": "^20.11.30", 23 | "@types/react": "^18.2.73", 24 | "@types/react-dom": "^18.2.23", 25 | "eslint": "^8.57.0", 26 | "eslint-config-next": "^14.1.4", 27 | "open-next": "^2.3.8", 28 | "typescript": "^5.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /maintainance-page-default-action/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /maintainance-page-default-action/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /maintainance-page-default-action/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maintainance-page-default-action/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maintainance-page-default-action/static/503.html: -------------------------------------------------------------------------------- 1 | 2 | Site Maintenance 3 | 11 | 12 |
13 |

We’ll be back soon!

14 |
15 |

Sorry for the inconvenience but we’re performing some maintenance at the moment.

16 |
17 |
18 | -------------------------------------------------------------------------------- /maintainance-page-default-action/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /maintainance-page-default-action/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | terraform { 2 | source = "tfr://registry.terraform.io/RJPearson94/open-next/aws//modules/tf-aws-open-next-zone?version=3.0.0" 3 | include_in_copy = ["./.open-next"] 4 | } 5 | 6 | inputs = { 7 | prefix = "open-next-auth-${get_aws_account_id()}" 8 | folder_path = "./.open-next" 9 | s3_exclusion_regex = ".*\\.terragrunt*" 10 | 11 | website_bucket = { 12 | force_destroy = true 13 | } 14 | 15 | waf = { 16 | deployment = "CREATE" 17 | aws_managed_rules = [] 18 | default_action = { 19 | action = "BLOCK" 20 | block_action = { 21 | response_code = 503 22 | custom_response_body_key = "maintainance" 23 | } 24 | } 25 | custom_response_bodies = [{ 26 | key = "maintainance" 27 | content = file("./static/503.html") 28 | content_type = "TEXT_HTML" 29 | }] 30 | } 31 | } -------------------------------------------------------------------------------- /maintainance-page-default-action/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .yarn 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # Open Next 39 | .open-next 40 | 41 | # Terraform 42 | .Terraform 43 | *tfstate* 44 | *tfvars 45 | *tfbackend 46 | deployments/*.tf 47 | 48 | # Terragrunt 49 | .terragrunt-cache -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/README.md: -------------------------------------------------------------------------------- 1 | # Maintainance page with IP bypass example 2 | 3 | This example shows how you can deploy a single next.js app to AWS that uses AWS WAF to block traffic and show a maintainance page to all IP address not included in the bypass list. This allows your internal teams to access the website whilst others see the maintainance page. 4 | 5 | Credit to Paul L for this idea - https://repost.aws/questions/QUeXIw1g0hSxiF0BpugsT7aw/how-to-implement-the-maintenance-page-using-route-53-to-switch-between-cloudfront-distributions 6 | 7 | Credit to pitch-gist for the simple maintainance page used - https://gist.github.com/pitch-gist/2999707 8 | 9 | ## Building the example 10 | 11 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 12 | 13 | **NOTE:** You will need node 20 or above installed to build the applications 14 | 15 | Please run the following commands 16 | 17 | ```shell 18 | yarn install 19 | yarn build:open-next 20 | ``` 21 | 22 | ## Deploying the examples 23 | 24 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 25 | 26 | To deploy the examples to AWS, you will need the following 27 | 28 | - An AWS Account 29 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 30 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 31 | - `ip_addresses.yaml` file with the ipv4 and ipv6 addresses set. See the [ip addresses template](./ip_addresses.tpl.yaml) for the details 32 | 33 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 34 | 35 | You will need to configure the AWS providers 4 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 36 | 37 | An example setup can be seen below 38 | 39 | ```tf 40 | provider "aws" { 41 | 42 | } 43 | 44 | provider "aws" { 45 | alias = "server_function" 46 | } 47 | 48 | provider "aws" { 49 | alias = "iam" 50 | } 51 | 52 | provider "aws" { 53 | alias = "dns" 54 | } 55 | 56 | provider "aws" { 57 | alias = "global" 58 | region = "us-east-1" 59 | } 60 | ``` 61 | 62 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 63 | 64 | ```shell 65 | terragrunt init 66 | ``` 67 | 68 | To see what changes will be made, you can run the following command: 69 | 70 | ```shell 71 | terragrunt plan 72 | ``` 73 | 74 | To deploy the website, you can run the following command: 75 | 76 | ```shell 77 | terragrunt apply 78 | ``` 79 | 80 | When you see the following 81 | 82 | ``` 83 | Do you want to perform these actions? 84 | Terraform will perform the actions described above. 85 | Only 'yes' will be accepted to approve. 86 | 87 | Enter a value: 88 | ``` 89 | 90 | type `yes` and hit the return/ enter key. 91 | 92 | 93 | ## Destroying the example 94 | 95 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 96 | 97 | ```shell 98 | terragrunt destroy 99 | ``` 100 | 101 | When you see the following 102 | 103 | ``` 104 | Do you really want to destroy all resources? 105 | Terraform will destroy all your managed infrastructure, as shown above. 106 | There is no undo. Only 'yes' will be accepted to confirm. 107 | 108 | Enter a value: 109 | ``` 110 | 111 | type `yes` and hit the return/ enter key. 112 | 113 | Then all the resources (which Terraform has state information for) should be removed. 114 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/app/api/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export async function GET() { 4 | return NextResponse.json({ name: "Test API route" }); 5 | } 6 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/maintainance-page-ip-bypass/app/favicon.ico -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Next.js app deployed using  9 | Open Next and Terraform 10 |

11 |
12 | 18 | By{" "} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{" "} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{" "} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{" "} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore the Next.js 13 playground. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{" "} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ); 113 | } 114 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/ip_addresses.tpl.yaml: -------------------------------------------------------------------------------- 1 | ipv4_addresses: 2 | - "" 3 | 4 | ipv6_addresses: 5 | - "" 6 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-portal", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "next": "^14.1.4", 15 | "postcss": "^8.4.38", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "tailwindcss": "^3.4.3" 19 | }, 20 | "devDependencies": { 21 | "@types/eslint": "^8.37.0", 22 | "@types/node": "^20.11.30", 23 | "@types/react": "^18.2.73", 24 | "@types/react-dom": "^18.2.23", 25 | "eslint": "^8.57.0", 26 | "eslint-config-next": "^14.1.4", 27 | "open-next": "^2.3.8", 28 | "typescript": "^5.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/static/503.html: -------------------------------------------------------------------------------- 1 | 2 | Site Maintenance 3 | 11 | 12 |
13 |

We’ll be back soon!

14 |
15 |

Sorry for the inconvenience but we’re performing some maintenance at the moment.

16 |
17 |
18 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | locals { 2 | ip_addresses = yamldecode(file("${path_relative_from_include()}/ip_addresses.yaml")) 3 | } 4 | 5 | terraform { 6 | source = "tfr://registry.terraform.io/RJPearson94/open-next/aws//modules/tf-aws-open-next-zone?version=3.0.0" 7 | include_in_copy = ["./.open-next"] 8 | } 9 | 10 | inputs = { 11 | prefix = "open-next-auth-${get_aws_account_id()}" 12 | folder_path = "./.open-next" 13 | s3_exclusion_regex = ".*\\.terragrunt*" 14 | 15 | website_bucket = { 16 | force_destroy = true 17 | } 18 | 19 | waf = { 20 | deployment = "CREATE" 21 | aws_managed_rules = [] 22 | additional_rules = [{ 23 | enabled = true 24 | name = "maintainance" 25 | action = "BLOCK" 26 | block_action = { 27 | response_code = 503 28 | custom_response_body_key = "maintainance" 29 | } 30 | ip_address_restrictions = [{ 31 | action = "BYPASS" 32 | name = "ivp4_bypass" 33 | },{ 34 | action = "BYPASS" 35 | name = "ivp6_bypass" 36 | }] 37 | }] 38 | custom_response_bodies = [{ 39 | key = "maintainance" 40 | content = file("./static/503.html") 41 | content_type = "TEXT_HTML" 42 | }] 43 | ip_addresses = { 44 | "ivp4_bypass": { 45 | ip_address_version = "IPV4" 46 | addresses = local.ip_addresses["ipv4_addresses"] 47 | }, 48 | "ivp6_bypass": { 49 | ip_address_version = "IPV6" 50 | addresses = local.ip_addresses["ipv6_addresses"] 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /maintainance-page-ip-bypass/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /multi-zone/README.md: -------------------------------------------------------------------------------- 1 | # Multi-zone example 2 | 3 | This example shows how you can deploy multiple zones to AWS using the same shared distribution 4 | 5 | ## Building the example 6 | 7 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 8 | 9 | **NOTE:** You will need node 20 or above installed to build the applications 10 | 11 | Please run the following commands 12 | 13 | ```shell 14 | cd ./docs 15 | yarn install 16 | yarn build:open-next 17 | ... 18 | cd ../home 19 | yarn install 20 | yarn build:open-next 21 | ``` 22 | 23 | ## Deploying the examples 24 | 25 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 26 | 27 | To deploy the examples to AWS, you will need the following 28 | 29 | - An AWS Account 30 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 31 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 32 | - `credentials.yaml` file with the username and password set. See the [credentials template](./credentials.tpl.yaml) for the details 33 | 34 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 35 | 36 | You will need to configure the AWS providers 4 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 37 | 38 | An example setup can be seen below 39 | 40 | ```tf 41 | provider "aws" { 42 | 43 | } 44 | 45 | provider "aws" { 46 | alias = "server_function" 47 | } 48 | 49 | provider "aws" { 50 | alias = "iam" 51 | } 52 | 53 | provider "aws" { 54 | alias = "dns" 55 | } 56 | 57 | provider "aws" { 58 | alias = "global" 59 | region = "us-east-1" 60 | } 61 | ``` 62 | 63 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 64 | 65 | ```shell 66 | terragrunt init 67 | ``` 68 | 69 | To see what changes will be made, you can run the following command: 70 | 71 | ```shell 72 | terragrunt plan 73 | ``` 74 | 75 | To deploy the website, you can run the following command: 76 | 77 | ```shell 78 | terragrunt apply 79 | ``` 80 | 81 | When you see the following 82 | 83 | ``` 84 | Do you want to perform these actions? 85 | Terraform will perform the actions described above. 86 | Only 'yes' will be accepted to approve. 87 | 88 | Enter a value: 89 | ``` 90 | 91 | type `yes` and hit the return/ enter key. 92 | 93 | 94 | ## Destroying the example 95 | 96 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 97 | 98 | ```shell 99 | terragrunt destroy 100 | ``` 101 | 102 | When you see the following 103 | 104 | ``` 105 | Do you really want to destroy all resources? 106 | Terraform will destroy all your managed infrastructure, as shown above. 107 | There is no undo. Only 'yes' will be accepted to confirm. 108 | 109 | Enter a value: 110 | ``` 111 | 112 | type `yes` and hit the return/ enter key. 113 | 114 | Then all the resources (which Terraform has state information for) should be removed. 115 | -------------------------------------------------------------------------------- /multi-zone/docs/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /multi-zone/docs/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy to AWS 31 | 32 | This application can be deployed to AWS using [Terraform](https://www.terraform.io/). 33 | 34 | The Terraform code and instructions on how to deploy the application can be found in the [infrastructure](./infrastructure/) folder. 35 | -------------------------------------------------------------------------------- /multi-zone/docs/app/api/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export async function GET() { 4 | return NextResponse.json({ name: "Docs API route" }); 5 | } 6 | -------------------------------------------------------------------------------- /multi-zone/docs/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/multi-zone/docs/app/favicon.ico -------------------------------------------------------------------------------- /multi-zone/docs/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /multi-zone/docs/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /multi-zone/docs/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Next.js Docs app deployed using  9 | Open Next and Terraform 10 |

11 |
12 | 18 | By{" "} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{" "} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{" "} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{" "} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore the Next.js 13 playground. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{" "} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ); 113 | } 114 | -------------------------------------------------------------------------------- /multi-zone/docs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | basePath: "/docs" 4 | }; 5 | 6 | module.exports = nextConfig; 7 | 8 | -------------------------------------------------------------------------------- /multi-zone/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-portal", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "next": "^14.1.4", 15 | "postcss": "^8.4.38", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "tailwindcss": "^3.4.3" 19 | }, 20 | "devDependencies": { 21 | "@types/eslint": "^8.37.0", 22 | "@types/node": "^20.11.30", 23 | "@types/react": "^18.2.73", 24 | "@types/react-dom": "^18.2.23", 25 | "eslint": "^8.57.0", 26 | "eslint-config-next": "^14.1.4", 27 | "open-next": "^2.3.8", 28 | "typescript": "^5.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /multi-zone/docs/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /multi-zone/docs/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /multi-zone/docs/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /multi-zone/docs/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /multi-zone/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /multi-zone/home/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /multi-zone/home/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy to AWS 31 | 32 | This application can be deployed to AWS using [Terraform](https://www.terraform.io/). 33 | 34 | The Terraform code and instructions on how to deploy the application can be found in the [infrastructure](./infrastructure/) folder. 35 | -------------------------------------------------------------------------------- /multi-zone/home/app/api/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export async function GET() { 4 | return NextResponse.json({ name: "Root API route" }); 5 | } 6 | -------------------------------------------------------------------------------- /multi-zone/home/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/multi-zone/home/app/favicon.ico -------------------------------------------------------------------------------- /multi-zone/home/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /multi-zone/home/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /multi-zone/home/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import Image from "next/image"; 4 | import { useRouter } from 'next/navigation'; 5 | 6 | export default function Home() { 7 | const router = useRouter(); 8 | 9 | return ( 10 |
11 |
12 |

13 | Root Next.js app deployed using  14 | Open Next and Terraform 15 |

16 | 17 |
18 | 21 |
22 |
23 | 24 |
25 | Next.js Logo 33 |
34 | 35 |
36 | 42 |

43 | Docs{" "} 44 | 45 | -> 46 | 47 |

48 |

49 | Find in-depth information about Next.js features and API. 50 |

51 |
52 | 53 | 59 |

60 | Learn{" "} 61 | 62 | -> 63 | 64 |

65 |

66 | Learn about Next.js in an interactive course with quizzes! 67 |

68 |
69 | 70 | 76 |

77 | Templates{" "} 78 | 79 | -> 80 | 81 |

82 |

83 | Explore the Next.js 13 playground. 84 |

85 |
86 | 87 | 93 |

94 | Deploy{" "} 95 | 96 | -> 97 | 98 |

99 |

100 | Instantly deploy your Next.js site to a shareable URL with Vercel. 101 |

102 |
103 |
104 |
105 | ); 106 | } 107 | -------------------------------------------------------------------------------- /multi-zone/home/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | module.exports = nextConfig; 5 | -------------------------------------------------------------------------------- /multi-zone/home/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-portal", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "next": "^14.1.4", 15 | "postcss": "^8.4.38", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "tailwindcss": "^3.4.3" 19 | }, 20 | "devDependencies": { 21 | "@types/eslint": "^8.37.0", 22 | "@types/node": "^20.11.30", 23 | "@types/react": "^18.2.73", 24 | "@types/react-dom": "^18.2.23", 25 | "eslint": "^8.57.0", 26 | "eslint-config-next": "^14.1.4", 27 | "open-next": "^2.3.8", 28 | "typescript": "^5.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /multi-zone/home/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /multi-zone/home/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /multi-zone/home/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /multi-zone/home/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /multi-zone/home/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /multi-zone/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /multi-zone/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | terraform { 2 | source = "tfr://registry.terraform.io/RJPearson94/open-next/aws//modules/tf-aws-open-next-multi-zone?version=3.4.2" 3 | include_in_copy = ["./docs/.open-next", "./home/.open-next"] 4 | } 5 | 6 | inputs = { 7 | prefix = "open-next-mz-${get_aws_account_id()}" 8 | deployment = "SHARED_DISTRIBUTION" 9 | 10 | s3_exclusion_regex = ".*\\.terragrunt*" 11 | zones = [{ 12 | root = true 13 | name = "home" 14 | folder_path = "./home/.open-next" 15 | },{ 16 | root = false 17 | name = "docs" 18 | folder_path = "./docs/.open-next" 19 | }] 20 | 21 | website_bucket = { 22 | force_destroy = true 23 | } 24 | } -------------------------------------------------------------------------------- /server-function-in-vpc/.npmrc: -------------------------------------------------------------------------------- 1 | node-linker=hoisted -------------------------------------------------------------------------------- /server-function-in-vpc/README.md: -------------------------------------------------------------------------------- 1 | # Server function in VPC 2 | 3 | This example shows how you can deploy a single next.js app to AWS using open next v3 with the server function within a VPC. VPC Endpoints are created to allow the server function to talk with S3, DynamoDB and SQS without requiring internet access 4 | 5 | ## Building the example 6 | 7 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 8 | 9 | **NOTE:** You will need node 20 or above installed to build the applications 10 | 11 | Please run the following commands 12 | 13 | ```shell 14 | pnpm install 15 | pnpm run build:open-next 16 | ``` 17 | 18 | ## Deploying the examples 19 | 20 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 21 | 22 | To deploy the examples to AWS, you will need the following 23 | 24 | - An AWS Account 25 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 26 | 27 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 28 | 29 | You will need to configure the AWS providers 5 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 30 | 31 | An example setup can be seen below 32 | 33 | ```tf 34 | provider "aws" { 35 | 36 | } 37 | 38 | provider "aws" { 39 | alias = "server_function" 40 | } 41 | 42 | provider "aws" { 43 | alias = "iam" 44 | } 45 | 46 | provider "aws" { 47 | alias = "dns" 48 | } 49 | 50 | provider "aws" { 51 | alias = "global" 52 | region = "us-east-1" 53 | } 54 | ``` 55 | 56 | Once the artifacts have been built they can be deployed using Terraform. First, you need to download the providers and module, you can do this by running the following command: 57 | 58 | ```shell 59 | terraform init 60 | ``` 61 | 62 | To see what changes will be made, you can run the following command: 63 | 64 | ```shell 65 | terraform plan 66 | ``` 67 | 68 | You will need to supply values for the required variables. 69 | 70 | To deploy the website, you can run the following command: 71 | 72 | ```shell 73 | terraform apply 74 | ``` 75 | 76 | You will need to supply values for the required variables. 77 | 78 | When you see the following 79 | 80 | ``` 81 | Do you want to perform these actions? 82 | Terraform will perform the actions described above. 83 | Only 'yes' will be accepted to approve. 84 | 85 | Enter a value: 86 | ``` 87 | 88 | type `yes` and hit the return/ enter key. 89 | 90 | 91 | ## Destroying the example 92 | 93 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 94 | 95 | ```shell 96 | terraform destroy 97 | ``` 98 | 99 | You will need to supply values for the required variables. 100 | 101 | When you see the following 102 | 103 | ``` 104 | Do you really want to destroy all resources? 105 | Terraform will destroy all your managed infrastructure, as shown above. 106 | There is no undo. Only 'yes' will be accepted to confirm. 107 | 108 | Enter a value: 109 | ``` 110 | 111 | type `yes` and hit the return/ enter key. 112 | 113 | Then all the resources (which Terraform has state information for) should be removed. 114 | -------------------------------------------------------------------------------- /server-function-in-vpc/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "current" {} 2 | -------------------------------------------------------------------------------- /server-function-in-vpc/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /server-function-in-vpc/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | prefix = var.prefix == null ? "" : "${var.prefix}-" 3 | suffix = var.suffix == null ? "" : "-${var.suffix}" 4 | } 5 | 6 | module "vpc" { 7 | source = "terraform-aws-modules/vpc/aws" 8 | version = "~> 5.0" 9 | 10 | name = "${local.prefix}vpc${local.suffix}" 11 | cidr = var.cidr_range 12 | 13 | azs = var.availability_zones 14 | private_subnets = var.private_subnets 15 | public_subnets = var.public_subnets 16 | 17 | single_nat_gateway = true 18 | 19 | # DNS settings 20 | enable_dns_hostnames = true 21 | enable_dns_support = true 22 | } 23 | 24 | # Create a security group for Lambda functions 25 | resource "aws_security_group" "lambda_sg" { 26 | vpc_id = module.vpc.vpc_id 27 | 28 | # Allow all outbound traffic 29 | egress { 30 | from_port = 0 31 | to_port = 0 32 | protocol = "-1" 33 | cidr_blocks = ["0.0.0.0/0"] 34 | description = "Allow all outbound traffic" 35 | } 36 | } 37 | 38 | # Security Group for VPC Endpoint resources 39 | resource "aws_security_group" "vpc_endpoint_sg" { 40 | vpc_id = module.vpc.vpc_id 41 | 42 | # Allow inbound HTTPS traffic from Lambda's security group 43 | ingress { 44 | from_port = 443 45 | to_port = 443 46 | protocol = "tcp" 47 | security_groups = [aws_security_group.lambda_sg.id] 48 | } 49 | } 50 | 51 | # Create a VPC endpoint for Dynamodb, S3 & SQS to allow Lambda to access it without going through the internet 52 | resource "aws_vpc_endpoint" "vpc_endpoint" { 53 | for_each = { "dynamodb" = "Gateway", "s3" = "Gateway", "sqs" = "Interface" } 54 | 55 | vpc_id = module.vpc.vpc_id 56 | service_name = "com.amazonaws.${data.aws_region.current.name}.${each.key}" 57 | vpc_endpoint_type = each.value 58 | subnet_ids = each.value == "Interface" ? module.vpc.private_subnets : null 59 | security_group_ids = each.value == "Interface" ? [aws_security_group.vpc_endpoint_sg.id] : null 60 | private_dns_enabled = each.value == "Interface" ? true : null 61 | route_table_ids = each.value == "Gateway" ? module.vpc.private_route_table_ids : null 62 | } 63 | 64 | module "opennext_single_zone" { 65 | source = "RJPearson94/open-next/aws//modules/tf-aws-open-next-zone" 66 | version = "3.3.0" 67 | 68 | open_next_version = "v3.x.x" 69 | folder_path = "./.open-next" 70 | 71 | prefix = var.prefix 72 | suffix = var.suffix 73 | 74 | server_function = { 75 | vpc = { 76 | security_group_ids = [aws_security_group.lambda_sg.id] 77 | subnet_ids = module.vpc.private_subnets 78 | } 79 | } 80 | 81 | distribution = { 82 | cache_policy = { 83 | enable_accept_encoding_brotli = true 84 | enable_accept_encoding_gzip = true 85 | } 86 | } 87 | 88 | website_bucket = { 89 | force_destroy = true 90 | } 91 | 92 | providers = { 93 | aws.server_function = aws.server_function 94 | aws.iam = aws.iam 95 | aws.dns = aws.dns 96 | aws.global = aws.global 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /server-function-in-vpc/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /server-function-in-vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cloudfront_url" { 2 | description = "The URL for the cloudfront distribution" 3 | value = module.opennext_single_zone.cloudfront_url 4 | } -------------------------------------------------------------------------------- /server-function-in-vpc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-function-in-vpc", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "react": "^19.0.0", 14 | "react-dom": "^19.0.0", 15 | "next": "15.2.0" 16 | }, 17 | "devDependencies": { 18 | "@eslint/eslintrc": "^3.3.0", 19 | "@opennextjs/aws": "3.5.0", 20 | "@types/node": "ts5.8", 21 | "@types/react": "^19.0.8", 22 | "@types/react-dom": "^19.0.3", 23 | "postcss": "^8.5.3", 24 | "typescript": "^5.8.2", 25 | "tailwindcss": "^3.4.1", 26 | "eslint": "^9.21.0", 27 | "eslint-config-next": "15.2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /server-function-in-vpc/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /server-function-in-vpc/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /server-function-in-vpc/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-function-in-vpc/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-function-in-vpc/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-function-in-vpc/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-function-in-vpc/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server-function-in-vpc/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/server-function-in-vpc/src/app/favicon.ico -------------------------------------------------------------------------------- /server-function-in-vpc/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --background: #ffffff; 7 | --foreground: #171717; 8 | } 9 | 10 | @media (prefers-color-scheme: dark) { 11 | :root { 12 | --background: #0a0a0a; 13 | --foreground: #ededed; 14 | } 15 | } 16 | 17 | body { 18 | color: var(--foreground); 19 | background: var(--background); 20 | font-family: Arial, Helvetica, sans-serif; 21 | } 22 | -------------------------------------------------------------------------------- /server-function-in-vpc/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Geist, Geist_Mono } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const geistSans = Geist({ 6 | variable: "--font-geist-sans", 7 | subsets: ["latin"], 8 | }); 9 | 10 | const geistMono = Geist_Mono({ 11 | variable: "--font-geist-mono", 12 | subsets: ["latin"], 13 | }); 14 | 15 | export const metadata: Metadata = { 16 | title: "Create Next App", 17 | description: "Generated by create next app", 18 | }; 19 | 20 | export default function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 30 | {children} 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /server-function-in-vpc/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 | Next.js logo 15 |
    16 |
  1. 17 | Get started by editing{" "} 18 | 19 | src/app/page.tsx 20 | 21 | . 22 |
  2. 23 |
  3. Save and see your changes instantly.
  4. 24 |
25 | 26 |
27 | 33 | Vercel logomark 40 | Deploy now 41 | 42 | 48 | Read our docs 49 | 50 |
51 |
52 | 99 |
100 | ); 101 | } 102 | -------------------------------------------------------------------------------- /server-function-in-vpc/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | colors: { 12 | background: "var(--background)", 13 | foreground: "var(--foreground)", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } satisfies Config; 19 | -------------------------------------------------------------------------------- /server-function-in-vpc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /server-function-in-vpc/variables.tf: -------------------------------------------------------------------------------- 1 | variable "prefix" { 2 | description = "A prefix which will be attached to the resource name to ensure resources are random" 3 | type = string 4 | default = null 5 | } 6 | 7 | variable "suffix" { 8 | description = "A suffix which will be attached to the resource name to ensure resources are random" 9 | type = string 10 | default = null 11 | } 12 | 13 | variable "cidr_range" { 14 | description = "The CIDR range for the VPC" 15 | type = string 16 | } 17 | 18 | variable "availability_zones" { 19 | description = "A list of availability zones in the region" 20 | type = list(string) 21 | } 22 | 23 | variable "private_subnets" { 24 | description = "A list of private subnet CIDR blocks" 25 | type = list(string) 26 | } 27 | 28 | variable "public_subnets" { 29 | description = "A list of public subnet CIDR blocks" 30 | type = list(string) 31 | } -------------------------------------------------------------------------------- /single-zone/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /single-zone/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .yarn 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # Open Next 39 | .open-next 40 | 41 | # Terraform 42 | .Terraform 43 | *tfstate* 44 | *tfvars 45 | *tfbackend 46 | deployments/*.tf 47 | 48 | # Terragrunt 49 | .terragrunt-cache -------------------------------------------------------------------------------- /single-zone/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | -------------------------------------------------------------------------------- /single-zone/README.md: -------------------------------------------------------------------------------- 1 | # Single-zone example 2 | 3 | This example shows how you can deploy a single next.js app to AWS using open next 4 | 5 | ## Building the example 6 | 7 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 8 | 9 | **NOTE:** You will need node 20 or above installed to build the applications 10 | 11 | Please run the following commands 12 | 13 | ```shell 14 | yarn install 15 | yarn build:open-next 16 | ``` 17 | 18 | ## Deploying the examples 19 | 20 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 21 | 22 | To deploy the examples to AWS, you will need the following 23 | 24 | - An AWS Account 25 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 26 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 27 | 28 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 29 | 30 | You will need to configure the AWS providers 4 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 31 | 32 | An example setup can be seen below 33 | 34 | ```tf 35 | provider "aws" { 36 | 37 | } 38 | 39 | provider "aws" { 40 | alias = "server_function" 41 | } 42 | 43 | provider "aws" { 44 | alias = "iam" 45 | } 46 | 47 | provider "aws" { 48 | alias = "dns" 49 | } 50 | 51 | provider "aws" { 52 | alias = "global" 53 | region = "us-east-1" 54 | } 55 | ``` 56 | 57 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 58 | 59 | ```shell 60 | terragrunt init 61 | ``` 62 | 63 | To see what changes will be made, you can run the following command: 64 | 65 | ```shell 66 | terragrunt plan 67 | ``` 68 | 69 | To deploy the website, you can run the following command: 70 | 71 | ```shell 72 | terragrunt apply 73 | ``` 74 | 75 | When you see the following 76 | 77 | ``` 78 | Do you want to perform these actions? 79 | Terraform will perform the actions described above. 80 | Only 'yes' will be accepted to approve. 81 | 82 | Enter a value: 83 | ``` 84 | 85 | type `yes` and hit the return/ enter key. 86 | 87 | 88 | ## Destroying the example 89 | 90 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 91 | 92 | ```shell 93 | terragrunt destroy 94 | ``` 95 | 96 | When you see the following 97 | 98 | ``` 99 | Do you really want to destroy all resources? 100 | Terraform will destroy all your managed infrastructure, as shown above. 101 | There is no undo. Only 'yes' will be accepted to confirm. 102 | 103 | Enter a value: 104 | ``` 105 | 106 | type `yes` and hit the return/ enter key. 107 | 108 | Then all the resources (which Terraform has state information for) should be removed. 109 | -------------------------------------------------------------------------------- /single-zone/app/api/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export async function GET() { 4 | return NextResponse.json({ name: "Test API route" }); 5 | } 6 | -------------------------------------------------------------------------------- /single-zone/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/single-zone/app/favicon.ico -------------------------------------------------------------------------------- /single-zone/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /single-zone/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ 12 | children, 13 | }: { 14 | children: React.ReactNode 15 | }) { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /single-zone/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Next.js app deployed using  9 | Open Next and Terraform 10 |

11 |
12 | 18 | By{" "} 19 | Vercel Logo 27 | 28 |
29 |
30 | 31 |
32 | Next.js Logo 40 |
41 | 42 |
43 | 49 |

50 | Docs{" "} 51 | 52 | -> 53 | 54 |

55 |

56 | Find in-depth information about Next.js features and API. 57 |

58 |
59 | 60 | 66 |

67 | Learn{" "} 68 | 69 | -> 70 | 71 |

72 |

73 | Learn about Next.js in an interactive course with quizzes! 74 |

75 |
76 | 77 | 83 |

84 | Templates{" "} 85 | 86 | -> 87 | 88 |

89 |

90 | Explore the Next.js 13 playground. 91 |

92 |
93 | 94 | 100 |

101 | Deploy{" "} 102 | 103 | -> 104 | 105 |

106 |

107 | Instantly deploy your Next.js site to a shareable URL with Vercel. 108 |

109 |
110 |
111 |
112 | ); 113 | } 114 | -------------------------------------------------------------------------------- /single-zone/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /single-zone/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-portal", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "next": "^14.1.4", 15 | "postcss": "^8.4.38", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "tailwindcss": "^3.4.3" 19 | }, 20 | "devDependencies": { 21 | "@types/eslint": "^8.37.0", 22 | "@types/node": "^20.11.30", 23 | "@types/react": "^18.2.73", 24 | "@types/react-dom": "^18.2.23", 25 | "eslint": "^8.57.0", 26 | "eslint-config-next": "^14.1.4", 27 | "open-next": "^2.3.8", 28 | "typescript": "^5.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /single-zone/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /single-zone/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /single-zone/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /single-zone/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /single-zone/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /single-zone/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | terraform { 2 | source = "tfr://registry.terraform.io/RJPearson94/open-next/aws//modules/tf-aws-open-next-zone?version=3.0.0" 3 | include_in_copy = ["./.open-next"] 4 | } 5 | 6 | inputs = { 7 | prefix = "open-next-sz-${get_aws_account_id()}" 8 | folder_path = "./.open-next" 9 | s3_exclusion_regex = ".*\\.terragrunt*" 10 | 11 | continuous_deployment = { 12 | use = true 13 | deployment = "NONE" 14 | traffic_config = { 15 | header = { 16 | name = "aws-cf-cd-staging" 17 | value = "true" 18 | } 19 | } 20 | } 21 | 22 | website_bucket = { 23 | force_destroy = true 24 | } 25 | } -------------------------------------------------------------------------------- /single-zone/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /v3-single-zone/.npmrc: -------------------------------------------------------------------------------- 1 | node-linker=hoisted -------------------------------------------------------------------------------- /v3-single-zone/README.md: -------------------------------------------------------------------------------- 1 | # v3 single zone example 2 | 3 | This example shows how you can deploy a single next.js app to AWS using open next v3 4 | 5 | ## Building the example 6 | 7 | To be able to deploy the examples, you will need to install the dependencies and build the websites using open-next. 8 | 9 | **NOTE:** You will need node 20 or above installed to build the applications 10 | 11 | Please run the following commands 12 | 13 | ```shell 14 | pnpm install 15 | pnpm run build:open-next 16 | ``` 17 | 18 | ## Deploying the examples 19 | 20 | **NOTE:** Deploying an example could cause you to start incurring charges on you AWS account 21 | 22 | To deploy the examples to AWS, you will need the following 23 | 24 | - An AWS Account 25 | - [Terragrunt](https://terragrunt.gruntwork.io/) v0.45.14 or above 26 | - [Terraform](https://terragrunt.gruntwork.io/) v1.4.0 or above 27 | 28 | To configure the AWS providers see the [provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 29 | 30 | You will need to configure the AWS providers 5 times, this is due to some orgs using different account or roles for IAM, DNS, etc. The server function is a seperate provider to allow you backend resources to be deployed to a region i.e. eu-west-1 and deploy the server function to another region i.e. us-east-1 for lambda@edge. 31 | 32 | An example setup can be seen below 33 | 34 | ```tf 35 | provider "aws" { 36 | 37 | } 38 | 39 | provider "aws" { 40 | alias = "server_function" 41 | } 42 | 43 | provider "aws" { 44 | alias = "iam" 45 | } 46 | 47 | provider "aws" { 48 | alias = "dns" 49 | } 50 | 51 | provider "aws" { 52 | alias = "global" 53 | region = "us-east-1" 54 | } 55 | ``` 56 | 57 | Once the artifacts have been built they can be deployed using Terraform & Terragrunt. First, you need to download the providers and module, you can do this by running the following command: 58 | 59 | ```shell 60 | terragrunt init 61 | ``` 62 | 63 | To see what changes will be made, you can run the following command: 64 | 65 | ```shell 66 | terragrunt plan 67 | ``` 68 | 69 | To deploy the website, you can run the following command: 70 | 71 | ```shell 72 | terragrunt apply 73 | ``` 74 | 75 | When you see the following 76 | 77 | ``` 78 | Do you want to perform these actions? 79 | Terraform will perform the actions described above. 80 | Only 'yes' will be accepted to approve. 81 | 82 | Enter a value: 83 | ``` 84 | 85 | type `yes` and hit the return/ enter key. 86 | 87 | 88 | ## Destroying the example 89 | 90 | Once you are finished with the resources you can remove all the provisioned resources by running the following command: 91 | 92 | ```shell 93 | terragrunt destroy 94 | ``` 95 | 96 | When you see the following 97 | 98 | ``` 99 | Do you really want to destroy all resources? 100 | Terraform will destroy all your managed infrastructure, as shown above. 101 | There is no undo. Only 'yes' will be accepted to confirm. 102 | 103 | Enter a value: 104 | ``` 105 | 106 | type `yes` and hit the return/ enter key. 107 | 108 | Then all the resources (which Terraform has state information for) should be removed. 109 | -------------------------------------------------------------------------------- /v3-single-zone/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /v3-single-zone/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /v3-single-zone/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v3-single-zone", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build:open-next": "open-next build", 8 | "build": "next build", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "react": "^19.0.0", 14 | "react-dom": "^19.0.0", 15 | "next": "15.1.6" 16 | }, 17 | "devDependencies": { 18 | "@eslint/eslintrc": "^3.2.0", 19 | "@opennextjs/aws": "3.4.2", 20 | "@types/node": "ts5.7", 21 | "@types/react": "^19.0.8", 22 | "@types/react-dom": "^19.0.3", 23 | "postcss": "^8.5.1", 24 | "typescript": "^5.7.3", 25 | "tailwindcss": "^3.4.1", 26 | "eslint": "^9.20.0", 27 | "eslint-config-next": "15.1.6" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /v3-single-zone/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /v3-single-zone/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | 3 | } 4 | 5 | provider "aws" { 6 | alias = "server_function" 7 | } 8 | 9 | provider "aws" { 10 | alias = "iam" 11 | } 12 | 13 | provider "aws" { 14 | alias = "dns" 15 | } 16 | 17 | provider "aws" { 18 | alias = "global" 19 | region = "us-east-1" 20 | } -------------------------------------------------------------------------------- /v3-single-zone/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /v3-single-zone/public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /v3-single-zone/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /v3-single-zone/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /v3-single-zone/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /v3-single-zone/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RJPearson94/terraform-aws-open-next-examples/8c3783284b9f9c9df2fe76c8cee175d4c70e81c8/v3-single-zone/src/app/favicon.ico -------------------------------------------------------------------------------- /v3-single-zone/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --background: #ffffff; 7 | --foreground: #171717; 8 | } 9 | 10 | @media (prefers-color-scheme: dark) { 11 | :root { 12 | --background: #0a0a0a; 13 | --foreground: #ededed; 14 | } 15 | } 16 | 17 | body { 18 | color: var(--foreground); 19 | background: var(--background); 20 | font-family: Arial, Helvetica, sans-serif; 21 | } 22 | -------------------------------------------------------------------------------- /v3-single-zone/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Geist, Geist_Mono } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const geistSans = Geist({ 6 | variable: "--font-geist-sans", 7 | subsets: ["latin"], 8 | }); 9 | 10 | const geistMono = Geist_Mono({ 11 | variable: "--font-geist-mono", 12 | subsets: ["latin"], 13 | }); 14 | 15 | export const metadata: Metadata = { 16 | title: "Create Next App", 17 | description: "Generated by create next app", 18 | }; 19 | 20 | export default function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 30 | {children} 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /v3-single-zone/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 | Next.js logo 15 |
    16 |
  1. 17 | Get started by editing{" "} 18 | 19 | src/app/page.tsx 20 | 21 | . 22 |
  2. 23 |
  3. Save and see your changes instantly.
  4. 24 |
25 | 26 |
27 | 33 | Vercel logomark 40 | Deploy now 41 | 42 | 48 | Read our docs 49 | 50 |
51 |
52 | 99 |
100 | ); 101 | } 102 | -------------------------------------------------------------------------------- /v3-single-zone/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | colors: { 12 | background: "var(--background)", 13 | foreground: "var(--foreground)", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } satisfies Config; 19 | -------------------------------------------------------------------------------- /v3-single-zone/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | terraform { 2 | source = "tfr://registry.terraform.io/RJPearson94/open-next/aws//modules/tf-aws-open-next-zone?version=3.2.0" 3 | include_in_copy = ["./.open-next"] 4 | } 5 | 6 | inputs = { 7 | prefix = "open-next-${get_aws_account_id()}" 8 | 9 | folder_path = "./.open-next" 10 | s3_exclusion_regex = ".*\\.terragrunt*" 11 | 12 | origin_timeouts = { 13 | keepalive_timeout = 60 14 | read_timeout = 60 15 | connection_attempts = 2 16 | connection_timeout = 5 17 | } 18 | 19 | distribution = { 20 | cache_policy = { 21 | enable_accept_encoding_brotli = true 22 | enable_accept_encoding_gzip = true 23 | } 24 | } 25 | 26 | continuous_deployment = { 27 | use = false 28 | deployment = "NONE" 29 | traffic_config = { 30 | header = { 31 | name = "aws-cf-cd-staging" 32 | value = "true" 33 | } 34 | } 35 | } 36 | 37 | additional_server_functions = { 38 | iam_policies = { 39 | include_bucket_access = true 40 | include_revalidation_queue_access = true 41 | include_tag_mapping_db_access = true 42 | } 43 | } 44 | 45 | website_bucket = { 46 | force_destroy = true 47 | } 48 | open_next_version = "v3.x.x" 49 | } -------------------------------------------------------------------------------- /v3-single-zone/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | --------------------------------------------------------------------------------