> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Load Balancer

> Guide to configuring an Nginx load balancer using round-robin, weighted round-robin, and ip_hash sticky sessions with Apache backends plus firewall and production checklist

Welcome back. In this lesson we'll configure an Nginx load balancer and demonstrate three common balancing methods:

* Round-robin (default)
* Weighted round-robin
* ip\_hash (simple session affinity / sticky)

We’ll use two Apache backend servers to show that Nginx can balance requests across different web servers.

![Diagram showing an NGINX load balancer using a round-robin algorithm to distribute requests evenly to two Apache web servers.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Intermediate-Config/Demo-Load-Balancer/nginx-round-robin-apache-servers.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=d07689f1359c890982f22f5365dccd77)

Round-robin alternates requests between backend servers (first request to backend A, second to backend B, etc.). Next we’ll bias traffic toward one backend using weighted round-robin.

![A diagram showing an NGINX load balancer using a weighted round-robin algorithm to send traffic to two Apache web servers, one with weight 10 and the other with weight 1. Icons illustrate the load balancer, the weighted round-robin circle, and the web server pool.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Intermediate-Config/Demo-Load-Balancer/nginx-loadbalancer-weighted-roundrobin-apache.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=2746ba791496334cf3982abdbb9c79fa)

Finally, we’ll demonstrate `ip_hash`, which preserves client affinity by routing a client (based on source IP) to the same backend it reached first — useful for simple session-affinity needs like basic shopping carts when you don’t use centralized session storage.

![A diagram showing an NGINX load balancer using an IP-hash algorithm to route incoming requests to three web servers. It illustrates request distribution and session affinity (sticky routing) to specific server instances.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Intermediate-Config/Demo-Load-Balancer/nginx-ip-hash-sticky-routing.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=273b98d292c807e53919f87063884252)

## Environment summary

* `root@nginx`: Nginx load balancer
* `root@node01`: Apache backend 1
* `root@node02`: Apache backend 2

## Verify backend and balancer services

Check Apache on each backend:

```bash theme={null}
# On node01 and node02
sudo systemctl status apache2
```

Check Nginx on the load balancer (Nginx should be installed only on the load balancer):

```bash theme={null}
# On the load balancer
sudo systemctl status nginx
```

## Firewall: allow only the load balancer to reach backend port 80

By design we do not open backend HTTP port 80 to the public. Instead whitelist the load balancer IP on each backend so only the balancer can connect.

Find the load balancer IP (example):

```bash theme={null}
# On the load balancer
ip a
```

Example relevant interface address (trimmed):

* Load balancer eth0: `192.230.202.10`

On each backend add a UFW rule to allow traffic from the load balancer IP to port 80:

```bash theme={null}
# On node01 and node02
sudo ufw allow from 192.230.202.10 proto tcp to any port 80
sudo ufw status
```

Example UFW status after adding the rule:

```text theme={null}
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
80/tcp                     ALLOW       192.230.202.10
```

Only allowing the load balancer to connect to backend port 80 reduces exposure — do not open backend HTTP ports to the public when traffic is meant to be routed through a load balancer.

## Nginx configuration: upstream and proxy\_pass

On the load balancer, create or edit the site file `/etc/nginx/sites-available/apache-app`. The two key pieces are:

* `upstream` block: defines the pool of backend servers
* `proxy_pass`: points the location to the upstream name

Base configuration (simple upstream and proxy\_pass):

```nginx theme={null}
# Upstream configuration
upstream apache_example {
    server 192.230.202.12:80;
    server 192.230.202.3:80;
}

# Default server configuration
server {
    listen 80;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    server_name apache.example.com;

    location / {
        proxy_pass http://apache_example;
    }
}
```

Notes:

* The upstream name (`apache_example`) is referenced in `proxy_pass`.
* Upstream entries may be IP addresses or DNS names. Including `:80` is explicit but optional for HTTP.

After editing the file:

1. Test Nginx configuration syntax.
2. Ensure the site is enabled (create a symlink to `/etc/nginx/sites-enabled/` if needed).
3. Reload Nginx.

Commands:

```bash theme={null}
# On the load balancer
sudo nginx -t
sudo ln -s /etc/nginx/sites-available/apache-app /etc/nginx/sites-enabled/ 2>/dev/null || true
sudo nginx -s reload
```

The `ln -s` uses a guard to avoid failing if the link already exists.

Test locally with curl:

```bash theme={null}
# On the load balancer
curl -s http://localhost | head -n 5
```

Refreshing the browser or repeating the curl command will show responses alternating between the two backends — the default round-robin behavior.

## Weighted round-robin

To bias traffic toward one backend, add a `weight` for each server in the upstream. For example, to send roughly 10/11 of requests to `node01` and 1/11 to `node02`:

```nginx theme={null}
# Upstream configuration (weighted)
upstream apache_example {
    server 192.230.202.12:80 weight=10;
    server 192.230.202.3:80  weight=1;
}
```

Save, test, and reload:

```bash theme={null}
sudo nginx -t
sudo nginx -s reload
```

Now repeated requests will mostly reach the higher-weighted backend and occasionally the lower-weighted one.

## ip\_hash (session affinity / sticky)

If you need simple session affinity so a client consistently hits the same backend, use `ip_hash` in the upstream:

```nginx theme={null}
# Upstream configuration (ip_hash)
upstream apache_example {
    ip_hash;
    server 192.230.202.12:80;
    server 192.230.202.3:80;
}
```

Then test and reload:

```bash theme={null}
sudo nginx -t
sudo nginx -s reload
```

With `ip_hash` enabled, routing is based on the client IP. This works for lightweight affinity needs but has important limitations.

`ip_hash` provides IP-based affinity and is not a substitute for shared session storage. Clients behind the same NAT will share a source IP and be routed to the same backend. If a backend is removed, affinity may be disrupted. For robust session persistence, use a centralized session store or a more advanced load-balancer solution.

## Quick reference — balancing methods

| Method | Description | Configuration snippet |
| - | - | - |
| Round-robin (default) | Alternates requests across upstream servers | `upstream apache_example { server 1.2.3.4:80; server 1.2.3.5:80; }` |
| Weighted round-robin | Bias traffic using weights (e.g., 10:1) | `server 1.2.3.4:80 weight=10; server 1.2.3.5:80 weight=1;` |
| ip\_hash | Simple IP-based sticky sessions | `upstream apache_example { ip_hash; server 1.2.3.4; server 1.2.3.5; }` |

## Checklist before going to production

* Validate configuration: `sudo nginx -t`
* Reload safely: `sudo nginx -s reload`
* Restrict backend access to only the load balancer via firewall rules
* Consider health checks and monitoring for backends (Nginx Plus or third-party solutions)
* For robust session persistence, use a centralized session store (Redis, database, etc.)

## Useful links and references

* [Nginx documentation — upstream module](https://nginx.org/en/docs/http/ngx_http_upstream_module.html)
* [Nginx proxying and load balancing guide](https://nginx.org/en/docs/http/load_balancing.html)
* [UFW — uncomplicated firewall](https://help.ubuntu.com/community/UFW)

That completes this lesson on configuring an Nginx load balancer with round-robin, weighted round-robin, and `ip_hash` session affinity.

> **[Watch Video](https://learn.kodekloud.com/user/courses/nginx-for-beginners/module/c78ff9cb-c15d-4f85-92fc-abee5ed98b20/lesson/a2b8d77e-6682-4fa2-bedf-a8dde19a29ef)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/nginx-for-beginners/module/c78ff9cb-c15d-4f85-92fc-abee5ed98b20/lesson/da8e5437-fc04-466c-9446-8f856d5bb9ec)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.