For the past few hours, I've been working on dockerizing a Nuxt.js server-side rendering app to be deployed to AWS Elastic Container Service (ECS). I hit a stone wall when environment variables are not properly injected on runtime on ECS. In this post, I will walk us through steps to properly dockerize Nuxt.js SSR apps and share some of the lessons I learnt. There are 2 major ways to dockerize Nuxt.js apps, and each of them has its shortcomings: 1. : The Nuxt app is built after Docker image is built, when the container is spawned. The downside of this is the container boot time takes significantly longer as it involves building the artifacts on run. This also violates the principle of a 12-factor app. Nuxt build on run build/release/run 2. : For this, sensitive environment variables are injected during stage. The upside is the boot time is much shorter now, hence, quicker revert time in case you need to revert to an older version. However, the downside is the sensitive variables are now bundled into our Docker image and it requires a rebuild every time a variable is updated. Nuxt build on Docker build docker build For this post, I will be using the first method, "Nuxt build on run". How environment variables works in Nuxt.js apps? Let's revisit how environment variables work in Nuxt apps. Some of us may already be familiar with the property in , which allows us to inject sensitive values from your terminal environment to the app on runtime. env nuxt.config.js { : { dbUri: process.env.DB_URI } } // in nuxt.config.js export default env /** * dbUri is accessible from both client and server side. */ From the snippet above, is read and injected to when we run the app for any purpose. ( , or ) When serving a production build, our environment variables are most likely different from environment to environment. Thus, if we build our app ( ) as part of the building steps of our Docker image, any sensitive environment variables that is injected when we run our Docker image ( ) will not work as the artifact has been built before these variables are injected. DB_URI dbUri nuxt start nuxt build nuxt nuxt build docker run ... How to safely inject environment variables into Dockerized Nuxt.js on runtime? By adopting " ", we adhere to: Nuxt build on run Principle 1: Build and serve on runtime! Principle 2: Never embed any sensitive value in Dockerfile { ... : { ... : , : , : ... } ... } "scripts" "build" "nuxt build --modern=server" "start" "nuxt start" "prod" "yarn build && yarn start" To serve a production build, all we need to do is to run . yarn prod In my : Dockerfile node: . APP_DIR /app/ HOST . FROM 10.16 3 ENV WORKDIR ${APP_DIR} COPY . ./ RUN yarn install ENV 0.0 0.0 # Insensitive environment variable EXPOSE 3000 CMD [ , ] "yarn" "prod" Here we go! Our dockerized Nuxt app is ready. We can run our Docker image using or alternatively with Docker Compose. I personally use Docker Compose a lot. In my case, I created a that inject environment variables from the file in same directory. docker run docker-compose.production.yml .env My : docker-compose.production.yml version: "3" services: web: build: . restart: always env_file: - .env ports: - "3000:3000" Once ready, we run to bring up our containerized Nuxt app. docker-compose -f docker-compose.production.yml up -d How to safely inject environment variable for dockerized Nuxt.js on AWS ECS This section is only applicable if you choose ECS as your deployment platform of choice. In this section, I will walk us through: storing sensitive values using AWS SSM Parameter Store building and pushing image to image registry creating an ECS task Step 1: Storing Sensitive Environment Variables in Parameter Store AWS provides several products for the purpose of storing sensitive configurations, namely AWS SSM Parameter Store and AWS Secrets Manager. I use Parameter Store because of its' free 10,000 Standard tier parameters. To add a parameter, click "Create Parameter" in the Parameter Store Management Console: Fill up the form, then submit: We should see the parameters created: We will leave the parameters created for now. These will be consumed in a latter step. Step 2: Building and Pushing Image to Image Registry To deploy our Nuxt.js app to AWS ECS, we first require a repository to store our Docker image. For the sake of simplicity, I use AWS Elastic Container Registry (ECR). The provides a comprehensive list of steps to create a repository on AWS ECR. official guide Once the image repository is created, we can then build and push our image: docker build -t <image_name> . docker tag <image_name>:latest <remote_repository_url> docker push <remote_repository_url> $ (aws ecr get-login --no-include-email --region <region>) Navigating to our repository with AWS Management Console, we should see our image pushed: Step 3: Create an ECS Task This details the steps to create a Task definition in ECS. It is highly suggested to read if you are not familiar with the concepts of Task and Service in ECS before moving forward. guide this While creating an ECS Task with the Management Console, you can now reference to parameters created in SSM Parameter Store by using the ARN of the parameters. Once the Task is created, we can then run it on ECS. Navigating the the endpoint of your Task, you should be able to see your app is up and running. Voila! Now we have a dockerized Nuxt.js SSR app that is running on ECS with sensitive environment variables stored on SSM Parameter Store. Have fun hacking around! This was first published on melvinkoh.me