Skip to content

Instantly share code, notes, and snippets.

@gilangvperdana
Last active April 2, 2024 13:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gilangvperdana/53a70f9a64d3f7becebfa5f3a3d54c1f to your computer and use it in GitHub Desktop.
Save gilangvperdana/53a70f9a64d3f7becebfa5f3a3d54c1f to your computer and use it in GitHub Desktop.
All About Nginx Load Balancer

Nginx Load Balancer

Experimental with 3 Container Docker, which is 1 Container for Nginx Load Balancer Reverse and 2 Container for Nginx Node
We will try to implement SSL + Auto Redirect + Load Balancer + Hostname Access Restrict

Environment

Ubuntu 20.04 LTS
Docker
3 Nginx Container

Installation

Docker

apt install -y docker.io

Pull Nginx Image

docker pull nginx

Run Nginx Image

docker run --name nginx-lb -d -p 80:80 -p 443:443 nginx
docker run --name nginx-1 -d nginx
docker run --name nginx-2 -d nginx
docker ps

Recap

In my case, i have an Docker Container IP like this :
Nginx-LB : 172.17.0.2
Nginx-1 : 172.17.0.3
Nginx-2 : 172.17.0.4

And then, i define labs.com for Domain experimental.

Remnindwarn

The default configurations is RoundRobin LoadBalancer Mode, if you want to use Least Connection or IP Hash Model please add this on /etc/nginx/conf.d/default :

Least Connection :
---
upstream backend {
 least_conn;
    server 172.17.0.3; 
    server 172.17.0.4;
} 
---

IP Hash :
---
upstream backend {
 ip_hash;
    server 172.17.0.3; 
    server 172.17.0.4;
} 
---

Configurations

docker exec -it nginx-lb bash

Not SSL Version :

nano /etc/nginx/conf.d/default.conf
upstream backend {
    server 172.17.0.3; 
    server 172.17.0.4;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 412;
} 

server {
    listen 80;
    server_name labs.com www.labs.com;

    location / {
        proxy_redirect      off;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Host $http_host;
        proxy_pass http://backend;
    }
}	

SSL Version :

Make sure you have an SSL Certificate, you can generate from Valid DNS or Self Signed with OpenSSL. 
Or you can goes to my Previos Topic about OpenSSL [https://gist.github.com/gilangvperdana/74ab7eb4e7d5e4ca76663334ed905bae]

OpenSSL

apt install -y openssl
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=Labs Inc./CN=labs.com' -keyout localhost.key -out localhost.crt
docker cp localhost.crt nginx-lb:/etc/ssl/certs/
docker cp localhost.key nginx-lb:/etc/ssl/certs/

Start Configure SSL

nano /etc/nginx/conf.d/default.conf
# SSL | Load Balancing | Restrict Access | Redirect to 443

# LOAD BALANCING NODE IP :
upstream backend {
    server 172.17.0.3; 
    server 172.17.0.4;
}

# RESTRICT ACCESS, MUST BE WITH SAME/CONFIGURED HOSTNAME TO ACCESS PAGE (REDIRECT TO 443) :
server {
        listen 80;
        server_name _;
        return 301 https://$host$request_uri;
}

# RESTRICT ACCESS, MUST BE WITH SAME/CONFIGURED HOSTNAME TO ACCESS PAGE :
server {
    listen 443 default_server;
    listen [::]:443 default_server;
    ssl_certificate /etc/ssl/certs/localhost.crt;
    ssl_certificate_key /etc/ssl/private/localhost.key;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    server_name _;
    return 412;
} 

# ACCESS ON PORT 80 THEN REDIRECT TO 443 :
server {
        listen 80;

        return 301 https://$server_name$request_uri;
}

# ACCESS WITH labs.com ON 443 :
server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    ssl_certificate /etc/ssl/certs/localhost.crt;
    ssl_certificate_key /etc/ssl/private/localhost.key;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    server_name labs.com labs.com;

    location / {
        proxy_redirect      off;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Host $http_host;
        proxy_pass http://backend;
    }
}

SSL Version with 2 Hostname :

Add telco.com for new domain.
nano /etc/nginx/conf.d/default.conf
# SSL | Load Balancing | Restrict Access | Redirect to 443

# LOAD BALANCING NODE IP :
upstream backend {
    server 172.17.0.3; 
    server 172.17.0.4;
}

# RESTRICT ACCESS, MUST BE WITH SAME/CONFIGURED HOSTNAME TO ACCESS PAGE (REDIRECT TO 443) :
server {
        listen 80;
        server_name _;
        return 301 https://$host$request_uri;
}

# RESTRICT ACCESS, MUST BE WITH SAME/CONFIGURED HOSTNAME TO ACCESS PAGE :
server {
    listen 443 default_server;
    listen [::]:443 default_server;
    ssl_certificate /etc/ssl/certs/localhost.crt;
    ssl_certificate_key /etc/ssl/private/localhost.key;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    server_name _;
    return 412;
} 

# ACCESS ON PORT 80 THEN REDIRECT TO 443 :
server {
        listen 80;

        return 301 https://$server_name$request_uri;
}

# ACCESS WITH labs.com ON 443 :
server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    ssl_certificate /etc/ssl/certs/localhost.crt;
    ssl_certificate_key /etc/ssl/private/localhost.key;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    server_name labs.com labs.com;

    location / {
        proxy_redirect      off;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Host $http_host;
        proxy_pass http://backend;
    }
}

# ACCESS WITH telco.com ON 443 :
server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    ssl_certificate /etc/ssl/certs/localhost.crt;
    ssl_certificate_key /etc/ssl/private/localhost.key;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    server_name telco.com telco.com;

    location / {
        proxy_redirect      off;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Host $http_host;
        proxy_pass http://backend;
    }
}

Save & Reload

service nginx reload

Access

You can access on for 1Host Version :
http://labs.com for Non-SSL,
https://labs.com for SSL.
You can access on for 2Host Version :
http://labs.com for Non-SSL,
https://labs.com for SSL.

and 
http://telco.com for Non-SSL,
https://telco.com for SSL.

Some additional Simple Metrics

You can see how much active connection with simple metrics expose from Nginx.
Goes to Nginx-lb
docker exec -it nginx-lb bash
Execute this :
nginx -V 2>&1 | grep -o with-http_stub_status_module
Edit default.conf
nano /etc/nginx/conf.d/default.conf
Add this on bottom of the line :
---
server {
    listen 443;
    listen [::]:443;
    ssl_certificate /etc/ssl/certs/all-labs.crt;
    ssl_certificate_key /etc/ssl/private/all-labs.key;
    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    server_name stat.labs.com stat.labs.com;

    location /nginx_status {
        stub_status on;
        access_log off;
    }
}
---
Access simple metrics on https://stat.labs.com/nginx_status

Testing

If you want to try as fast as possible, you can use my Docker Image on Docker Hub with :
docker network create --subnet=172.19.0.0/16 nginxnet
docker run --net nginxnet --ip 172.19.0.10 --name nginx-lbs -d -p 80:80 -p 443:443 gilangvperdana/research:nginx-lbs
docker run --net nginxnet --ip 172.19.0.11 --name nginx-1 -d gilangvperdana/research:nginx-1
docker run --net nginxnet --ip 172.19.0.12 --name nginx-2 -d gilangvperdana/research:nginx-2
docker run --net nginxnet --ip 172.19.0.13 --name nginx-3 -d gilangvperdana/research:nginx-3
docker run --net nginxnet --ip 172.19.0.14 --name nginx-final -d gilangvperdana/research:nginx-f
Access on https://labs.com OR https://telco.com
or you can use Nginx Load Balancer (nginx-lbs) with Metrics, you can use this image :
docker run --net nginxnet --ip 172.19.0.10 --name nginx-lbs -d -p 80:80 -p 443:443 gilangvperdana/research:nginx-lbs-metrics

Then, you can access metrics on :
https://stat.labs.com/nginx_status

LB Healthcheck NGINX (for Multiple Upstream Endpoint)

location / {
        proxy_pass              http://lb
        proxy_next_upstream     error timeout invalid_header http_500;
        proxy_connect_timeout   2;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment