In this post I'll explain a setup for one of my NextJS websites on elasticbeanstalk. You probably already know about what are NextJS, Nginx and elasticbeanstalk, so I'll skip the introductory definitions.
I have a hybrid NextJS website. Some content is
- SSG which stands for Static-Site Generated
- SSR which stands for Server-Side Rendered
Hint: If you just have a static nextjs app, maybe this post will work better.
My hybrid NextJS website is running on an elasticbeanstalk service, single instance, on the ec2 t2.micro with 1G RAM.
At the time of the writing, I couldn't chose running elb environments without a proxy. Only available options were Apache or Nginx. Since I'm more familiar with Nginx, I configured elb running on NodeJS 16 behind Nginx.
When I think about it, maybe running a NextJS app behind a proxy isn't such a bad idea. When you build a NextJS app, you get plenty of static files in the next directory. Proxy servers like Apache and Nginx are better suited for serving statics.
First steps
You can run your Nextjs app on elastic beanstalk by simply uploading a package to your eb environment.
You don't need to configure anything, default port will be whatever is defined in the PORT environment variable and will run on 8080 by default.
This simple script will prepare the app for uploading to eb environment.
#!/bin/bash
declare -r app_name="package-demo"
declare -r version="1.0"
# Stops execution of the script if error
set -e
export NODE_ENV=production
npm run build
zip -r app.zip .next pages public styles *.json *.js
Npm packages that require native libraries
You might have stumbled upon sharp issues when you installed it as a recommendation for NextJs image optimization. You might see something like this:
Sharp requires libvips, and it has something to do with permissions when deploying your app, better said in this github issue. But really this isn't just a problem with sharp, it will affect any kind of npm library that uses native system libs. So, my solution is just add a pre build hook that installs all dependencies, except dev ones.
And the script - don't forget to chmod +x it:
00_npm_install.sh
#!/bin/bash
set -e
EXIT_CODE=0
cd /var/app/staging
runuser -u webapp -- npm i --omit=dev || EXIT_CODE=$?
echo $EXIT_CODE
Serve static behind Nginx
Although Node app would probably do fine at serving a file, I think Nginx is faster. No need to burden the app with static request calls, when nginx can just call a sendfile.
What can be served only behind nginx is everything located in _next/static and favicon.ico.
00_application.conf
location ^~ /_next/static/ {
alias /var/app/current/.next/static/;
sendfile on;
sendfile_max_chunk 2m;
access_log off;
expires 30d;
add_header Cache-Control public;
tcp_nodelay off;
}
location = /favicon.ico {
alias /var/app/current/public/favicon.ico;
sendfile on;
sendfile_max_chunk 2m;
access_log off;
expires 30d;
add_header Cache-Control public;
tcp_nodelay off;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Add swap space
If you experience app crashes, probably your ec2 instance is too weak. If you don't want to invest into stronger instance, a cheap workaround is adding swap space. Keep in mind that this solution will slow down your app deployments.
Add another hook, like in the picture above. Don't forget to chmod +x it.
01_add_swap.sh
#!/bin/bash
set -e
EXIT_CODE=0
if [[ ! -f /swapfile ]]
then
dd if=/dev/zero of=/swapfile bs=128M count=8
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
swapon -s
else
echo "Skipping add swap. Already defined!"
fi
echo $EXIT_CODE
The End
Read this If you'd like to ssh to elastic beanstalk ec2 instance and don't know how.
I wrote several articles on configuring nextjs, maybe you're interested.
All code is available in the Github repo https://github.com/amarjanica/demo-nextjs-elasticbeanstalk.