Part Two: Dockerizing for production a TypeScript React App with NGINX using WSL2 Alpine Linux on…

Part Two: Dockerizing for production a TypeScript React App with NGINX using WSL2 Alpine Linux on…

Version 1.0
Date 2022/11/27
By Nicolas Barlatier

Hello all, I hope you are doing okay. You are safe in the hard time we are living now.

Introduction

Today, I will show you how to build a React application Container for production.

Read the last sentence again, it is about building a production-ready container.
It is not about building a production-ready react application with the code and stack where we use the best practices and security of front-end web applications in mind!

I will in the future write an article about the best practices for making production-ready front-end web applications using React.

In the previous article, I showed how to build and run a container synchronised with our local React application code base on the dev machine.

If you want to read it, it is just below:

Part One Dockerizing the TypeScript React App with NodeJS Vs NGINX with WSL2 Alpine Linux on Windows 10

The React application is secured by JWT and Keycloak.

You can read the article in 4 parts:

Part One: Installing Keycloak with Docker and Administration

Part Two: Securing a front-end React application

Part three: Securing the ASP.NET Core C# REST Web

Part Four: Calling the protected Web API from the React SPA with the access JWT Token Bearer Authorization

Our project is available on GitHub in the subdirectory [reactwebapikeycloak](github.com/nicoclau/reactwebapiaspnetcoreke.. "reactwebapikeycloak")

[GitHub - nicoclau/reactwebapiaspnetcorekeycloak: React and REST Web API protected by Keycloak with…
React and REST Web API protected by Keycloak with Authorization Code Flow and JWT Token - GitHub …github.com](https://github.com/nicoclau/reactwebapiaspnetcorekeycloak "github.com/nicoclau/reactwebapiaspnetcoreke..")

Why do we use NGINX in a Docker container for hosting our React application in production?

Before going into action, we need to understand our choices.
Why would we use the NGINX for hosting our React application built for production? Why indeed?

React is an open-source front-end JavaScript library which ultimately builds static assets. So we need a server to serve them.

We will see why NGINX pronounced Engine-X is so popular and is almost always used when deploying one React application on production.

When I think about it carefully, I can think the main solutions available are :

  • NGINX
  • Express
  • Serve by vercel

Moreover the official website of Create React App on the following link about how to deploy our React application on production recommends using a Static Server like Serve or use Express.

[Deployment | Create React App
npm run build creates a build directory with a production build of your app. Set up your favorite HTTP server so that a…create-react-app.dev](create-react-app.dev/docs/deployment "create-react-app.dev/docs/deployment")

But to be honest, we will need way further features than just delivering static content when it is about to use our React application on the production like Authentification, Authorization, Load Balancing,

Also, it is the fastest, below the benchmark showing that for one server with less resources, Nginx handles way more requests per second:

It uses less memory:

Also let’s compare NGINX usage vs other technologies

[Wappalyzer
Edit descriptionwappalyzer.com](https://www.wappalyzer.com/compare/nginx-vs-express "wappalyzer.com/compare/nginx-vs-express")

[Wappalyzer
Edit descriptionwappalyzer.com](https://www.wappalyzer.com/compare/nginx-vs-varnish/ "wappalyzer.com/compare/nginx-vs-varnish")

[Wappalyzer
Edit descriptionwappalyzer.com](https://www.wappalyzer.com/compare/nginx-vs-lightspeed-ecom/ "wappalyzer.com/compare/nginx-vs-lightspeed-..")

We can see right away that NGINX is used way more often than the others.

So now we are convinced and understand why NGINX is used to deploy React.

We will use Docker for two things:

  • Build our production react application
  • Host our production react application within Nginx container

Docker File for Production React Application:

It will divided in two section:

  • Building
  • Hosting

We will call the docker file: dockerfileprod and put the content:

# building

FROM node:19-alpine3.15 AS builder
ENV NODE_ENV production
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
COPY package-lock.json .
RUN npm install --production
# Copy app files
COPY . .
# Build the app
RUN npm run build

# hosting

# Bundle static assets with nginx
FROM nginx:1.23-alpine as production
ENV NODE_ENV production
# Copy built assets from builder
COPY --from=builder /app/build /usr/share/nginx/html
# Add your nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

Note: Mind you I use the npm, but you can update the dockerfile to use yarn for example.

We use the node sdk with alpine distro to build our production react application.

We then use the nginx with alpine distro to be the lightest as possible.
We copy the production react application to the directory used by nginx.
We copy the configuration file nginx.conf we will create now to the directory used by nginx.

Finally we give the command used by the docker container when we run our app image with docker.

Let’s add our nginx.conf file:

server {
listen 80;

location / {
root /usr/share/nginx/html/;
include /etc/nginx/mime.types;
try_files $uri $uri/ /index.html;
}
}

It is bloody simple, only the last line is interresting, it says when the url doesn’t match any resource, we go the root /index.html. It will be handed by the react router :)

Let’s see our project directory structure.

λ tree /f
Folder PATH listing for volume OS
Volume serial number is C0000100 8021:2C9C
C:.
│ .dockerignore
│ .gitignore
│ Dockerfile
│ dockerfileprod
│ nginx.conf
│ package-lock.json
│ package.json
README.md
│ tsconfig.json

├───public
│ favicon.ico
│ index.html
│ keycloak.json
│ logo192.png
│ logo512.png
│ manifest.json
│ robots.txt

└───src
│ App.css
│ App.test.tsx
│ App.tsx
│ index.css
│ index.tsx
│ logo.svg
│ react-app-env.d.ts
│ reportWebVitals.ts
│ setupTests.ts

├───security
│ KeyCloakService.tsx

└───services
HttpServices.ts

Let’s build our container image now, it takes a while to install all the dependencies.

C:\Tutorial\keycloak\reactwebapikeycloak\reactonlywithkeycloak\myapp (main -> origin)
λ docker build -f dockerfileprod -t myreactnginx:1 .
[+] Building 115.4s (16/16) FINISHED
=> [internal] load build definition from dockerfileprod 0.1s => => transferring dockerfile: 36B 0.0s => [internal] load .dockerignore 0.1s => => transferring context: 35B 0.0s => [internal] load metadata for docker.io/library/nginx:1.23-alpine 0.7s => [internal] load metadata for docker.io/library/node:19-alpine3.15 0.9s => [builder 1/7] FROM docker.io/library/node:19-alpine3.15@sha256.. 0.0s => [internal] load build context 0.1s => => transferring context: 965B 0.0s => CACHED [production 1/3] FROM docker.io/library/nginx:1.23-alpine@sha256:.. 0.0s => CACHED [builder 2/7] WORKDIR /app 0.0s => [builder 3/7] COPY package.json . 0.2s => [builder 4/7] COPY package-lock.json . 0.3s => [builder 5/7] RUN npm install --production 92.8s => [builder 6/7] COPY . . 0.1s => [builder 7/7] RUN npm run build 19.9s => [production 2/3] COPY --from=builder /app/build /usr/share/nginx/html 0.1s => [production 3/3] COPY nginx.conf /etc/nginx/conf.d/default.conf 0.1s => exporting to image 0.2s => => exporting layers 0.2s => => writing image sha256:6e6ceb15aa23c2d92a540a1493494ed2129c56ad0701c6fa889c09a7881d660b 0.0s => => naming to docker.io/library/myreactnginx:1 0.0s
.....
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

It took 2 minutes the very first time, but the next time we build it takes only 20 seconds with the help of the layers in the cache.

Let’s check our container image:

λ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myreactnginx 1 6e6ceb15aa23 6 minutes ago 24.4MB

Only 24 Mb :)

Now we are ready to run our production react application hosted within the Nginx container.

To read the documentation about how to run the nginx container please go to:

[Deploying NGINX and NGINX Plus on Docker
Deploy NGINX and NGINX Plus as the Docker container. NGINX Plus, the high‑performance application delivery platform…docs.nginx.com](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-docker/ "docs.nginx.com/nginx/admin-guide/installing..")

The main command is:

docker run --name mynginx1 -p 80:80 -d nginx

In our case we will not use port 80, we will use port 8081 and our container image name is: myreactnginx:1

so we do:

docker run --name myreactnginx -p 8081:80 -d myreactnginx:1

We get:

C:\Tutorial\keycloak\reactwebapikeycloak\reactonlywithkeycloak\myapp (main -> origin)
λ docker run --name myreactnginx -p 8081:80 -d myreactnginx:1
9339c4b1b50498861c4401b27b7c78cd97879e8ebc0874b950b920e7fddefb8b

Let’s check our running container:

C:\Tutorial\keycloak\reactwebapikeycloak\reactonlywithkeycloak\myapp (main -> origin)
λ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9339c4b1b504 myreactnginx:1 "/docker-entrypoint.…" 33 seconds ago Up 32 seconds 0.0.0.0:8081->80/tcp myreactnginx

We see we can call our application on the port 8081, and we get:

Please make sure keycloak is running with docker on port 8080:

C:\Tutorial\keycloak\reactwebapikeycloak\reactonlywithkeycloak\myapp (main -> origin)
λ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e6cf7557d52e quay.io/keycloak/keycloak:18.0.0 "/opt/keycloak/bin/k…" 8 minutes ago Up 8 minutes 0.0.0.0:8080->8080/tcp, 8443/tcp trusting_burnell
9339c4b1b504 myreactnginx:1 "/docker-entrypoint.…" 11 minutes ago Up 11 minutes 0.0.0.0:8081->80/tcp myreactnginx

If you need help with keycloak and react, you can find it by reading the two first parts of my article:

[Part One: Security with Keycloak in React and Web Api in ASP.NET
Part One: Installing Keycloak with Docker and Administrationsystemweakness.com](https://systemweakness.com/security-in-react-and-webapi-in-asp-net-core-c-with-authentification-and-authorization-by-keycloak-1d076777a979 "systemweakness.com/security-in-react-and-we..")

[Security in React and WebApi in ASP.NET Core C# with authentification and authorization by KeyCloak
Part two: Securing a front-end React application
Version 1.0
Date 2022/05/29
By Nicolas Barlatier
blog.devgenius.io](https://blog.devgenius.io/security-in-react-and-webapi-in-asp-net-core-c-with-authentification-and-authorization-by-keycloak-89ba14be7e5a "blog.devgenius.io/security-in-react-and-web..")

After logging in we get:

Conclusion

Congratulations you now know how to build you react application for production by hosting it with the very powerful nginx in your customized container image!

Please if you need help, or have any questions ask me. If you liked my articles, you can follow me and give some claps :)