├── .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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 | router.push('/docs')} className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
19 | Go to Docs multi-zone
20 |
21 |
22 |
23 |
24 |
25 |
33 |
34 |
35 |
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 |
15 |
16 |
17 | Get started by editing{" "}
18 |
19 | src/app/page.tsx
20 |
21 | .
22 |
23 | Save and see your changes instantly.
24 |
25 |
26 |
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 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
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 |
15 |
16 |
17 | Get started by editing{" "}
18 |
19 | src/app/page.tsx
20 |
21 | .
22 |
23 | Save and see your changes instantly.
24 |
25 |
26 |
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 |
--------------------------------------------------------------------------------