如何使用TCP负载平衡配置Nginx SSL/TLS直通

时间:2019-11-20 08:52:50  来源:igfitidea点击:

如何在Linux或类似Unix的系统上运行的Nginx负载均衡器上配置SSL/TLS传递?如何对TCP流量进行负载平衡并设置SSL直通,以将在负载平衡器处接收到的SSL流量传递到后端Web服务器上?

通常,SSL终止发生在负载平衡器,未加密的流量发送到后端Web服务器。所有HTTPS/SSL/TLS和HTTP请求都在Nginx服务器本身上终止。 Nginx服务器使用HTTP协议与后端服务器对话。您必须格外小心,以确保没有人在您的专用网络之间监听流量。在共享环境中,专用网络可能不安全,或者您可能无法获得专用网络的VLAN和VPN。在这种情况下,您可以配置Nginx将所有加密的流量直接传递到后端Web服务器。所有后端Web服务器之间的通信均保持加密:请注意,必须在所有后端服务器(例如192.168.1.100和192.168.1.101)上安装SSL/TLS。

如何在Nginx负载均衡后端服务器中安装配置SSL/TLS。
如何在Linux/Nignx上运行的Nginx负载均衡器上配置SSL/TLS传递?
如何对TCP流量进行负载平衡并设置SSL直通,以将在负载平衡器处接收到的SSL流量传递到后端Web服务器上?

通常,所有HTTPS/SSL/TLS和HTTP请求在Nginx服务器上终止。抵达不了后端服务器。Nginx服务器和后端服务器是通过HTTP协议通讯的。

那么,我们该如何配置Nginx,使其将所有加密的流量直接传递到后端Web服务器?

使用nginx stream模块

我们需要使用ngx_stream_core_module模块进行TCP负载平衡,该模块自1.9.0版开始可用。

默认情况下,Debian/Ubuntu Linux上自带的nginx没有,所以需要使用--with-stream配置参数来自己编译。

安装Nginx LB(将Nginx作为负载均衡器)

在Ubuntu Linux 16.04 LTS服务器上安装Nginx LB

首先使用wget命令获取PGP密钥:

$ cd /tmp/
$ wget https://nginx.org/keys/nginx_signing.key

使用apt-get命令安装密钥:

$ sudo apt-key add nginx_signing.key

创建一个配置文件:

$ sudo vi /etc/apt/sources.list.d/nginx.list

内容如下:

deb http://nginx.org/packages/ubuntu/ xenial nginx
deb-src http://nginx.org/packages/ubuntu/ xenial nginx

更新仓库并安装nginx:

$ sudo apt-get update
$ sudo apt-get install nginx

在Debian Linux 9.x服务器上安装Nginx LB

首先使用wget命令获取PGP密钥:

$ cd /tmp/
$ wget http://nginx.org/keys/nginx_signing.key

使用apt-get命令安装密钥:

$ sudo apt-key add nginx_signing.key

创建一个配置文件:

$ sudo vi /etc/apt/sources.list.d/nginx.list

内容如下:

## [ NOTE: Debian 8.x user replace stretch with jessie ] ##
deb http://nginx.org/packages/debian/ stretch nginx
deb-src http://nginx.org/packages/debian/ stretch nginx

保存并关闭文件。更新仓库并安装nginx:

$ sudo apt-get update
$ sudo apt-get install nginx

在RHEL/CentOS Linux 6.x/7.x服务器上安装Nginx LB

为RHEL/CentOS设置yum存储库,创建一个文件/etc/yum.repos.d/nginx.repo:

$ sudo vi /etc/yum.repos.d/nginx.repo

添加以下配置:

## Replace "OS" with rhel or centos depending on the distribution used
## Replace "OSRELEASE" with 6 or 7, for 6.x or 7.x versions, respectively
## An example for CentOS 7.x is as follows:
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

运行以下yum命令:

$ sudo yum update
$ sudo yum install nginx

配置Nginx LB

编辑/etc/nginx/nginx.conf文件

$ sudo vi /etc/nginx/nginx.conf

添加一行:

include /etc/nginx/passthrough.conf;

nginx.conf示例:

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

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    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;
    keepalive_timeout  65;
    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
include /etc/nginx/passthrough.conf;

创建一个文件:

$ sudo vi /etc/nginx/passthrough.conf

内容如下:

## tcp LB  and SSL passthrough for backend ##
stream {
    upstream theitroadbackgroup {
        server 192.168.1.100:443 max_fails=3 fail_timeout=10s;
        server 192.168.1.101:443 max_fails=3 fail_timeout=10s;
    }

log_format basic '$remote_addr [$time_local] '
                 '$protocol $status $bytes_sent $bytes_received '
                 '$session_time "$upstream_addr" '
                 '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

    access_log /var/log/nginx/www.theitroad.local_access.log basic;
    error_log  /var/log/nginx/wwww.theitroad.local_error.log;

    server {
        listen 443;
        proxy_pass theitroadbackgroup;
        proxy_next_upstream on;
    }
}

检查配置文件语法:

$ nginx -t

重新加载Nginx服务器使配置生效:

$ sudo systemctl reload nginx

或者

$ sudo /etc/init.d/nginx reload

在Nginx(负载均衡器,运行在公网IP)上打开端口443和80

在Debian/Ubuntu Linux上使用ufw命令打开端口443:

$ sudo ufw allow proto tcp from any to 202.54.1.5 port 443
$ sudo ufw allow proto tcp from any to 202.54.1.5 port 80

在CentOS7/RHEL7上使用以下命令打开端口80/443:

# firewall-cmd --get-default-zone
# firewall-cmd --get-active-zones
# firewall-cmd --permanent --add-service=http
# firewall-cmd --permanent --add-service=https
# firewall-cmd --reload

后端服务器设置

后端服务器(192.168.1.100和192.168.1.101)必须设置SSL/TLS。

这里我们使用Lets Encrypt SSL免费证书。

$ sudo apt-get install git bc wget curl
$ cd /tmp/
$ git clone https://github.com/Neilpang/acme.sh.git
$ cd acme.sh/
$ sudo -i
# ./acme.sh --install
$ sudo source ~/.bashrc
# D=/var/www/html
# DOM='www.theitroad.local'
# mkdir -vp ${D}/.well-known/acme-challenge/
###---[ NOTE: Adjust permission as per your setup ]---###
# chown -R www-data:www-data ${D}/.well-known/acme-challenge/
# chmod -R 0555 ${D}/.well-known/acme-challenge/
# mkdir -p /etc/nginx/ssl/${DOM}/
# cd /etc/nginx/ssl/${DOM}/
# openssl dhparam -out dhparams.pem -dsaparam 4096
# acme.sh --issue -w $D -d $DOM -k 4096
# vi /etc/nginx/sites-available/default

编辑ssl的配置:

## START: SSL/HTTPS www.theitroad.local ###
server {
    #------- Start SSL config with http2 support ----#
    listen 443 http2;
    server_name www.theitroad.local;
    ssl on;
    ssl_certificate /etc/nginx/ssl/www.theitroad.local/www.theitroad.local.cer;
    ssl_certificate_key /etc/nginx/ssl/www.theitroad.local/www.theitroad.local.key;
    ssl_session_timeout 30m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
    ssl_session_cache shared:SSL:10m;
    ssl_dhparam /etc/nginx/ssl/www.theitroad.local/dhparams.pem;
    ssl_prefer_server_ciphers on;
     ## Improves TTFB by using a smaller SSL buffer than the nginx default
    ssl_buffer_size 8k;
 
    ## Enables OCSP stapling
    ssl_stapling on;
    resolver 8.8.8.8;
    ssl_stapling_verify on;
 
    ## Send header to tell the browser to prefer https to http traffic
    add_header Strict-Transport-Security max-age=31536000;
 
    ## SSL logs ##
    access_log /var/log/nginx/ssl_access.log;
    error_log /var/log/nginx/ssl_error.log;
    #-------- END SSL config -------##
     # Add rest of your config below like document path and more ##
}
## END SSL www.theitroad.local ######

然后创建一个shell脚本/root/hook.sh,

用于将/etc/nginx/配置从192.168.1.100复制到第二台服务器(192.168.1.101)中并。

脚本参考:

#!/bin/bash
# ---------------------------------------------------------------------
_rsync="/usr/bin/rsync"
_ssh="/usr/bin/ssh"
_lxc="/usr/bin/lxc"
_rsync_opt='-az -H --delete --numeric-ids '
u="root"
## 后端服务器ip ##
servers="192.168.1.101"
S='/etc/nginx/'
D=/etc/nginx

for b in ${servers}
do
${_rsync} ${_rsync_opt} "$@" ${S} ${u}@${b}:${D}
${_ssh} ${u}@${b} /etc/init.d/nginx reload
done
## Reload 192.168.1.100 too ##
/etc/init.d/nginx reload

执行以下命令:

# acme.sh --installcert -d $DOM --keypath /etc/nginx/ssl/$DOM/$DOM.key --fullchainpath /etc/nginx/ssl/$DOM/$DOM.in.cer --reloadcmd '/root/hook.sh'

现在,添加cron任务,自动创建证书并运行/root/hook.sh:

## default cron installed by acme.sh
## no need to create it ##
33 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
 
## 每90天更新一次证书 ##