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

时间:2020-01-09 10:37:46  来源: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。

stream 模块

您需要使用ngx_stream_core_module模块进行TCP负载平衡,该模块自1.9.0版开始可用。
默认情况下,该模块不是在Debian/Ubuntu或任何其他发行版上构建的,应该使用--with-stream配置参数来启用。
但是,您可以安装官方的Nginx软件包并使用此模块。

步骤1:安装Nginx LB

根据您的Linux发行版运行命令:

Ubuntu Linux 16.04 LTS服务器

首先使用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服务器

首先使用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服务器

您必须为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

步骤2:配置Nginx LB

编辑/etc/nginx/nginx.conf文件,运行:

$ sudo vi /etc/nginx/nginx.conf

追加以下行:

include /etc/nginx/passthrough.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 theitroadcomapache {
        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 theitroadcomapache;
        proxy_next_upstream on;
    }
}

保存并关闭文件。
测试一下:

$ nginx -t

重新启动或重新加载Nginx服务器,运行:

$ sudo systemctl reload nginx

或者

$ sudo /etc/init.d/nginx reload

打开端口443和80(必须在公共IP上运行的Nginx服务器上键入)

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

$ sudo ufw allow proto tcp from any to 192.54.1.5 port 443
$ sudo ufw allow proto tcp from any to 192.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

步骤3:后端网路伺服器设定为192.168.1。{100,101}

您必须在生产现场使用真实/商业证书。
我将Nginx与免费的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 ######

保存并关闭文件。
创建一个名为/root/hook.sh的shell脚本,将/etc/nginx /配置从192.168.1.100复制到第二台服务器(192.168.1.101)并重新加载它。
这是一个示例脚本:

#!/bin/bash
# Purpose: Replicate ssl and nginx settings/certs across all backends
# Author: Hyman Gite {https://www.theitroad.local}
# License: GPL v2.0+
# -
# NOTE: SSH keys must be set between all hosts
# The certificate information must be replicated on 
# every server. Modify script as per your needs.
# --------------------------------------------------------------------
_rsync="/usr/bin/rsync"
_ssh="/usr/bin/ssh"
_lxc="/usr/bin/lxc"
_rsync_opt='-az -H --delete --numeric-ids '
u="root"
## add all IPs/hostnames of backend here ##
servers="192.168.1.101"
S='/etc/nginx/'
D=/etc/nginx
## Do it ##
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
 
## above will renew certificate every 90 days ##