Skip to content

Commit

Permalink
nginx-load-balancing
Browse files Browse the repository at this point in the history
  • Loading branch information
thatshashankguy committed Oct 13, 2024
1 parent 288212d commit be88938
Show file tree
Hide file tree
Showing 30 changed files with 996 additions and 108 deletions.
208 changes: 208 additions & 0 deletions content/posts/nginx-load-balancing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
---
title: Load Balancing and Static File Serving with NGINX
author: Shashank Shekhar
date: 2024-10-13
---

![alt text](/nginx-load-balancing.png)

NGINX is a popular web server often used to host Node.js applications in production. It provides features like **load balancing**, **proxying**, **reverse proxy**, and **static file serving** out of the box.

#### Serving Web Apps with NGINX

Today, we will perform a simple exercise using a basic JavaScript backend to demonstrate the **load balancing** capabilities of the NGINX web server. Alongside the backend server script, we’ll also host a single webpage on NGINX to showcase static file serving.

As usual, code examples are available in my [GitHub repository](https://github.com/thatShashankGuy/code-examples/tree/master/nginx-load-balancer). Let’s get started!

In this exercise, our web page will send a request to the backend, and the backend will respond with a joke. We will simulate load balancing among different servers by running our backend script on four separate ports. The backend script will check the `PORT` value for each request and return a **port-specific joke** to the webpage.

---

### Exercise: Random Joke Generator

Here is the code for the backend server and the web page.

#### `index.html`

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Joke Balancing with NGINX</title>
</head>
<body>
<h1>Here are Random Jokes</h1>
<p>With each request the server responds to, NGINX will serve a port-specific joke.</p>
<div>JOKE FROM PORT: <b><i id="server-port">waiting...</i></b></div>
<div id="server-response">Fetching a joke from the server...</div>

<script>
fetch('/api/data')
.then(response => response.json())
.then(data => {
document.getElementById('server-response').innerText = data.joke;
document.getElementById('server-port').innerText = data.port;
})
.catch(error => {
document.getElementById('server-response').innerText = 'Error fetching data';
console.error('Error:', error);
});
</script>
</body>
</html>
```

#### `server.js`

```js
const http = require('http');
const os = require('os');

const PORT = process.env.PORT || "3000";

http.createServer((req, res) => {
let joke = `THIS IS SERIOUS BUSINESS`;
switch (PORT) {
case "3000":
joke = `Why don't skeletons fight each other? Because they don't have the guts.`;
break;
case "8080":
joke = `What do you call fake spaghetti? An impasta!`;
break;
case "1313":
joke = `Why did the scarecrow win an award? Because he was outstanding in his field!`;
break;
case "1517":
joke = `Why don’t eggs tell jokes? Because they might crack up!`;
break;
default:
break;
}

console.log(JSON.stringify({ port: PORT, joke }));

res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ port: PORT, joke }));
}).listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});
```

#### A Script to Start All Servers Together

```bash
#!/bin/bash

PORTS=(3000 8080 1313 1517)
SERVER_JS_PATH="./server.js"

for PORT in "${PORTS[@]}"
do
echo "Starting server.js on port $PORT"
PORT=$PORT nohup node $SERVER_JS_PATH > logs/server_$PORT.log 2>&1 &
done

echo "All servers started."
```

---

### Configuring NGINX for Our Web App

Before configuring NGINX, you need to [install NGINX](https://nginx.org/en/docs/install.html) on your system. You can check if NGINX is installed by running the following command:

```bash
nginx -v
```

The behavior of NGINX is determined by its configuration file, typically named `nginx.conf`. By default, this file is located in directories such as `/etc/nginx` or `/usr/local/etc/nginx`, but for this demonstration, we will keep the `nginx.conf` file in the same directory as the project files.

You can read the configuration file with the following command:

```bash
nginx -c /your/path/to/code-examples/nginx-load-balancer/nginx.conf
```

Before running the server, it’s always a good idea to test the configuration using the `-t` flag:

```bash
nginx -t -c /your/path/to/code-examples/nginx-load-balancer/nginx.conf
```

#### NGINX Configuration (`nginx.conf`)

```bash
events {
worker_connections 1024;
}

http {
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:8080;
server 127.0.0.1:1313;
server 127.0.0.1:1517;
}

server {
listen 80;
server_name localhost;

location / {
root code-examples/nginx-load-balancer;
index index.html;
}

location /api/data {
proxy_pass http://backend;
}
}
}
```

---

### Explaining the NGINX Configuration

**Worker Connections**: In the `events` block, we configured NGINX to handle 1024 simultaneous connections per worker. This optimizes how NGINX deals with incoming requests.

**Upstream Block**: The `upstream` block defines a pool of backend servers, each running on a different port (3000, 8080, 1313, and 1517). NGINX will distribute the load across these servers using a **round-robin method**, sending each request to a different server in turn.


**Port 80**: NGINX listens on port 80, which is the default HTTP port.

**Serving Static Files**: When a request is made to `/`, NGINX serves the static HTML file (`index.html`) located in the `code-examples/nginx-load-balancer` directory.

**Proxying Requests**: When a request is made to `/api/data`, NGINX acts as a **proxy** and forwards the request to one of the backend servers, which will respond with a port-specific joke.

---

### Testing the Web Application

Once everything is set up, open a browser and go to `http://localhost`. Each time you refresh the page, NGINX will serve the static HTML file and fetch data from different backend servers running on different ports, showing a new joke with each request.

Request 1
![image not found](/nginx-req1.png)

Request 2
![image not found](/nginx-req2.png)

---

### Conclusion

In this article, we explored how to use NGINX to serve a Node.js application, demonstrating its **load-balancing**, **proxying**, and **static file serving** capabilities. NGINX is a popular choice in the Node.js ecosystem for production environments, thanks to its efficiency and powerful features.

This is a basic example demonstrating some of NGINX's capabilities. In future exercises, we will explore more features such as caching, reverse proxying, and SSL/TLS configuration.

---

### Further Reading
- [What is a Web Server?](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Web_mechanics/What_is_a_web_server)
- [NGINX Beginner's Guide](https://nginx.org/en/docs/beginners_guide.html)
- [Load Balancing Node.js Applications on NGINX](https://docs.nginx.com/nginx/deployment-guides/load-balance-third-party/node-js/)
- [Apache vs IIS vs NGINX: Web Server Comparison](https://www.linuxcareers.com/resources/blog/2023/07/apache-vs-iis-vs-nginx-an-in-depth-comparison-of-web-servers/)

As always, happy coding!
8 changes: 4 additions & 4 deletions public/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/web-socket-chat-server/'>Chat server with Websocket in Node JS</a></h1>
<div class="date">Oct 6, 2024</div>
<h1 class="title"><a href='/posts/nginx-load-balancing/'>Load Balancing and Static File Serving with NGINX</a></h1>
<div class="date">Oct 13, 2024</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/browser-extension/'>Build Custom Browser Extensions with Javascript</a></h1>
<div class="date">Sep 23, 2024</div>
<h1 class="title"><a href='/posts/web-socket-chat-server/'>Chat server with Websocket in Node JS</a></h1>
<div class="date">Oct 6, 2024</div>
</div>
</section>

Expand Down
8 changes: 4 additions & 4 deletions public/404/page/2/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/store-fm-1/'>Building Web APIs in Go - StoreFM#2</a></h1>
<div class="date">Aug 25, 2024</div>
<h1 class="title"><a href='/posts/browser-extension/'>Build Custom Browser Extensions with Javascript</a></h1>
<div class="date">Sep 23, 2024</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/store-fm-2/'>Working with Go&#39;s Standard Library - StoreFM#1</a></h1>
<div class="date">Aug 18, 2024</div>
<h1 class="title"><a href='/posts/store-fm-1/'>Building Web APIs in Go - StoreFM#2</a></h1>
<div class="date">Aug 25, 2024</div>
</div>
</section>

Expand Down
8 changes: 4 additions & 4 deletions public/404/page/3/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/javascript-garbage-collection/'>Garbage Collection in JavaScript</a></h1>
<div class="date">Aug 10, 2024</div>
<h1 class="title"><a href='/posts/store-fm-2/'>Working with Go&#39;s Standard Library - StoreFM#1</a></h1>
<div class="date">Aug 18, 2024</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/node-js-profiling/'>Profiling Your Node.js Production Code</a></h1>
<div class="date">Aug 4, 2024</div>
<h1 class="title"><a href='/posts/javascript-garbage-collection/'>Garbage Collection in JavaScript</a></h1>
<div class="date">Aug 10, 2024</div>
</div>
</section>

Expand Down
8 changes: 4 additions & 4 deletions public/404/page/4/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/love-being-boring/'>Learn to Love Boring</a></h1>
<div class="date">Jun 11, 2024</div>
<h1 class="title"><a href='/posts/node-js-profiling/'>Profiling Your Node.js Production Code</a></h1>
<div class="date">Aug 4, 2024</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/acid-base-cap/'>Database Paradigms - ACID, BASE and CAP in brief</a></h1>
<div class="date">Jan 8, 2024</div>
<h1 class="title"><a href='/posts/love-being-boring/'>Learn to Love Boring</a></h1>
<div class="date">Jun 11, 2024</div>
</div>
</section>

Expand Down
8 changes: 4 additions & 4 deletions public/404/page/5/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/burnout/'>Coding My Way Out of Burnout</a></h1>
<div class="date">Dec 25, 2023</div>
<h1 class="title"><a href='/posts/acid-base-cap/'>Database Paradigms - ACID, BASE and CAP in brief</a></h1>
<div class="date">Jan 8, 2024</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/io-in-node/'>Async IO programming with Node js</a></h1>
<div class="date">Dec 15, 2023</div>
<h1 class="title"><a href='/posts/burnout/'>Coding My Way Out of Burnout</a></h1>
<div class="date">Dec 25, 2023</div>
</div>
</section>

Expand Down
6 changes: 3 additions & 3 deletions public/404/page/6/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/externals/'>Reference Articles and Whitepapers</a></h1>
<div class="date">Nov 15, 2023</div>
<h1 class="title"><a href='/posts/io-in-node/'>Async IO programming with Node js</a></h1>
<div class="date">Dec 15, 2023</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/typescript-guide/'>The Typescript Programming Guide</a></h1>
<h1 class="title"><a href='/externals/'>Reference Articles and Whitepapers</a></h1>
<div class="date">Nov 15, 2023</div>
</div>
</section>
Expand Down
8 changes: 4 additions & 4 deletions public/404/page/7/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/errors-as-values/'>Go Basics - Error as values</a></h1>
<div class="date">Oct 29, 2023</div>
<h1 class="title"><a href='/posts/typescript-guide/'>The Typescript Programming Guide</a></h1>
<div class="date">Nov 15, 2023</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/structs/'>Go Basics - Map and Structs</a></h1>
<div class="date">Oct 9, 2023</div>
<h1 class="title"><a href='/posts/errors-as-values/'>Go Basics - Error as values</a></h1>
<div class="date">Oct 29, 2023</div>
</div>
</section>

Expand Down
8 changes: 4 additions & 4 deletions public/404/page/8/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ <h2 class="read-more">Read more</h2>

<section class="item">
<div>
<h1 class="title"><a href='/posts/array-slices/'>Go Basics - Arrays vs Slices</a></h1>
<div class="date">Aug 11, 2023</div>
<h1 class="title"><a href='/posts/structs/'>Go Basics - Map and Structs</a></h1>
<div class="date">Oct 9, 2023</div>
</div>
</section>



<section class="item">
<div>
<h1 class="title"><a href='/posts/pointers-in-go/'>Go Basics - Pointers</a></h1>
<div class="date">Jul 20, 2023</div>
<h1 class="title"><a href='/posts/array-slices/'>Go Basics - Arrays vs Slices</a></h1>
<div class="date">Aug 11, 2023</div>
</div>
</section>

Expand Down
Loading

0 comments on commit be88938

Please sign in to comment.