Nginx as Load Balancer is a common use case for Nginx around the world. Load balancer usually not only for balancing the upstream server load, but also improve the overall security of your application. 2 types of Load Balancer can be built using Nginx. The first one is Layer 4 Load Balancer, the second one is Layer 7 Load Balancer. The term Load Balancer (without saying the layer) usually refers to layer 7.
In this tutorial, we will do a Layer 7 Load Balancer configuration. If you need Layer 4 Load Balancer configuration, you can check my other tutorial: How to Configure Nginx as Layer 4 Load Balancer.
Check Prerequisite
This tutorial needs Nginx Installed, if the Nginx is not installed yet, you can just use apt install nginx
to install it.
Sudo Privileges
Before starting, make sure that we have no permission issue on the configuration by executing this command:
sudo su
Use Case
To demonstrate the load balancing configuration, will use this use case
____________
| |
-----> | App1 |
| |____________|
___________ | ____________
| | | | |
user -----------> | LB |----|-----> | App2 |
|___________| | |____________|
| ____________
| | |
-----> | App3 |
|____________|
3 application nodes will be load balanced using Nginx LB (Load Balancer). These are the specification of the nodes:
- LB Node
- IP: 10.11.12.13
- Port: 3000
- App1 Node
- IP: 10.1.1.10
- Port: 4000
- App2 Node
- IP: 10.1.1.20
- Port: 4000
- App3 Node
- IP: 10.1.1.30
- Port: 4000
In this use case, we will assume that the application should be using TLS
or https
with example.com
as the domain name. The Load Balancer will terminate the TLS
, then use plain http to the upstream. If you are not using TLS
, We will also provide you guidance on how to do that.
Load Balancer Configuration
First, you need an Nginx that already running and the move our work directory to the Nginx configuration folder
cd /etc/nginx
Backup tne default nginx configuration file
mv nginx.conf nginx.conf.old
Create a new configuration file
nano nginx.conf
Add this configuration to the configuration file
user www-data;
worker_processes auto;
worker_rlimit_nofile 8192;
pid /run/nginx.pid;
events {
worker_connections 4096;
}
This will set up a basic global configuration for the Nginx. The important part is the worker_rlimit_nofile
and worker_connections
directives. You can set the number higher depending on the specification of your server. No one knows the best setup, you must do a load test yourself.
After that, create a http
block under the events
block like this.
http {
include mime.types;
default_type application/octet-stream;
# Log Setting
log_format complete '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time '
'ua="$upstream_addr" us="$upstream_status" '
'ut="$upstream_response_time" ul="$upstream_response_length"';
access_log /var/log/nginx/access.log complete;
error_log /var/log/nginx/error.log warn;
# Sending fille Optimization
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Keepalive Connection
keepalive_timeout 65;
upstream app_node {
server 10.1.1.10:4000;
server 10.1.1.20:4000;
server 10.1.1.30:4000;
}
server {
listen 3000 ssl http2;
server_name example.com
# Security and SSL
ssl_protocols TLSv1.3 TLSv1.2;
ssl_certificate /etc/ssl/cert_file.crt;
ssl_certificate_key /etc/ssl/key_file.key;
location / {
# HTTP 1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_pass http://app_node;
}
}
}
Let’s review this line by line.
include mime.types
directive is import the mime.types
files in the Nginx directory so the Nginx support serving static file extensions that are included in mime.types
file.
default_type
directive is to set the default Content-Type
response header if the header is not configured. Usually, the default is application/octet-stream
as we used in this tutorial.
log_format
directive is to format the format of the Nginx log.
access_log
and error_log
directive is to set where the Nginx log will be stored.
sendfile
, tcp_nopush
, and tcp_nodelay
directive is to optimize the Nginx performance when serving static files.
keepalive_timeout
directive is to set the http timeout before Nginx closes the connection after the user made 1 request. If the user makes another request within the keepalive_timeout
, Nginx will not make a new connection to the server the request, hence improving the Nginx performance.
Inside the upstream
block, there are 3 servers that match our use case. Our target is load balancing these 3 server behind the Nginx. By default, Nginx will use the Round Robin
algorithm to load balance incoming traffic, directing it sequentially to the servers in the configured upstream. If you want to use another algorithm you can check Nginx documentation: Choosing an NGINX Plus Load‑Balancing Technique.
Inside the server block, there are a few directives.
listen
directive is to set the port of our Load Balancer will listen to, also we add ssl
parameter to tell Nginx that the traffic is encrypted with TLS, and http2
to use http2
protocol that comes with performance improvement from plain http
version 1.
server_name
directive is to set the domain name of the load balancer.
ssl_protocols
is to set the version of TLS
protocol used. It is recommended to use TLSv1.3
and TLSv1.2
to get maximum security with high compatibility.
ssl_certificate
and ssl_certificate_key
directive is where the SSL cert and key location.
proxy_http_version
directive is to set the http version used for upstream connection. Version 1.1
is recommended.
proxy_set_header Connection ""
directive is needed when we use http version 1.1
for the upstream connection.
Lastly, we use the proxy_pass
directive to tell the Nginx to pass the traffic to the upstream
location.
So the full configuration of nginx.conf
is like this
user www-data;
worker_processes auto;
worker_rlimit_nofile 8192;
pid /run/nginx.pid;
events {
worker_connections 4096;
}
http {
include mime.types;
default_type application/octet-stream;
# Log Setting
log_format complete '\$remote_addr - \$remote_user [\$time_local] "\$request" '
'\$status $body_bytes_sent "\$http_referer" '
'"\$http_user_agent" "\$http_x_forwarded_for" '
'rt=\$request_time '
'ua="\$upstream_addr" us="\$upstream_status" '
'ut="\$upstream_response_time" ul="\$upstream_response_length"';
access_log /var/log/nginx/access.log complete;
error_log /var/log/nginx/error.log warn;
# Sending fille Optimization
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Keepalive Connection
keepalive_timeout 65;
upstream app_node {
server 10.1.1.10:4000;
server 10.1.1.20:4000;
server 10.1.1.30:4000;
}
server {
listen 3000 ssl http2;
server_name example.com
# Security and SSL
ssl_protocols TLSv1.3 TLSv1.2;
ssl_certificate /etc/ssl/cert_file.crt;
ssl_certificate_key /etc/ssl/key_file.key;
location / {
# HTTP 1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_pass http://app_node;
}
}
}
If your domain is not using TLS/SSL
then you can comment out ssl_protocols
, ssl_certificate
, and ssl_certificate_key
directives, and also change the listen
directive to:
listen 3000;
After the configuration is done, make sure that there is no error in the configuration by running this command
nginx -t
Reload the Nginx so it uses the new configuration file
service nginx reload
You can check the Nginx status by running this command
service nginx status
That’s it! Congratulation, now you can build your own Load Balancer using Nginx.
Final word, if you make a Load Balancer for many different application, I suggest you to understand how the Nginx serve a request by learning the Nginx server block and location block. You can read my other tutorial: Understanding Nginx Server Block and Understanding Nginx Location Block.