Nginx 负载均衡及其 HTTPS 部署

Nginx 是最流行的软负载均衡中间件。本文以 CentOS 为例,使用 Nginx 实现 Tomcat 多实例负载均衡的部署,并总结了安装 HTTPS 证书的方法。

作者:王克锋
出处:https://kefeng.wang/2016/12/29/nginx-https/
版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。

1 概述

Nginx(发音为“Engine X”),使用基于BSD许可,作者是俄罗斯人。
是个轻量级、高性能的 HTTP 服务器和反向代理服务器,也是IMAP/POP3/SMTP 代理服务器。
国内各大门户网站已经部署了 Nginx,如阿里、腾讯、新浪、网易等。

2 安装与配置

2.1 安装

优点是自动化安装,缺点是不可指定 Nginx 版本(比如下面的操作只能安装版本 1.14.0)。
如果对 Nginx 版本没有特别要求,推荐使用该方式,本文也是采用此方式。
如果是 Windows 环境,下载 nginx-1.15.2.zip 并解压后即可直接运行 nginx.exe。

## sudo vim /etc/yum.repos.d/nginx.repo
## http://nginx.org/en/linux_packages.html#stable
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
## sudo yum -y install nginx

2.2 配置为 systemd 服务

注意:nginx.service 与 nginx.conf 中的 pid 配置必须一致(建议用 /var/run/nginx.pid)。

sudo systemctl enable nginx
sudo systemctl start nginx
curl http://localhost/

# sudo systemctl stop nginx
# sudo systemctl disable nginx

2.3 防火墙放行

### sudo vim /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
### 重启生效: sudo systemctl restart iptables

2.4 常用文件

ls -l /usr/sbin/nginx ## 主文件
ls -l /etc/nginx/mime.types ## mime.types
ls -l /etc/nginx/nginx.conf ## 主配置文件
ls -l /etc/nginx/conf.d/ ## 被 http{} 包含的 server{} 文件
ls -l /var/log/nginx/ ## 日志文件(access.log, error.log)

2.5 常用命令

sudo nginx -v ## 查看版本(nginx/1.10.2)
sudo nginx -t ## 检查配置文件语法
sudo nginx -s stop   ## 快速退出
sudo nginx -s quit   ## 优雅退出
sudo nginx -s reload ## 重载配置(主进程不变,新工作进程加载新配置,原工作线程优雅退出)

3 基本配置

http://nginx.org/en/docs/
http://nginx.org/en/docs/ngx_core_module.html

3.1 工作进程

主进程只能 1 个,用来读取配置文件、管理工作进程;
工作进程个数由 worker_processes 指定,用来处理请求。

3.2 配置符号

容量符号: k/m(K/M)
时间符号: yMdhms/ms/w(周)
事件模型: use [select|poll|epoll]

3.3 配置文件结构

Nginx 由指令控制的模块组成,指令包括简单指令和块指令。
简单指令形如“name value;”,块指令形如“name [value] {}”,不在块中的指令被认为是在主块 main{} 中。

3.4 主配置

下面的配置是充当前面三个 Tomcat 实例(端口号分别为 8001/8002/8003)的负载均衡。
相关链接: Tomcat 安装及其单机多实例部署

## sudo vim /etc/nginx/nginx.conf
user  nginx;
worker_processes auto; # 工作进程个数(auto或具体数值比如2)

error_log  /var/log/nginx/error.log warn; # 错误日志文件、日志级别
pid        /var/run/nginx.pid;

events {
    worker_connections 1024; # 最大并发连接数
    use epoll; # 网络I/O模型
}

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; # 启用内核复制模式, 有利于I/O
    keepalive_timeout 60; # 长连接持续时长

    # 配置 gzip 压缩,可用于:http, server, location
    gzip on; # 开启gzip(默认为关闭)
    gzip_min_length 1k; # 设置允许压缩的页面最小字节数(默认为0), 小于1k可能会越压越大。
    gzip_buffers 4 8k;  # 原始数据大小以 8k 为单位的4倍申请内存
    gzip_comp_level 5;  # gzip压缩比(默认为1), 取值为1-9, 压缩比与CPU消耗成正比
    gzip_types text/plain text/css text/javascript application/x-javascript; # 这些 MIME 才压缩(无论是否指定, text/html总是压缩)

    # 预定义 upstream 及其名字,将在 http.server.location.proxy_pass 中引用: http://upstream_name
    # http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
    # http://nginx.org/en/docs/http/load_balancing.html
    upstream upstream_tomcat {
        # 常见负载均衡机制:
        # (1)round-robin; # 轮询分配(缺省值)
        # (2)ip_hash;     # 访问者IP地址的哈希值,可保证同一客户端落在同一服务器上
        # (3)least_conn;  # 最少连接
        # (4)fair;        # 响应时间短的优先分配
        server localhost:8001 weight=3; # 指定权重(三种机制都适用)
        server localhost:8002; # 默认权重为1
        server localhost:8003; # 默认权重为1
    }

    include /etc/nginx/conf.d/*.conf; ## 各个 server{} 块
}

3.5 HTTP/HTTPS 配置

## sudo vim /etc/nginx/conf.d/default.conf
server { # HTTP
    # 对于特定请求 http://host:port/path
    # (1)host 匹配于 server.server_name
    # (2)port 匹配于 server.listen
    # (3)path 匹配于 server.location, 而且优先采用精确匹配项
    listen       80; # HTTP
    listen       443 ssl; # HTTPS
    server_name  localhost centos kefeng.wang www.kefeng.wang; # 通配符、正则
    if ($scheme != https) { # 强制 HTTP 跳转至 HTTPS
        # host 与 server_name 等价, redirect/permanent 分别为临时跳转/永久跳转
        rewrite ^(.*)$  https://$host$1 permanent; 
    }

    # 重定向错误页
    error_page   404              /static/error/404.html;
    error_page   500 502 503 504  /static/error/50x.html;

    # 静态页面,直接指向目录 /usr/share/nginx
    # http://denglz.blog.51cto.com/3617037/1341841
    location ^~ /static/ { # 首部匹配
        root   /usr/share/nginx; # 其下有 static 目录
        index  index.html index.htm;

        # 以下指令都适用于 http, server, location
        add_header X-Header-Name value;
        chunked_transfer_encoding on;
        expires 1d;
        gzip on; # 开启压缩(默认关闭)
    }

    # 动态数据,转给三个 Tomcat 实例负载均衡
    location / {
        proxy_pass   http://upstream_tomcat;
        proxy_set_header Host $host;
        proxy_set_header Connection close;
        proxy_connect_timeout 100ms; # 代理机器连接超时时长(默认的60s太长了)
        expires 30d;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt { access_log off; log_not_found off; allow all; }

    # HTTPS 专用配置
    # http://nginx.org/en/docs/http/configuring_https_servers.html
    ssl_certificate      /etc/nginx/ssl/nginx.crt; # 证书文件
    ssl_certificate_key  /etc/nginx/ssl/nginx.key; # 密钥对文件(包含公钥和私钥, 私钥不会发给客户端)
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # SSL(包括 v3)都有漏洞,应该用 TLS(TLS1.0 = SSL 3.1)
    ssl_ciphers   HIGH:!aNULL:!MD5;
}

3.6 验证

curl http://centos

4 准备证书

4.1 生成 X509 V3 扩展文件

## sudo mkdir -p /etc/nginx/ssl/
## sudo vim /etc/nginx/ssl/x509v3.ext
basicConstraints=CA:FALSE
authorityKeyIdentifier=keyid,issuer
keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName=email:copy,DNS:centos,DNS:kefeng.wang,DNS:www.kefeng.wang,IP:192.168.214.132

4.2 生成密钥和证书文件

http://chenjumin.iteye.com/blog/2328875

## cd /etc/nginx/ssl/
## sudo vim update.sh
sudo rm -f nginx.* public.pem private.pem modulus.js

## 生成密钥对(nginx.key, 包含公钥和私钥)
sudo openssl genrsa -out nginx.key 2048

## 生成证书请求(nginx.csr, 包含公钥和主题信息)
## 注意:CN必须是将来的域名,否则 Chrome 访问时报错 NET::ERR_CERT_AUTHORITY_INVALID
sudo openssl req -new -sha256 -key nginx.key -out nginx.csr -subj "/CN=kefeng.wang/O=kefeng.wang/L=SHANGHAI/ST=SHANGHAI/C=CN"

## 商用证书: 把证书请求文件(nginx.csr)连同费用,交给 Verisign 等CA服务公司,CA 用它的私钥签名生成证书返还证书(nginx.crt);
## 个人证书: 个人使用密钥(nginx.key),签发证书请求(nginx.csr),生成根证书(nginx.crt);
## 商用证书的 CA 根证书已经内置在浏览器中,无需手工导入;而个人证书则需要导入。
## 注意: 必须指定 -sha256, 否则 Chrome 访问时报错 This page is insecure (broken HTTPS). SHA-1 Certificate
sudo openssl x509 -req -sha256 -days 3650 -in nginx.csr -signkey nginx.key -extfile x509v3.ext -out nginx.crt
sudo sz nginx.crt ## 下载至 Windows

# 根据密钥对(nginx.key),生成私钥(private.pem)、公钥(public.pem)、modulus(JavaScript 中可用)
sudo openssl pkcs8 -topk8 -in nginx.key -nocrypt -out private.pem
sudo openssl rsa -in nginx.key -pubout -out public.pem
openssl rsa -in nginx.key -noout -modulus | sudo tee -a modulus.js

4.3 检查并重新加载 Nginx

sudo nginx -t
sudo nginx -s reload

5 客户端验证

5.1 设置 hosts

Linux: /etc/hosts

127.0.0.1    centos
127.0.0.1    kefeng.wang
127.0.0.1    www.kefeng.wang

WINDOWS: C:\Windows\System32\drivers\etc\hosts

192.168.214.132    centos
192.168.214.132    kefeng.wang
192.168.214.132    www.kefeng.wang

5.2 Linux 下导入根证书

# sudo cp /etc/pki/tls/certs/ca-bundle.crt{,.bak} ## 首次备份
sudo diff /etc/pki/tls/certs/ca-bundle.crt{,.bak} ## 比较备份
sudo cp /etc/pki/tls/certs/ca-bundle.crt{.bak,} ## 恢复备份
cat nginx.crt | sudo tee -a /etc/pki/tls/certs/ca-bundle.crt ## 追加根证书

curl https://centos
curl https://kefeng.wang
curl https://www.kefeng.wang

执行 curl https://kefeng.wang 时报错:

curl: (60) Issuer certificate is invalid.
More details here: http://curl.haxx.se/docs/sslcerts.html

浏览网址 https://curl.haxx.se/docs/sslcerts.html 发现原因和解决办法:
curl 对无法识别自签名证书,需要采取两种措施之一:

  • curl 忽略服务器证书验证
curl -k https://kefeng.wang
  • curl 指定获取到的 CA 证书
openssl x509 -in <(openssl s_client -connect localhost:443 -prexit 2>/dev/null) | sudo tee curl.pem
sudo curl --cacert curl.pem https://kefeng.wang

5.3 Windows 下导入根证书

对于 Nginx 中使用个人证书,如果不在 Windows 下导入根证书,Chrome 浏览器会报错:
地址栏会有感叹号和红斜线,“您的连接不是私密连接”,展开“高级”才能继续访问。
个人证书安装方法:从 Linux 下载 nginx.crt,Windows 下双击安装,指定证书存储位置“受信任的根证书颁发机构”。
使用 Chrome 浏览器打开 https://kefeng.wang, HTTPS 相关标志全部正常。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值