文章目录
  1. 1 概述
  2. 2 安装与配置
    1. 2.1 安装
    2. 2.2 配置为 systemd 服务
    3. 2.3 防火墙放行
    4. 2.4 常用文件
    5. 2.5 常用命令
  3. 3 基本配置
    1. 3.1 工作进程
    2. 3.2 配置符号
    3. 3.3 配置文件结构
    4. 3.4 主配置
    5. 3.5 HTTP/HTTPS 配置
    6. 3.6 验证
  4. 4 准备证书
    1. 4.1 生成 X509 V3 扩展文件
    2. 4.2 生成密钥和证书文件
    3. 4.3 检查并重新加载 Nginx
  5. 5 客户端验证
    1. 5.1 设置 hosts
    2. 5.2 Linux 下导入根证书
    3. 5.3 Windows 下导入根证书

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。

1
2
3
4
5
6
7
8
## 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)。

1
2
3
4
5
6
sudo systemctl enable nginx
sudo systemctl start nginx
curl http://localhost/

# sudo systemctl stop nginx
# sudo systemctl disable nginx

2.3 防火墙放行

1
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 常用文件

1
2
3
4
5
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 常用命令

1
2
3
4
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 安装及其单机多实例部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
## 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 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
## 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 验证

1
curl http://centos

4 准备证书

4.1 生成 X509 V3 扩展文件

1
2
3
4
5
6
## 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
## 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

1
2
sudo nginx -t
sudo nginx -s reload

5 客户端验证

5.1 设置 hosts

Linux: /etc/hosts

1
2
3
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

1
2
3
192.168.214.132    centos
192.168.214.132 kefeng.wang
192.168.214.132 www.kefeng.wang

5.2 Linux 下导入根证书

1
2
3
4
5
6
7
8
# 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 时报错:

1
2
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 忽略服务器证书验证

    1
    curl -k https://kefeng.wang
  • curl 指定获取到的 CA 证书

    1
    2
    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. 1 概述
  2. 2 安装与配置
    1. 2.1 安装
    2. 2.2 配置为 systemd 服务
    3. 2.3 防火墙放行
    4. 2.4 常用文件
    5. 2.5 常用命令
  3. 3 基本配置
    1. 3.1 工作进程
    2. 3.2 配置符号
    3. 3.3 配置文件结构
    4. 3.4 主配置
    5. 3.5 HTTP/HTTPS 配置
    6. 3.6 验证
  4. 4 准备证书
    1. 4.1 生成 X509 V3 扩展文件
    2. 4.2 生成密钥和证书文件
    3. 4.3 检查并重新加载 Nginx
  5. 5 客户端验证
    1. 5.1 设置 hosts
    2. 5.2 Linux 下导入根证书
    3. 5.3 Windows 下导入根证书