loading...

Routing requests to containers with nginx

tirthaguha profile image Tirtha Guha Updated on ・3 min read

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

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"));

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"
  }
}

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" ]

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"));

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" ]

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;
  }

}

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

Create the images and run the containers

Go to first-app directory and build the image

sudo docker build -t first-app .

Go to the second-app directory and build the image

sudo docker build -t second-app .

Run the images now

sudo docker run -p 3000:3000 -d first-app
sudo docker run -p 4000:4000 -d second-app

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

{
"title": "Express",
"application": "Application 1"
}

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

{
"title": "Express",
"application": "Application 2"
}

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

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

Posted on by:

tirthaguha profile

Tirtha Guha

@tirthaguha

javascript, ux, nodejs, react, backbonejs, marionettejs, npm, devops,

Discussion

pic
Editor guide