Deploying React app to Jelastic with NGiNX

This post addresses the steps required to get your own custom Docker image running on Jelastic.

For example, I want to serve a React app from Jelastic. Of course I want a setup where I can deploy to production in a pretty straight forward way. Ideally using only the command line.

To serve our React app, we need a server to respond to requests over http. It has to have a mechanism to route all requests to index.html. So we have either Apache, Nodejs, Nginx. Apparently Nginx is pretty lightweight; that's what we'll use.

We need an Nginx capable of receiving the source code somehow. Jelastic has the option for the Nodejs container to pull your source code from vcs. This is done after the container creation in the "Deployments" section.

Read jelastic forever to see how intertwined using the default Node container is.

Constraints of Jelastic: In order to deploy a React app on Jelastic, you need to docker run your own react-nginx image.

In Jelastic to have your own image, you need to load it from a registry (be it private or public). One option is to use the docker hub registry image and run it on Jelastic as a new environment over plain http.

Of course, a registry over http is unthinkable, and it's a horrible pain to set up ssl in front of the registry image. How that is performed I don't know.

What they suggest is to use an unsecured version of the registry (without ssl, over plain HTTP). Although it is definitely not recommended in production, using it as a bootstrapping registry may prove useful.

IMPORTANT: using the insecure registry allows you to build and push images to it without too much hassle and from there you can upload a secured image version of the registry, for example, and delete the unsecured one, once you have confirmed functionality of the secured one.

Anyhow if you are on Ubuntu locally, you need to install Docker and allow insecure repository for our specific Jelastic private repository:

sudo vim /etc/docker/daemon.json

Add the contents below and save. Note that you have to enter the endpoint with the nodeXXX- part as well as the appropriate publicly exposed IP, which was automatically assigned when you add+ the endpoint for TCP port 5000.

{
  "insecure-registries" : ["node37385-registry.jcloud-ver-jpc.ik-server.com:11555"]
}

Now that you have that, you need to sudo service docker restart.

Now both Jelastic registry and local environments are ready to start pushing your custom images to Jelastic.

Building the React / Nodejs / Nginx multistage image

IMPORTANT to make this all work cd to your app's root directory. All dirs are relative to the root of your react app.

You will have to add a few things to your react project:

  1. ./nginx/nginx.conf : the nginx configuration
  2. ./.dockerignore : tell docker to ignore node_modules
  3. ./Dockerfile : the image building spec

1. ./nginx/nginx.conf

Let's start by using a very simple ./nginx/nginx.conf that we will later use to replace the nginx:alpine's default.conf file :

server {

  listen 80;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;

    error_page   500 502 503 504  /50x.html;

    location = /50x.html {
      root   /usr/share/nginx/html;
    }
  }
}

NOTE: this works with react-router-dom out of the box.

2. .dockerignore

You need to not track node_modules (why?, because we are going to get a react build, and this will create static files that will contain all the necessary code). To ignore node_modules, create a ./.dockerignore at the root of the react app, and add this line:

node_modules

3. Dockerfile

Now with the image creation.

We will use node to build the react app.

# Prepare two environments
# 0. where the application is built
# 1. where the application is run
# https://cloud.google.com/community/tutorials/deploy-react-nginx-cloud-run
# https://www.youtube.com/watch?v=Sm8GbC02MlE

# 0. build environment
FROM node:alpine as build-stage
# any dir you want actually
WORKDIR /app
# copy the react app to the container to a random dir /app
COPY . /app/
# prepare the container for building react
RUN npm i
RUN npm i react-scripts@latest -g
RUN npm audit fix
RUN ENDPOINT="https://graphql.cronide.com"
RUN npm run build

# at this point we could use the serve command
# serve -s build
# to have it running on node under build/server.js
# but we want to run it on nginx, so we do a next stage

# 1. server environment
FROM nginx:alpine

# copy nginx config file to appropriate location
COPY nginx/nginx.conf /etc/nginx/conf.d/

# copy react built app to nginx public document root
COPY --from=build-stage /app/build /usr/share/nginx/html

# fire the app and pause everything else
# The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.
EXPOSE 80

# Exec Form does not work on Jelastic
# CMD ["nginx", "-g", "daemon off;"]
# is absorbed by Jelastic as the CMD to start the container
# WARNING: but it does not escape it properly

# so instead use this Shell Form:
CMD nginx -g "daemon off;"

Pre-Conclusion

With this we should be all setup. But we are not.

What we have here is a plain HTTP application. But we wanted SSL (HTTPS).

There are a few solutions proposed by Jelastic:

  • adding an Nginx load balancer in front of your Nginx server container. The load balancer has the ability to get an SSL Certificate from a marketplace "Let's encrypt Certificate" plug-in. The load balancer terminates ssl and forwards it to our custom Nginx container as HTTP.
  • Not adding any load balancer and use their shared SSL certificate, which is issued for your hosting Jelastic's platform reserved domain. So it won't work for your own custom domain. Use this *if you are not going to use your own custom domain. You could also redirect your custom domain to the jelastic domain (*.jcloud-ver-jpc.ik-server.com/), and your users would see the latter, which is sub optimal.

The first is an ok solution if you don't want to bother with generating your certificates etc. But now you have two containers running instead of one. So $$$.

Using Nginx with TLS

What we are going to do is download