Monday, July 22, 2019

Deploy Nginx and HAproxy load balancer with SSL certificate



Summary :

Nginx is a high performance web server software. It is a much more flexible and lightweight program compare to Apache web Server. This article show how to install and configure nginx with external haproxy load balancer

Environment :

Server                IP            Role
nginx-node1           10.152.0.25   nginx
nginx-node1           10.152.0.26   nginx
nginx-loadbalancer    10.152.0.27   load balancer



Install and Configure nginx on Centos 7

To add the CentOS 7 EPEL repository, open terminal and use the following command:

# yum install epel-release














Install Nginx using the following yum command:

# yum install nginx














To get Nginx running, type:

# systemctl start nginx
# systemctl enable nginx







To allow HTTP and HTTPS traffic:

# firewall-cmd --permanent --zone=public --add-service=http
# firewall-cmd --permanent --zone=public --add-service=https
# firewall-cmd --reload












Verify nginx running on http using public ip:

 










Create an SSL Certificate on Nginx for CentOS 7

Note: This step not required if you are using HA Proxy configured with SSL certificate.

TLS, and its predecessor SSL are web protocols used to wrap normal traffic in a protected, encrypted wrapper. By enabling this, servers can send traffic safely between the server and the client without the concern that the messages will be intercepted and read by an external party. 

create a new directory to store our private key:

# mkdir /etc/nginx/ssl

Files must be kept strictly private, we will modify the permissions to make sure only the root user has access:

# chmod 700 /etc/nginx/ssl


Create the SSL key and certificate files with openssl:

# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx-selfsigned.key -out /etc/nginx/ssl/nginx-selfsigned.crt

  • openssl: This is the basic command line tool for creating and managing OpenSSL certificates, keys, and other files.
  • req -x509: This specifies that we want to use X.509 certificate signing request (CSR) management. The "X.509" is a public key infrastructure standard that SSL and TLS adhere to for key and certificate management.
  • -nodes: This tells OpenSSL to skip the option to secure our certificate with a passphrase. We need Apache to be able to read the file, without user intervention, when the server starts up. A passphrase would prevent this from happening, since we would have to enter it after every restart.
  • -days 365: This option sets the length of time that the certificate will be considered valid. We set it for one year here.
  • -newkey rsa:2048: This specifies that we want to generate a new certificate and a new key at the same time. We did not create the key that is required to sign the certificate in a previous step, so we need to create it along with the certificate. The rsa:2048 portion tells it to make an RSA key that is 2048 bits long.
  • -keyout: This line tells OpenSSL where to place the generated private key file that we are creating.
  • -out: This tells OpenSSL where to place the certificate that we are creating.















While we are using OpenSSL, we should also create a strong Diffie-Hellman group, which is used in negotiating Perfect Forward Secrecy with clients.

# openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

# cat /etc/ssl/certs/dhparam.pem | sudo tee -a /etc/nginx/ssl/nginx-selfsigned.crt



Configure nginx.conf to use certificates:

 
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;

        server_name  _;
        root         /usr/share/nginx/html;

        ssl_certificate "/etc/nginx/ssl/nginx-selfsigned.crt";
        ssl_certificate_key "/etc/nginx/ssl/nginx-selfsigned.key";

        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;


        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

}



Check nginx.conf syntax:

nginx -t

Reload nginx service:

systemctl reload nginx













Verify nginx running on https using public ip:











Install HAProxy :

# yum install haproxy -y











Start haproxy service : 

# systemctl enable haproxy
# systemctl start haproxy






Allow firewall rule for haproxy :

firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --permanent --zone=public --add-port=8181/tcp
firewall-cmd --reload

 









Add host entries on /etc/hosts :

# vim /etc/hosts
 
10.152.0.25 nginx-node1
10.152.0.26 nginx-node2


Create a new directory to store our private key :

# mkdir /etc/haproxy/ssl

Files must be kept strictly private, we will modify the permissions to make sure only the root user has access:

# chmod 700 /etc/haproxy/ssl


Create the SSL key and certificate files with openssl:

# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/haproxy/ssl/haproxy-selfsigned.key -out /etc/haproxy/ssl/haproxy-selfsigned.crt

 
While we are using OpenSSL, we should also create a strong Diffie-Hellman group, which is used in negotiating Perfect Forward Secrecy with clients.

# openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

# cat /etc/ssl/certs/dhparam.pem /etc/haproxy/ssl/haproxy-selfsigned.crt /etc/haproxy/ssl/haproxy-selfsigned.key > /etc/haproxy/ssl/haproxy-selfsigned-crt-key.pem


 
Configure haproxy.cfg :

# vim /etc/haproxy/haproxy.cfg

global
  log 127.0.0.1 local0
  maxconn 4000
  daemon
  uid 99
  gid 99

defaults
  log     global
  mode    http
  option  httplog
  option  dontlognull
  timeout server 5s
  timeout connect 5s
  timeout client 5s
  stats enable
  stats refresh 10s
  stats uri /haproxy?stats

frontend https_frontend
  bind *:80
  bind *:443 ssl crt /etc/haproxy/ssl/haproxy-selfsigned-crt-key.pem
  mode http
  option httpclose
  option forwardfor
  reqadd X-Forwarded-Proto:\ https
  default_backend web_server
 
backend web_server
  mode http
  balance roundrobin
  cookie SERVERID insert indirect nocache
  server ngnix-node1 10.152.0.25:80 check cookie nginx-node1
  server ngnix-node2 10.152.0.26:80 check cookie nginx-node2

 

Verify HA Proxy statistics :

 





 






Verify nginx running on HA Proxy load balancer via https using public ip: