Deploying a React+Node App with Nginx as Reverse Proxy on Azure Container App: A Comprehensive Guide
Published Apr 15 2024 03:08 AM 1,336 Views
Microsoft

This blog demystifies the process of deploying a React+Node application using Nginx as a reverse proxy on Azure Container App. This blog will serve as a hands-on guide to help you navigate the complexities of deploying your React+Node application on Azure. We’ll cover everything from setting up your environment to configuring Nginx and Azure Container App.

 

Prerequisites

As stated in our official documentation for Azure Container Apps, there are two types of ingress that can be enabled: External and Internal. In addition, it supports both HTTP and TCP for ingress protocols. For this demo we will require Ingress-enabled Container App and Azure Container Registry to build and publish Docker containers.

 

Architecture

The architecture features an Nginx container that will be accessible over the public internet, with React and Node container apps configured to be internal. Nginx will direct incoming requests to either react-fe-app or node-be-app based on the URL path specified. Furthermore, the react-fe-app communicates with the node-be-app APIs via Nginx. The node-be-app handles requests routed by Nginx and serves the response accordingly.

 

image.png

 

For Example: In the outlined sequence, the initial requests arriving at the '/' path of Nginx are proxied to react-fe-app. Subsequently, when react-fe-app initiates a call to '/api', for a server response, the request is initially captured by the Nginx reverse proxy and it is then directed to the node-be-app, which hosts the backend server application.

 

Each app is supported by its own replica sets for efficient request handling and scalability within a secure network environment. This setup optimizes traffic routing, enhances performance, and enables seamless communication between the frontend and backend components. The frontend and backend apps are shielded from direct internet access, thereby providing isolation and abstraction to the users. Additionally, the application content is only exposed at the container app environment, which provides added security to the application.

 

Client App

To create the client application, first ensure you have Node.js installed on your system. Then, run the command npm create vite@latest client --template react in your terminal, which scaffolds a new project in a directory called client using the React template. Once the project is created, navigate into the project directory with cd client. Install the necessary dependencies by running npm install.

 

Axios is a popular JavaScript library that can be utilized to make outbound calls to backend APIs. The below code snippet configures the Axios library to set up a default instance for making HTTP requests to nginx container app.

 

import axios from "axios";

export default axios.create({
    baseURL: "https://nginx-proxy.icysky-8546baf3.westus2.azurecontainerapps.io/api/"
});

 

  • axios.create(): This function creates a new instance of Axios with custom configuration.
  • baseURL: This property sets the base URL for all HTTP requests made through this Axios instance.

 

When you make an API call using this Axios instance, it will automatically prepend the baseURL to your request paths. For example, if you make a request to /home, Axios will convert it to https://nginx-proxy.icysky-8546baf3.westus2.azurecontainerapps.io/api/home.

 

The baseURL points to an NGINX server configured as a reverse proxy. This means that NGINX will receive the requests and forward them to the appropriate backend service by abstracting internal architecture.

 

You can start the development server by executing npm run dev. This command compiles the React application and hosts it on a local server, typically accessible via http://localhost:5173 in your web browser.

 

Now we will containerize the client application using the below dockerfile.

 

FROM node:alpine
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
EXPOSE 5173
CMD [ "npm", "run", "dev" ]

 

You can use the following command to build, tag, and push the image to the container registry.

 

az acr build -t <registry>/<image-name>:<tag> -r <registry> .

 

 

Server App

Create a new directory for your server app and navigate into it with mkdir server && cd server. Initialize a new Node.js project by running npm init -y, which will create a package.json file with default values.

 

Now, you can create an entry file, for example, index.js, and write your Node.js code in it. To launch your application, use the command npm run start from within your project directory. This will start your Node.js application, and you can begin to build out your server’s functionality. Please ensure CORS is enabled either in the code or from the Container App configuration.

 

Now we will containerize the server application using the below dockerfile.

 

FROM node:alpine
WORKDIR /usr/src/app
COPY . .
RUN npm install
EXPOSE 3000
CMD [ "npm", "run", "start" ]

 

As mentioned above, this image can be pushed to container registry using the same command.

 

Nginx Configuration

Nginx is a powerful and versatile web server that can also function as a reverse proxy. As a reverse proxy, Nginx acts as an intermediary for requests from clients seeking resources from servers. It accepts all incoming traffic and forwards it to different backend servers based on the configuration. Using Nginx as a reverse proxy can improve the security, performance, and scalability of web applications. It handles the SSL/TLS encryption, offloading the burden from the backend servers, which can now focus on serving content.

 

Configuring Nginx as a reverse proxy involves setting up server blocks that define the forwarding rules. The configuration file nginx.conf is edited to specify the location blocks, where proxy_pass directives are used to relay requests to the appropriate application servers.

 

user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    sendfile        on;

    keepalive_timeout  65;

    
	server {
        listen 80;
        location / {
            proxy_http_version 1.1;
            proxy_pass http://react-fe-app.internal.icysky-8546baf3.westus2.azurecontainerapps.io;
        }
        location /api/ {
            proxy_http_version 1.1;
            proxy_pass http://node-be-app.internal.icysky-8546baf3.westus2.azurecontainerapps.io;
        }
    }
}

 

 

This Nginx configuration file defines two locations, '/' and '/api', and routes traffic to the client (react-fe-app) and server (node-be-app) container apps respectively using their internal URLs, http://react-fe-app.icysky-8546baf3.westus2.azurecontainerapps.io; and http://node-be-app.icysky-8546baf3.westus2.azurecontainerapps.io

 

We will containerize the nginx server using the below dockerfile.

 

FROM nginx:alpine
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 80

 

As mentioned above, this image can be pushed to container registry using the same command.

 

Container App Configuration

Navigate to the Ingress Blade of the Nginx container app and set Ingress Traffic to "Accepting Traffic from Anywhere" and Ingress type to "HTTP".

 

image.png

 

For the frontend and backend container apps, set Ingress Traffic to "Limited to Container Apps Environment" and Ingress type to "HTTP". We configured proxy_pass directive in nginx.conf to the 'http' protocol; therefore Enable "Insecure Connection" under Ingress Blade.

 

image.png

 

Conclusion

Verify that the setup with path-based routing is working. When you navigate to the Nginx container app, we can see the default homepage of our React app. On clicking 'Get Message', it will make a call to the backend Node API to display the message. 

image.png

You have now successfully set up both client and server container app with path based routing with an NGINX container for your container apps! I hope this solution helps.

Co-Authors
Version history
Last update:
‎Apr 15 2024 03:08 AM
Updated by: