DEV Community

Cover image for Docker 201: Use NGINX as a Reverse Proxy for NodeJS Server in 2020! 📦 🙌 (practical guide)
Shahjada Talukdar for The Destro Dev Show

Posted on

Docker 201: Use NGINX as a Reverse Proxy for NodeJS Server in 2020! 📦 🙌 (practical guide)

I will skip "What/Why Docker?" part to make it straight to the point! 🤝

Goal: We are gonna use NGINX as a Reverse Proxy for a NodeJS Server. ⧚

For that, I will use 2 Docker images from Docker Hub - One is for NodeJS and another one is for NGINX 🤞

Let's see this in action!


I have already installed -

  • NodeJS
  • Docker

We will create a simple Node Server. We will use http module from node and make a simple http server. server.js file contains the code of our server-

var http = require('http');

var server = http.createServer(function (request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.end("Node & Docker Running...");
});

server.listen(3333);

console.log("Node HTTP Server started at http://localhost:3333/");
Enter fullscreen mode Exit fullscreen mode

If we run node server.js on our terminal, it will start the server at 3333 port on localhost.
We can open a browser and hit http://localhost:3333/ and we can see server is sending the text Node & Docker Running....
Awesome 👏

Now, we want to create a docker image for our Node Server. To do this, we need to create a file named Dockerfile with the below commands-

FROM mhart/alpine-node
COPY server.js .
EXPOSE 3333
CMD node server.js
Enter fullscreen mode Exit fullscreen mode

Here, I have used mhart/alpine-node(Minimal Node.js Docker Image) for having NodeJS environment.

EXPOSE 3333 means - 3333 port is intended to be published.

Now that we have our Dockerfile ready, we will build a Docker image from this file. We can run on the terminal-

docker build -t docknode .
Enter fullscreen mode Exit fullscreen mode

*Here, docknode is the image name. We can use any name.

I will run the docker image now which will make a container for us-

docker run -d -p 3333:3333 --name node-server  docknode
Enter fullscreen mode Exit fullscreen mode

I have used -d which will help to run the container in the background.

After running this command, our NodeJS server should run inside the Docker container named node-server.
Now, if I open any Browser and hit http://localhost:3333, we can see the server is running 🎉

Ok, awesome! As our NodeJS server inside a Node Docker image is running, we need to add NGINX Reverse Proxy next.


We will use the official NGINX image from DockerHub.
Let's create a Dockerfile for that.

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

I am gonna create a file called default.conf for NGINX with the following configurations -

server {
  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://server:3333;
  }
}
Enter fullscreen mode Exit fullscreen mode

Please note that, here in the configurations, we have http://server:3333. This 3333 is the Port from our NodeJS Docker container. I will come to the server part later in this article.

Let's go to Terminal and run-

docker build -t docknginx .
Enter fullscreen mode Exit fullscreen mode

This will build the docker image for NGINX. After running the command, we will see something like this-

Alt Text

And, to verify that our image is available in our local machine, we can run the below command to see the list-

docker images
Enter fullscreen mode Exit fullscreen mode

Alt Text

Coolio! We can see both of our images are available here 👏

As our goal is to have the NGINX as the Reverse Proxy for our NodeJS Server. When we will run the NGINX image, We need to link the NodeJS Server to NGINX.

To do that, I will run the below command on the Terminal-

docker run -d -p 8080:80 --link node-server:server --name nginx-proxy  docknginx
Enter fullscreen mode Exit fullscreen mode

Here, --link is helping to link our NodeJS Container to this NGINX container. If you double-check, I named the NodeJS Container as node-server. And this :server is used inside our NGINX Configurations. 🤝

After running the command, if we now go to our Browser and hit http://localhost:8080/, we can see our NodeJS App is running on this port now 🎉

Alt Text

We are actually hitting the NodeJS Server through NGINX as it is working as a Reverse Proxy here.

Awesome 🙌

I hope, you liked it. And if you haven't used Docker yet, I think, you should Try it in 2020!

See you in my next article.

Till then,
Cheers!
👋

As I am trying to contribute contents on the Web, you can buy me a coffee for my hours spent on all of these ❤️😊🌸
Buy Me A Coffee

Oldest comments (18)

Collapse
 
tawsbob profile image
Dellean Santos

nice article, just to add more information --link flag is a legacy feature of Docker

Collapse
 
destro_mas profile image
Shahjada Talukdar

Thanks, I will update accordingly 👍

Collapse
 
tawsbob profile image
Dellean Santos

Great 😃

Collapse
 
mrnonz profile image
Nontawat Numor

I think it's will make people confuse between Proxy Vs Reverse Proxy.

If you agree with me please correct these.

Collapse
 
destro_mas profile image
Shahjada Talukdar

Actually, Reverse proxy is the specific term. I will update

Collapse
 
sani071 profile image
MD. Sani Mia

very helpful article .. Thanks for sharing
1

Collapse
 
destro_mas profile image
Shahjada Talukdar

Welcome!

Collapse
 
reggietheroman profile image
reggietheroman

This is really interesting. Could you eli5 why one would need to use a reverse proxy at all?

Collapse
 
maximization profile image
Maxim Orlov

One reason is, you have multiple apps/websites hosted on the same server. Say you have a landing/marketing page at myproduct.com and a dashboard for user accounts at app.myproduct.com. They can't both listen port 80 (default http port). You set up a reverse proxy that listens to 80 and forwards traffic to the respective app based on the domain. The apps can listen to ports 3000 and 3001 for example.

Does that make sense?

Collapse
 
reggietheroman profile image
reggietheroman

I think so. Just so im sure i understood your explanation, internally they use 3000 and 3001, and when people hit up myproduct.com and app.myproduct.com, that goes to nginx which then forwards the request to the correct ports?

Thread Thread
 
maximization profile image
Maxim Orlov

Correct!

Thread Thread
 
reggietheroman profile image
reggietheroman

awesome. thanks so much!

Collapse
 
destro_mas profile image
Shahjada Talukdar

This is a really nice article-
cloudflare.com/learning/cdn/glossa...

Collapse
 
dancsee89 profile image
Daniel Molnar

In the next round, do this with https ;) :D

Collapse
 
destro_mas profile image
Shahjada Talukdar

Will try,
I have a lot of things in my queue 😀

Collapse
 
luiscarlosb3 profile image
Luis Carlos Galvão de Oliveira

nice article, have you any tips about static files? I've been some problems with css and js front end scripts locations

Collapse
 
rhernandog profile image
Rodrigo Hernando

What worked for me was to create a different folder with nginx and use docker compose in order to run and connect everything at the same time. It works fine in development. Here is the repo I have so far:
github.com/rhernandog/docker-expre...

Since I just started with docker a couple of weeks ago, I can't get it to work on production though. I can make it work with the static files but I can't find a way to start the express API server.

If someone could lend me a hand I'd appreciate it. Here is how my Dockerfile looks so far:

FROM nginx AS static
WORKDIR /app
COPY ./client /app

FROM node:12-alpine AS api
WORKDIR /app
COPY ./server/package.json /app
RUN npm install
COPY ./server /app

FROM nginx
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=static /app /usr/share/nginx/html
EXPOSE 80

If I remove the middle section (all the node part) it works fine, but as I said I can't find a way to start the express server.

If you user the code in the repo, running docker-compose up --build is going to work fine, as long as you provide your own mongo database of course.

Collapse
 
chiragshahklc profile image
Chirag Shah

If you haven't gave a chance, try Caprover. It's based on docker and very very simple to use.
It uses docker + nginx reverse proxy + let's encrypt.
caprover.com/