DEV Community

Tirtha Guha
Tirtha Guha

Posted on • Edited on

Routing requests to containers with nginx

Often in large application ecosystems a common nginx is used as a loadbalancer and reverse-proxy for many applications. In a previous post of this series, we have seen how nginx can be used to load balance traffic multiple containers.
In this post, we're going to see how we can use nginx as a reverse-proxy which would route requests to different containers based on path.

What we are going to do

  1. create an express application, with path /app-first path and launch it in a container
  2. create an express application, with path app-second path and launch it in a container
  3. create an nginx container, and have 2 paths configured in it. path-1 forwards the request to first container, and path-2 forwards the request to second container

Create the directories

mkdir first-app
mkdir second-app
mkdir nginx-docker
Enter fullscreen mode Exit fullscreen mode

Create the first application

I just created a very basic nodeJs application. The app.js looks like the following

var express = require("express");
var app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.get("/app-first", function (req, res, next) {
  res.send({ title: "Express", application: "Application 1" });
});

app.listen(3000, () => console.log("Running on http://localhost:3000"));
Enter fullscreen mode Exit fullscreen mode

The package.json looks like the following

{
  "name": "express-with-env",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "~4.16.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

and in parallel to these, the Dockerfile looks like the following

FROM node:12-slim
WORKDIR /app
COPY ./package*.json ./
RUN npm install
COPY ./ ./
EXPOSE 3000

# Run the code
CMD [ "npm", "start" ]
Enter fullscreen mode Exit fullscreen mode

Create the second application

The second application is exactly like the first application, except, it runs on PORT 4000, and exposes path /app-second. the app.js looks like the following

var express = require("express");
var app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.get("/app-second", function (req, res, next) {
  res.send({ title: "Express", application: "Application 2" });
});
app.listen(4000, () => console.log("Running on http://localhost:4000"));
Enter fullscreen mode Exit fullscreen mode

and the Dockerfile looks like the following

FROM node:12-slim
WORKDIR /app
COPY ./package*.json ./
RUN npm install
COPY ./ ./
EXPOSE 4000

# Run the code
CMD [ "npm", "start" ]
Enter fullscreen mode Exit fullscreen mode

The packageJSON looks exactly like the first application

Create the nginx config

Go to the nginx-docker directory and create nginx.conf file

upstream first-app {
    server 172.17.0.1:3000 weight=1;
}

upstream second-app {
    server 172.17.0.1:4000 weight=1;
}

server {

  location /app-first {
    proxy_set_header X-Forwarded-Host $host:$server_port;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://first-app;
  }

  location /app-second {
    proxy_set_header X-Forwarded-Host $host:$server_port;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://second-app;
  }

}
Enter fullscreen mode Exit fullscreen mode

Create a dockerfile for the nginx and here's what it looks like

FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
Enter fullscreen mode Exit fullscreen mode

Create the images and run the containers

Go to first-app directory and build the image

sudo docker build -t first-app .
Enter fullscreen mode Exit fullscreen mode

Go to the second-app directory and build the image

sudo docker build -t second-app .
Enter fullscreen mode Exit fullscreen mode

Run the images now

sudo docker run -p 3000:3000 -d first-app
sudo docker run -p 4000:4000 -d second-app
Enter fullscreen mode Exit fullscreen mode

Now, if you open http://localhost:3000/app-first in browser, you should get the following JSON

{
"title": "Express",
"application": "Application 1"
}
Enter fullscreen mode Exit fullscreen mode

and by opening http://localhost:4000/app-second, you should get

{
"title": "Express",
"application": "Application 2"
}
Enter fullscreen mode Exit fullscreen mode

You see, the applications are running in different ports. Your target is to expose them both in the same port.

Go to the nginx-docker directory and build the nginx image and run it.

sudo docker build -t nginx-proxy .
sudo docker run -p 8000:80 -d nginx-proxy
Enter fullscreen mode Exit fullscreen mode

Now you'll be able to see both the applications running in port 8000, as

PS:
We wrote code for 2 applications(first-app and second-app) here, and wrote configuration for the third(nginx). We created their docker images, and we ran those images. Of course, these are too many commands to handle. In our next post, we'll look into docker-compose to simplify these image building and running.
The code for this tutorial is checked in at https://github.com/tirthaguha/container-reverse-proxy

Top comments (0)