Hello! Welcome back to the course.
Introduction
In our previous lesson, we analyzed the fundamental trade-offs between Layer 4 and Layer 7 load balancing, establishing when to prioritize raw performance versus intelligent, application-aware routing. We concluded that for most web-based and microservice architectures, the rich feature set of an L7 load balancer is indispensable.
Today, we move from theory to practice. This lesson directly addresses the learning outcome: Configure nginx as a reverse proxy with upstream definitions, load balancing algorithms, and health checks. We will take the concepts from our last discussion and implement them using nginx, one of the most widely deployed reverse proxies and load balancers in the world.
You have extensive experience building and managing high-load services, so we will dispense with the basics and focus directly on the configuration directives that allow you to control traffic distribution and ensure system resilience.
1. The Core Components: upstream and proxy_pass
At the heart of nginx's load balancing capability are two directives that work in tandem:
- The
upstreamblock, which defines a pool of backend servers. - The
proxy_passdirective, which forwards incoming requests to that pool.
Let's start by looking at the basic syntax and a clear demonstration of how these are used.
This video from NGINX provides a concise walkthrough of the fundamental setup. It will show you how to define the upstream server group and then direct traffic to it.
Watch the segment from 02:02 to 03:45. Focus on how the upstream block is defined within the http context and how the proxy_pass directive within a location block references the upstream group by name.
As you saw, the configuration is straightforward. Here is the essential structure:
http {
# 1. Define a pool of backend servers
upstream backend_servers {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server app.example.com:8080;
}
server {
listen 80;
location / {
# 2. Forward requests to the upstream pool
proxy_pass http://backend_servers;
}
}
}
- The
upstreamblock, which we've namedbackend_servers, contains a list of the application servers that can handle requests. These can be specified by IP address or hostname. - The
proxy_passdirective tells nginx to forward any request matching thelocation /block to one of the servers in thebackend_serversgroup.
This forms the foundation upon which we will build more sophisticated behaviors.
2. Choosing a Load Balancing Algorithm
By default, nginx uses a round-robin algorithm, distributing requests evenly across the servers in the upstream group. However, for real-world systems, you often need more control. Your servers may not have identical capacity, or you might need to ensure a user's session stays on a single server.
Let's explore the most common load balancing methods you can configure in nginx.
HTTP Load Balancing | NGINX Documentation
The official NGINX documentation provides the definitive guide to the available load balancing methods. We'll use it as our primary reference.
Please read the sections 'Choosing a Load Balancing Method' and 'Server Weights'. Pay close attention to the configuration syntax for: Round Robin (the default) Least Connections (least_conn) IP Hash (ip_hash) How the weight parameter modifies the distribution.
Now, let's watch a practical demonstration of these algorithms in action.
The 'Load Balancing with NGINX' video includes excellent live demos that show how these configurations affect traffic distribution in real-time.
This is a longer segment, but it's highly practical. Watch from 03:45 to 11:15, and then the corresponding demos from 20:13 to 27:10. Focus on: Weighted Round Robin (03:45 & 20:13): Understand how assigning a weight to a server directs a proportional amount of traffic to it. This is crucial for heterogeneous environments. IP Hash (08:22 & 23:42): See how ip_hash ensures requests from the same client IP are sent to the same server, achieving session persistence. Least Connections (06:09 & 25:50): Grasp the concept of sending new requests to the server with the fewest active connections. This is a more dynamic and often fairer distribution method than round-robin.
Summary of Key Algorithms
Let's synthesize this into a quick reference.
| Method | Directive | Description | Common Use Case |
|---|---|---|---|
| Weighted Round Robin | (default) | Distributes requests sequentially. The weight parameter can be used to send more traffic to more powerful servers. |
Simple distribution, or when servers have different capacities (e.g., weight=5). |
| Least Connections | least_conn |
Sends the next request to the server with the fewest active connections. Also considers server weights. | Fairly distributing load for requests with varying completion times (e.g., long-polling or file uploads). |
| IP Hash | ip_hash |
The server is determined by a hash of the client's IP address. | Ensuring session persistence ("sticky sessions") when application state is held on a specific server. |
Here is how you would apply them in a configuration:
upstream backend_servers {
# For Least Connections:
least_conn;
# For IP Hash:
# ip_hash;
server backend1.example.com weight=3; # Receives 3/4 of traffic in round-robin
server backend2.example.com; # Receives 1/4 of traffic
}
Note that you place the algorithm directive at the top of the upstream block. If no directive is present, weighted round-robin is the default.
3. Ensuring Resilience with Health Checks
Distributing traffic is only half the battle. A production-grade load balancer must also detect and route around failing backend servers. Nginx handles this through passive health checks.
A passive check means nginx monitors the results of live client requests. If a certain number of requests to a server fail within a specific timeframe, nginx will temporarily mark that server as "down" and stop sending traffic to it.
The key parameters for this are max_fails and fail_timeout.
HTTP Health Checks | NGINX Documentation
The official documentation on HTTP Health Checks explains these parameters clearly.
Read the 'Passive Health Checks' section. Focus on the definitions of max_fails and fail_timeout and how they work together.
To see a powerful demonstration of this failover in action, watch the following clip.
How to setup NGINX Reverse Proxy as load balancer with traffic splitting and health check
This video from Paris Nakita Kejser provides a simple but very effective demo of nginx's health checks automatically handling a server failure.
Watch from 06:54 to 09:41. The presenter configures max_fails and fail_timeout, then shuts down one of the backend VMs. Observe how nginx automatically redirects traffic to the healthy server and then restores traffic once the failed server comes back online.
Configuration Example
Here’s how you would configure this in your upstream block:
upstream resilient_backend {
server backend1.example.com;
# This server will be marked as down for 60 seconds
# if nginx sees 5 failed connection attempts within that 60-second window.
server backend2.example.com max_fails=5 fail_timeout=60s;
}
max_fails=5: The server is marked as down after 5 consecutive failed attempts.fail_timeout=60s: This parameter serves two purposes:- It specifies the duration over which the
max_failscount is tracked. - It defines how long the server will be considered down before nginx attempts to send traffic to it again.
- It specifies the duration over which the
This simple configuration is fundamental to building a self-healing system, preventing a single failing node from causing a widespread outage.
Conclusion
In this lesson, we translated the theoretical concepts of L7 load balancing into concrete nginx configurations. You are now equipped to set up a robust reverse proxy that intelligently distributes traffic and automatically routes around failures.
Key Takeaways:
- Upstream and Proxy Pass: The
upstreamblock defines your server pool, andproxy_passdirects traffic to it. - Load Balancing Algorithms: You can control traffic distribution with directives like
least_connandip_hash, and influence the default round-robin with theweightparameter. - Passive Health Checks: Using
max_failsandfail_timeoutonserverdirectives allows nginx to automatically detect and isolate failing backend nodes, significantly improving your system's availability.
Preview of the Next Lesson:
While nginx is a powerful and versatile tool, it's not the only player in the game. In our next lesson, we will address the learning outcome: Compare HAProxy and nginx for TCP and HTTP load balancing, analyzing their performance characteristics and configuration approaches. We will explore HAProxy, another high-performance load balancer, and discuss the architectural scenarios where you might choose one over the other.