ReactJs production deployment using Docker and Nginx

Published on
-
5 mins read
-
––– views
Author
  • avatar
    Name
    Endalkachew Biruk
    Twitter
banner

In this article we are going to build and deploy the default create-react-app using Docker and Nginx. To get started let's create a new react project.

npx create-react-app react-app --template typescript

If you want to jump to the code directly, you can use the following link: https://github.com/endalk200/blog_posts/tree/reactjs-docker-setup

Dockerfile

Create Dockerfile and add the following multi stage Dockerfile there.

Dockerfile
# Dependency installation stage.
FROM node:alpine AS dependencies
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine
# to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# React app build stage.
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=dependencies /app/node_modules ./node_modules
## Install build toolchain, install node deps and compile native add-ons
RUN apk add --no-cache python3 make g++
RUN npm run build && npm install --production --ignore-scripts --prefer-offline
# Nginx configuration and runing stage.
FROM nginx:alpine AS runner
# Set working directory to nginx asset directory
WORKDIR /usr/share/nginx/html
# Remove default nginx static assets
RUN rm -rf ./*
# Copy static assets from builder stage
COPY --from=builder /app/build .
EXPOSE 80
# Containers run nginx with global directives and daemon off
ENTRYPOINT ["nginx", "-g", "daemon off;"]

After creating the dockerfile now create .dockerignore file. Any files or directories referenced here will be ignored in th build process. This can help use reduce our image size.

.dockerignore
node_modules/

Let's go over the dockerfile configuration one by one.

Dockerfile:
# Dependency installation stage.
FROM node:alpine AS dependencies
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine
# to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

In this stage of the dockerfile we are going to install the dependencies for the application. Firs chose the node:alpine image. This image is a base image for the nodejs application. Second install libc6-compat which is shared missing library from node:alpine base image so we need to install that. If you want to read more about this refer https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine

Then we are going to install npm dependencies. We are going to use the npm ci command to install the dependencies. This command is preferable over npm install because npm ci is optimized for CI run while npm install is not.

Dockerfile:
# React app build stage.
FROM node:alpine AS builder
WORKDIR /app
COPY . .
COPY --from=dependencies /app/node_modules ./node_modules
## Install build toolchain, install node deps and compile native add-ons
RUN apk add --no-cache python3 make g++
RUN npm run build && npm install --production --ignore-scripts --prefer-offline

This is the build stage. Copy the node_modules directory from the dependency installation stage. Then add python3 make and g++ which are part of build tools in linux, So they will facilitate the build process. Then run npm run build && npm install --production --ignore-scripts --prefer-offline. Basicaly we are runing the build script with production tag. At this point we have the built static files under build directory.

Dockerfile
# Nginx configuration and runing stage.
FROM nginx:alpine AS runner
# Set working directory to nginx asset directory
WORKDIR /usr/share/nginx/html
# Remove default nginx static assets
RUN rm -rf ./*
# Copy static assets from builder stage
COPY --from=builder /app/build .
EXPOSE 80
# Containers run nginx with global directives and daemon off
CMD ["nginx", "-g", "daemon off;"]

We have reached the final stage. At this stage we are going to copy the static files from the build stage to the nginx asset directory. Then we are going to run the nginx container. WORKDIR /usr/share/nginx/html is the working directory where nginx assets reside. we are going to remove the default files and configurations from this directory RUN rm -rf ./*. After removing the default assets we are going to copy the static files from the build stage to the nginx asset directory. Then we are going to run nginx using ENTRYPOINT ["nginx", "-g", "daemon off;"]

Build and Run

In the above section we have created a Dockerfile for the production ready ReactJS application. Now we are going to build the image and run the container. To build the Dockerfile run

docker run -t react-app-image .

Here we are building the dockerfile and naming the resulting image react-app-image. Then we can run the container using the following command:

docker run react-app-image -p 8080:80

Nginx default port is 80 so we need to map that port to our port. Here I have set to 8080. Now we can access the application using the following URL: http//localhost:8080.

Conclusion

Now that we a have our react app runing in production environment the only thing left is configure the IP address, domain and SSL certificate. To refer to the full code for this guide visit https://github.com/endalk200/blog_posts/tree/reactjs-docker-setup