Deploy a Next.js application on AWS using CDK & Fargate
Tags: aws, devops, nextjs
Published: 2021-09-08 11:55:50

### What is Fargate ?


![Capture d’écran 2021-08-12 à 14.18.30.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1628770733808/ERXH8uhVs.png)


### Why Next.js on AWS ?

The Next.js documentation says : 


> The easiest way to deploy Next.js to production is to use the Vercel platform from the creators of Next.js

Well, if you are just getting started with your project, i will say go for Vercel.

But in my case, i had all my projects on AWS using CDK, and i don't wanted to have to manage my Next.js app on another platform.

### Let's get started

Let's create the main folder of the project 


```
mkdir nextJsOnAws
cd nextJsOnAws
``` 


#### NextJS part

```
npx create-next-app
``` 

and name it the way you want (i named it front)

We are going to create a Dockerfile ( i am using the  [official](https://nextjs.org/docs/deployment#docker-image)  one from the Vercel documentation)


```
# Install dependencies only when needed

FROM node:alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Rebuild the source code only when needed

FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build && yarn install --production --ignore-scripts --prefer-offline

# Production image, copy all the files and run next

FROM node:alpine AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001


COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

USER nextjs

EXPOSE 3000

CMD ["yarn", "start"]
``` 


#### CDK part

Let's create a new CDK project on a dedicated folder

```
mkdir cdkPart
cd cdkPart
cdk init --language typescript
``` 

Then let's install the package we need

```
npm install @aws-cdk/aws-ec2 @aws-cdk/aws-ecs @aws-cdk/aws-ecs-patterns
``` 

In the lib folder, a file was created called cdk_part-stack, open it and complete it like this


```
import * as cdk from '@aws-cdk/core';
import * as ec2 from "@aws-cdk/aws-ec2";
import * as ecs from "@aws-cdk/aws-ecs";
import * as ecs_patterns from "@aws-cdk/aws-ecs-patterns";
import { DockerImageAsset } from "@aws-cdk/aws-ecr-assets";

export class CdkPartStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

 const APP_PORT = 3000
 const pathToDockerFile = "../front"

    const vpc = new ec2.Vpc(this, "MyVpc", {
      maxAzs: 2,
    });

    const taskDefinition = new ecs.FargateTaskDefinition(this, "MyTaskDefinition", {
      memoryLimitMiB: 512,
      cpu: 256,
    });

    const dockerFile = new DockerImageAsset(this, 'DockerFileAsset', {
      directory: pathToDockerFile,
      file: 'Dockerfile',
    });

    // cdk will build it and push it to en ecr repository
    const image = ecs.ContainerImage.fromDockerImageAsset(dockerFile);

    const container = taskDefinition.addContainer("MyContainer", {
      image,
      // store the logs in cloudwatch 
      logging: ecs.LogDriver.awsLogs({ streamPrefix: "myexample-logs" })
    });

    container.addPortMappings({
      containerPort: APP_PORT, 
    });

    const cluster = new ecs.Cluster(this, "MyECSCluster", {
      clusterName: "MyECSCluster",
      containerInsights: true,
      vpc,
    });

    const securityGroup = new ec2.SecurityGroup(this, `My-security-group`, {
      vpc: vpc,
      allowAllOutbound: true,
      description: 'My Security Group'
    });

    securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(APP_PORT));

    const fargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'MyFargateService', {
      cluster,
      publicLoadBalancer: true,
      cpu: 256,
      desiredCount: 1,
      memoryLimitMiB: 512,
      taskDefinition,
      securityGroups: [securityGroup]
    })

    const scalableTarget = fargateService.service.autoScaleTaskCount({
      minCapacity: 1,
      maxCapacity: 2
    })

    scalableTarget.scaleOnCpuUtilization('cpuScaling', {
      targetUtilizationPercent: 70
    })
  }
}
``` 

Now time for deploy 

```
cdk synth
``` 
Then after that : 

```
cdk deploy
``` 

The deploy can be a little long , so be patient :) 

### Let's go to the console 

After the deploy is completed, go to your AWS Console > ECS (for Elastic Container Service)


![Capture d’écran 2021-08-18 à 19.32.59.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308029943/hS9F6JDe2.png)

Click on MyECSCluster


![Capture d’écran 2021-08-18 à 19.34.07.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308068125/9SIjePWlE.png)

Click on the service

![Capture d’écran 2021-08-18 à 19.34.53.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308120568/BKEqT1rTl.png)

Select the Task Tab

![Capture d’écran 2021-08-18 à 19.35.03.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308170683/NfIAkm89d.png)

Click on the Task


![Capture d’écran 2021-08-18 à 19.37.35.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308267543/wfRWylVQpW.png)

You can see that your container is ... RUNNING :) 

### Let's see the app !!! 

Go to the console > EC2 > LoadBalancer and copy the DNS name of your load balancer


![Capture d’écran 2021-08-18 à 19.38.43.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308377424/fd4DmwfWw.png)

Paste it in your browser and ... 


![Capture d’écran 2021-08-18 à 19.40.10.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629308422041/VcSSwju0T.png)

Congrats ! You deployed your Next.js app with Fargate and it's running :) 

### Cleaning

Don't forget to clean after this tutorial, i don't want you to have a huge bill on AWS! 


```
cdk destroy
``` 

I hope you liked this tutorial, i will try my best to post some articles about AWS.

If you want, you can follow me on Twitter :)