Deploy NUXT with SSR on AWS Elastic Beanstalk

Jimmar · January 11, 2022

I couldn’t find any tutorial for deploying a server side side rendered nuxt application on AWS EB so I wrote one to save everyone the pain (also as a pain saver for future me when I’d need to do this again).

TL;DR

This is the quick read section, if you want to read the full version then check out the step-by-step section down below.

  • Install the Elastic Beanstalk command line interface (if you use homebrew then you can install it with brew install awsebcli)
  • Create a .ebextensions directory in the root directory of your nuxt project.
  • Create a file called 01_nuxt.config and put this in it
container_commands:
  01_nuxt_build:
    command: "npm install && npm run build"
  • From your project root directory run eb init and follow the instructions.
  • Commit all the changes (make sure you include .ebextensions directory and everything in it in your git commits)
  • Run eb create dev-env (or whatever name you want to pick) this will create an environment and deploy your app to it.
  • If the previous command failed for any reason run eb logs to get the logs.
  • You can deploy again by running run eb deploy.
  • Run eb open to open your app
  • Fin

Note: You can also deploy from staged files with eb deploy --staged if you don’t want to commit the changes yet and eb status will get you info about your enviroment. Another Note: I’ve had issues deploying nuxt to EB instances running node 16, but it worked fine running node 14.


Step by step

Most of the tutorials that I found (including the official one) were showing instructions for how to deploy a static nuxt app, if that’s what you want then you might be better off checking those tutorials however if you want to deploy a nuxt app with Server Side Rendring then this is for you 😁.

Elastic Beanstalk

Elastic Beanstalk (EB) is a managed AWS service, it basically makes it easy to deploy and accumelate resources for your apps depending on your configurations and needs. If you’ve used Heroku then it does a similar job, but a bit more complicated to work with.

EB is organized in a way so that you’d have an application that can support one or more environment, each enviroment would have it’s own resources, the idea is to make it easier to have a dev/staging/production setup.

It’s important to note that EB would provision EC2 machines for you to use, you can use the aws console or the command line to interact with EB but it’s better to avoid modifying any of the resources outside of EB (like don’t modify the ec2 instance from the EC2 section of the aws console unless you know what you are doing) since that might cause your environment in an unstable satate (I learned that the hard way 😅)

I’m gonna assumes that you already have an AWS account (duh) and that your application is on a git repository.

Start here

Alt Text

We are gonna use the Elastic Beanstalk command line interface so you need to install it first.

If you use homebrew on MacOS then you can install it with brew install awsebcli but if you don’t use homebrew why not ??

Initialize all the things !!

When that is all done, navigate to your app directory and run the init command

eb init

If you have not set up your aws credentials then you’d need to provide those, if you don’t know how to get the application credentials then check this url.

Name the application whatever you want then chose Node.js as your platform, select yes for ssh (it’s good to have ssh access to your instance).

Also make sure you pick Amazon Linux 2 as your platform.

This will initialize your application, it’ll also create a directory called .elasticbeanstalk with file called config.yml which contains your application configurations.

Creating an environment

Make sure you are on the correct branch that you want to associate with the environment you want to create (don’t worry much though, that can be changed) then use this comand

eb create dev-env

you can name your environment whatever you want, in this case I just called dev-env since it’s the development environment but you can be more specific and use a format like sitename-nuxt-dev and for your production sitename-nuxt-prod.

The create command will create an environment and provision all the resources needed then it’ll deploy your app, it might take like 5 minutes to create the environment. By default it’ll compress the whole directory while abiding by your .gitignore and upload it to S3, even if it said that it succeeded, it won’t be running properly because we haven’t finished configuring it. The create command should run fine, but it will fail during the deploy step which is fine. To check the status of the instance we can use eb status and to get the logs we can use eb logs.

Alternatively, you can also go to the Elastic Beanstalk page in your console and you’ll see your application and your environment there (make sure you are viewing the page on the same region).

If you click on the environment you just created, you should be able to see the option to retrieve the logs on the left side which gives you the option to fetch the last 100 lines of each log file or get the full bundle.

While you are there, you can also edit the Configuration -> Software options to add any environment variable that your application would need.

Why did it fail ?

Alt Text

The deployment would fail because EB would try to run npm run start on your app, which needs the application to be built first ! Even if you built the app locally by running npm run build, it’ll create a .nuxt directory that contains your production app BUT that directory is already included in .gitignore so it’ll be ignored.

One (unrecommended) solution would be to introduce an .ebignore file which will be used instead of .gitignore and have it ignore everything except for those directories/files:

package.json
nuxt.config.js
.nuxt/
static/

But that means you’d have to locally build everything everytime you want to deploy, why would you do something manually when you can have the server automate it for you ? let’s do that !

Running eb ssh and understanding what’s going on [Optional].

If you are in a hurry and have a deployment deadline in an hour, then skip this part .. actually .. shouldn’t you be just reading the TL;DR section ? this is a good time to reflect on your life choices

Before resuming this, if you want to check the state of the app, you can ssh into the server by running eb ssh (or eb ssh YOUR_ENV_NAME) and it’ll drop you in an ssh session as an ec2-user user.

The app should be in /var/app/ directory which you can get to by running cd /var/app and then ls to see what’s in there.

The way EB works here is that when you deploy a new app, it’ll put in a staging directory then try to run it, if it managed to run it then it’ll move it to a current directory and delete the staging directory, otherwise it’ll remain in the staging directory if you ever wanted to inspect it.

EB uses the user webapp to run everything, so if for example you wanted to try and run the build command yourself on the staging directory to see what exactly is happening, you’d need to switch to that user which you can do by running this command sudo su webapp.

Also if you have your environment variables set up, they won’t be accessible by default, but you can load them using this line

export $(/opt/elasticbeanstalk/bin/get-config --output YAML environment | sed -r 's/: /=/' | xargs)

and you can confirm that it worked by running printenv which should print all your env variables so you can confirm that they are all there.

.ebextensions what ?

Alt Text

NOTE: We are building the project in the same instance that is running the app, for production it’s better to use a something like CodeBuild which is mentioned later on in the article.

EB provides a way for you to automatically interact with it via the use of config yaml files, you can read about all the options on the eb docs but the ones we care about are “Container commands” which according to the docs:

You can use the container_commands key to execute commands that affect your application source code. Container commands run after the application and web server have been set up and the application version archive has been extracted, but before the application version is deployed.

Sounds exactly where we need to build the app , right ? create a directory called .ebextensions in the root of your project, it’ll be in the same level as .elasticbeanstalk and your package.json and create a file called 01_nuxt.config (or whatever you want to call it, nobody will judge you) and put this in it (this is a yaml file so spaces are important)

container_commands:
  01_nuxt_build:
    command: "npm install && npm run build"

Note: eb will run the container_commands in “alphabetical order by name” this is why we have the 01 so that if we ever needed to run any other command we can decide which runs first.

Deploy

This should be it, if you commit this and run

eb deploy

then your app should be deployed successfully !! (yay) If something wrong occurred and wasn’t working as intended, you can get the logs with eb logs, fix it and then deploy again !

Alterantively you can just stage the changes and deploy the staged changes by running.

eb deploy --staged

and it should deploy your app, you can view it by running eb open and your app should be running with all of it’s SSR glory !

Nginx Configurations [Optional]

If you need to change nginx configurations, you can interact with it by putting a file called proxy.conf in this path .platform/nginx/conf.d/proxy.conf/ where .platform should be at the root of your project. One common change would be to increase the max body size (which defaults to 1MB) if for example you were uploading files in your app that might be larger than that, otherwise you’ll get a 413 error like HTTP Error 413 request entity too large. to set it to 30MB for example you should put this in your proxy.conf

client_max_body_size 30M;

and then commit then deploy again.

Code pipeline

If you want to automate the delivery, you can use CodePipeline which can fetch from github (or from any provider), build your project for you using CodeBuild and deploy it to Elastic Beanstalk. For that you should remove the build step from your project (the 01_nuxt.config file from .ebextensions) and instead add a file called buildspec.yml in the root if your project which contains this.

version: 0.2

phases:
  pre_build:
    commands:
      - npm install
  build:
    commands:
      - npm run build

artifacts:
  files:
    - "package.json"
    - "nuxt.config.js"
    - ".nuxt/**/*"
    - "static/**/*"
    - ".platform/**/*"
    - ".ebextensions/**/*"

As above, this is a yaml file, spaces and indentation matters

Just make sure that when setting it up in the console, that you add a build stage and tell it to read from buildspec.yml. Also if you have any environment variables, add them in the build stage on the console when you create the app build configurations.

This will have CodeBuild build the project for you then produce the artifacts mentioned which would get sent to your EB environment.

PS: if you are having issues installing some packages that includes binaries saying Permission denied then you can fix that by adding a .npmrc file containing unsafe-perm=true in the root of your project and including it in the artifacts in buildspec.yml. to understand what this does, check out this blog post

Done !

If you have any comments or if you found any mistakes, drop a comment and I’ll update the post to fix them !

good luck !!

Alt Text

Twitter, Facebook