In this tutorial we will see how we can deploy our NextJS application using NodeJS and Docker on Elastic Beanstalk, but first, lets talk about what Elastic Beanstalk is.
Elastic Beanstalk is AWS managed service for deploying, scaling and managing web application and services. Being a managed service means that AWS Elastic Beanstalk will take care of all deployment from capacity provisioning, load balancing, and auto scaling to application health monitoring. All you need to do is upload your code as we will do in this walk through. Though there are other managed services like Heroku, Vercel, Engine Yard, Netlify, Azure DevOps, and DigitalOcean App service, that perform capacity provision, Elastic Beanstalk some more edge than they do, especially cost wise.
Let’s talk briefly about the pros and cons of Elastic Beanstalk.
pros of Elastic Beanstalk
Support: AWS Elastic Beanstalk has of support for many popular programming languages, including Java, .NET, PHP, Node.js, Python, Ruby, Go, and also Docker web applications.
Powerful Customization: Elastic Beanstalk as a combination of various AWS Service deployed for you means you can customize them to your taste. With that you can SSH into the EC2 server, change the Security group, add environment variables, increase or decrease server type, etc. They are all under your control.
Price and Flexibility: One good thing about Elastic Beanstalk is its good pricing. While you can easily match your application load to the deployed service, and also easily scale down. Thanks to the Autoscaling group.
cons of elastic beanstalk
Deployment Speed: The deployment on Elastic Beanstalk ranges from 5 minutes to 15 minutes for the simplest application. While this looks cool, it may be a drawback especially if you are managing a simple application that requires fast deployment and response in real time.
Stack Upgrades: The Beanstalk stack is a combination of AWS services that meets your application deployment requirement managed by AWS team. This translates to recieving regular updates. This updates are not mentioned in some cases, therefore can turn out you will be blind to what is going on in your stack. However, AWS CloudWatch events and logs can come to help with visibility.
Complex Troubleshooting: This is a bounce of from the above point. For one like me, I love to get my hands dirty when troubleshooting, however, with elastic beanstalk, I can be a little difficult finding what went wrong when an application fails deployment or health check. Like while I attempted deploying the first time, the Health status was 5xx error. There are different causes of that error there, and so, I had a hard time figuring out the issue. Though, AWS did justice bu providing the logs to give hints as to what is going wrong.
create beanstalk application
That been said, let’s move into deploying our application. We will start with using NodeJS, and then later, see how we can use docker.
Search for the AWS Elastic Beanstalk, then click the Create Application.
You will be asked for the Application Name. I named mind testbeanstalk. Also, I added tags to identify my deployment.
Once we settled the platform, we will select the Application code, and since we are not testing Elastic Beanstalk, go ahead and select the Upload Your Code option.
You can also clone and upload the same Nextjs source code I used from my repository here. I have extracted the needed artifacts from the next build before pushing to that repository. You will see how to use the full source code later when we use docker multistage build to host Elastic Beanstalk.
upload zipped source code folder
Let’s proceed to select the location to upload the folder. As at the time of this writting, AWS Elastic Beanstalk only allows only two source code origin. Local File which is a zip file you upload from your machine, or Public S3 URL, which is the URL of the S3 bucket where you upload the code.
I have the code in my local and zipped it already. So, I will select the Local File option, then Choose File.
NOTE: You will need to zip the root content of your project before uploading it into Elastic Beanstalk. Make sure your project contains the package.js, index files and node_modules directory in the zipped folder.
One more important step is to tell Elastic Beanstalk to ignore any elevated commands when compiling our code. So, we will add the NPM_CONFIG_UNSAFE_PERM in the environment properties.
Click the Configure More Options, select Software, click the Edit button.
Scroll down to find the Environment Properties and type in NPM_CONFIG_UNSAFE_PERM under Name, and true under value. Then, click on the Save button.
In the next window, click on the Create App button. This send you configuration in “active mode” and since Elastic Beanstalk is a managed service, AWS will commence the deployment of your application and also configuration of all the needed services on your behalf. The service includes, EC2, AutoScaling Group, Security Group, and some more.
checking your deployment
You should get a screen like the below showing you the process of deploying you application. This will usually take some minutes to complete.
After the above process completes, you will get a status page showing the Health status and the Beanstalk URL for you application. You will also get some events logs at the bottom of the health status.
Grab the URL of from Elastic Beanstalk deployment and paste in your web browser. The app we deployed is a NextJS app default page.
And you successfully deploy your application using Elastic Beanstalk, next, we will deploy the same application using Docker to Elastic Beanstalk.
deploy with docker to elastic beanstalk
To begin, we will create a Dockerfile at the root of our source code directory. We will use the multi-stage docker configuration. This will ensure our image is a light as possible.
FROM node:18-alpine AS builder WORKDIR /app COPY package.json /app RUN npm install COPY . . RUN chmod -R 777 /app RUN npm run build FROM node:18-alpine AS runner WORKDIR /app COPY --from=builder /app/.next/standalone ./.next/standalone COPY --from=builder /app/.next/static ./.next/standalone/.next/static COPY --from=builder /app/public ./.next/standalone/public EXPOSE 3000 CMD [ "node", "./.next/standalone/server.js" ]
Now, let’s create our Elastic Beanstalk for docker deployment. Enter the name of your application.
Under the Platform option, we will select the Docker. The branch and platform version remains the latest from AWS.
zip the source code
Then, select the Upload Your Code option, and again upload the zipped source code containing the Dockerfile at the root of your project. Get the source code from here.
Then click on the Create Application.
After a few minutes you should see the successful deployment of your application using docker engine which AWS Elastic Beanstalk created for us.
Now you can deploy your application using AWS Elastic Beanstalk using NodeJS and Docker. You can also checkout how to deploy using aws code pipeline too.
- ERROR: permission denied for npm run build
SOLUTION: Change the file or directory mode to executable or to allow the present user access to it.
RUN chmod -R 755 /app
- ERROR: Getting a 502 error after the deployment completes with a severe health status.
SOLUTION: Change the start command inside the packaga.json from “next start”, to “node server.js” or “node startfile.js”.
Where the startfile.js is your script that is responsible to start your application.
- ERROR: Error: Cannot find module ‘/var/app/current/server.js’
SOLUTION: Check to be sure the server.js is at the root of the project. Add it there if it is not and rezip the directory.
- ERROR: 100.0 % of the requests are failing with HTTP 5xx.
SOLUTION: The means the application deployed successfully, however, it could not be served. Check that the zips artifacts are the correct files and directories compiled to run the application. For Next, check that you compiled the build into a standalone subdirectory inside the .Next directory after the build.
- ERROR: RUN npm run build
—> Running in c9296c1b349e
[91msh: [0m[91mnext: Permission denied
SOLUTION:This happens when Elastic Beanstalk does not have root permission to run the npm run build command. Add the .npmrc file in the root of the project. Add the below snippet in the file.
You can set this environement configuration in the Beanstalk console.
Environment > EnvironmentName > Configuration
Scroll to Software Settings and add the environment variable NPM_CONFIG_UNSAFE_PERM = true.
Also, create a 01_fix_permissions.config inside .ebextensions directory in the root of your project and add the config below.
files: "/opt/elasticbeanstalk/hooks/appdeploy/pre/49_change_permissions.sh": mode: "000755" owner: root group: root content: | #!/usr/bin/env bash sudo chown -R ec2-user:ec2-user tmp/