8. Nginx高级配置
3 Nginx高级配置
3.1 Nginx状态页
-
基于ngx_http_stubs_module模式实现, 在编译安装时, 需要添加编译参数, --with-http_stub_status_module, 否则配置完成之后监测会提示语法错误
-
状态页显示的是整个服务器的状态, 而非虚拟主机的状态
# 在任意一个虚拟主机配置即可
location /nginx_status {
stub_status;
auth_basic "auth log";
auth_basic_user_file /apps/nginx/conf/.htpasswd;
allow 120.78.154.82;
deny all;
}
- 状态页用于输出nginx的基本状态信息
Active connections: 2
server accepts handled requests
4(accepts) 4(handled) 3(requests)
Reading: 0 Writing: 1 Waiting: 1
- 状态页参数
Active connections: # 当前处于活动状态的客户端连接数, 包括连接等待, 空闲连接数 = reading+writing+waiting
accepts: # 统计总值, Nginx自启动后, 已经接受的客户端请求的总数
handled: # 统计总值, Nginx自启动后, 已经处理完成的客户端请求总数, 通常等于accepts, 除非有因worker_connections限制等被拒绝的连接
requests: # 统计总值, Nginx自启动后客户端发来的总的请求数
Reading: # 当前状态, 正在读取客户端请求报文首部的连接的连接数, 数值越大, 说明排队现象越严重, 性能不足
Writing: # 当前状态, 正在向客户端发送响应报文过程中的连接数, 数值越大, 说明访问量越大
Waiting: # 当前状态, 正在等待客户端发出请求的空闲连接数, 开启 keep-alive的情况下, 这个值等于active - (reading+writing)
3.2 Nginx 第三方模块
第三方模块是对nginx的功能扩展, 第三方模块需要在编译安装nginx的时候使用参数--add-module=PATH指定路径添加, 有的模块是由公司的开发人员针对业务需求定制开发的, 有的模块是开源爱好者开发好之后上传到github进行开源的模块, nginx支持第三方模块, 需要从源码重新编译, 比如:开源的echo模块: https://github.com/openresty/echo-nginx-module
[17:12:39 root@nginx ~]#systemctl stop nginx
[17:47:15 root@nginx ~]#cp -a /apps/nginx/sbin/nginx{,.bak}
[17:48:00 root@nginx ~]#vim /apps/nginx/conf.d/pc.conf
server {
listen 80;
server_name pc.wang.org;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
location / {
root /data/nginx/html/pc;
}
location /main {
index index.html;
default_type text/html; # 必须指定默认类型为文件, 否则会认为是不识别的默认模式, 浏览器会把main文件下载下来
echo "hello world,main-->"; # 访问/main时, 会打印hello world,main--> remote_addr(远程连接客户端地址)
echo $remote_addr; # 远程连接客户端地址, 公网ip
echo_reset_timer; # 将计时器开始时间重置为现在
echo_location /sub1; # 调用/sub1 location里的指令
echo_location /sub2; # 调用/sub2 location里的指令
echo "took $echo_timer_elapsed sec for total."; # 打印访问/main, 总共花费的时间
}
location /sub1 {
echo_sleep 1;
echo sub1;
}
location /sub2 {
echo_sleep 1;
echo sub2;
}
}
# 此时, 因为nginx编译时没有把echo模块编译进去, 因此, 重新加载服务会报错
[17:52:12 root@nginx ~]#nginx -s reload
nginx: [emerg] unknown directive "echo" in /apps/nginx/conf.d/pc.conf:14
- 下面准备重新编译nginx, 把echo模块编译进去
[17:12:39 root@nginx ~]#systemctl stop nginx # 停止nginx服务
[17:47:15 root@nginx ~]#cp -a /apps/nginx/sbin/nginx{,.bak} # 将现有的二进制文件做备份
cd /usr/local/src
yum -y install git
git clone https://github.com/openresty/echo-nginx-module.git
[18:13:01 root@nginx /usr/local/src]#ls
echo-nginx-module-master.zip nginx-1.18.0 nginx-1.18.0.tar.gz
[18:18:22 root@nginx /usr/local/src]#unzip echo-nginx-module-master.zip
[18:19:05 root@nginx /usr/local/src]#ls
echo-nginx-module-master echo-nginx-module-master.zip nginx-1.18.0 nginx-1.18.0.tar.gz
[18:13:04 root@nginx /usr/local/src]#cd nginx-1.18.0/
./configure --prefix=/apps/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=/usr/local/src/echo-nginx-module-master
make && make install
# 编译成功
[18:21:07 root@nginx /usr/local/src/nginx-1.18.0]#ll /apps/nginx/sbin/nginx
-rwxr-xr-x 1 root root 8126344 Mar 17 18:21 /apps/nginx/sbin/nginx
[18:21:17 root@nginx /usr/local/src/nginx-1.18.0]#ll /apps/nginx/sbin/
total 22768
-rwxr-xr-x 1 root root 8126344 Mar 17 18:21 nginx # 新的二进制程序
-rwxr-xr-x 1 nginx nginx 7591104 Mar 15 15:22 nginx.bak # 手动的备份
-rwxr-xr-x 1 nginx nginx 7591104 Mar 15 15:22 nginx.old # 编译后会自动备份
[18:21:37 root@nginx /usr/local/src/nginx-1.18.0]#nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[18:22:26 root@nginx /usr/local/src/nginx-1.18.0]#systemctl start nginx
图片.png
3.3 Nginx变量使用
nginx的变量可以在配置文件中引用, 作为功能判断或者日志等场景使用
变量可以分为内置变量和自定义变量
内置变量是由nginx模块自带, 通过变量可以获取到众多的与客户端访问相关的值
3.3.1 内置变量
- 官方文档:
http://nginx.org/en/docs/varindex.html
- 常用内置变量
$remote_addr;
# 显示客户端地址, 一般是用户的公网出口ip, 请求通告DNS解析到企业的防护墙入口, 通告DNAT发送到四层负载(HA), 再由HA转发给七层的Nginx, 由于HA工作在四层时并不会修改请求报文的源ip, 防火墙的DNAT也不会修改源ip, 因此请求报文到达Nginx后, 源ip还是用户公网出口ip, 也就会被记录到$remote_addr;
$http_name;
#所有请求报文的字段, 都可以用$http_name变量来获取, name就是请求报文字段的名字
$proxy_add_x_forwarded_for;
# 此变量表示将客户端ip追加到请求报文中X-Forwarded-For首部字段, 多个ip之间用逗号分隔, 如果请求报文中没有X-Forwarded-For, 就使用$remore_addr;
the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.
$args;
# 变量中存放了URL中的参数, 例如访问: http://pc.wang.org/main/index.do?id=202020202&partner=search
# 返回结果为, id=202020202&partner=search
$document_root;
# 保存了针对当前资源的请求的系统根目录, 例如:/apps/nginx/html
$document_uri;
# 保存了当前请求中, 不包含参数的URI, 注意是不包含请求的指令, 比如 http://pc.wang.org/main/index.do?id=202020202&partner=search 会被定义为/main/index.do
# 返回结果为: /main/index.do
$host;
# 存放了请求的host名称
limit_rate 10240
echo $limit_rate;
# 如果nignx服务器使用了limit_rate配置了限制下载速度, 则会显示具体速度, 否则显示0
$remote_port;
# 客户端请求nginx服务器随机打开的端口号, 这里是每个客户端自己的端口
$remote_user;
# 已经经过auth basic module验证的用户名
$request_body_file;
# 做反向代理时发给后端服务器的本地资源的名称
$request_method;
# 请求资源的方式, GET/PUT/DELETE等
$request_filename;
# 当前请求的资源文件的磁盘路径, 由/root或alias指令与URI请求生成的文件组成的绝对路径
如: /apps/nginx/html/main/index.html
# 当请求的资源总是找不到时, 可以在对应的location下, 添加$request_filename来查看具体是找的磁盘上哪个文件
$request_uri; 除了FQND剩下的链接内容
# 包含请求参数的原始URI, 不包含主机名, 相当于: $document_uri?$args, 例如: /main/index.do?id=20200221&partner=search
$scheme;
# 请求的协议, 例如: http, https, ftp等
# 通过$scheme可以实现, 当用户用http访问时, 自动跳转的https
$server_protocol;
# 保存了客户端请求资源使用的协议的版本, 例如: HTTP/1.0, HTTP/1.1, HTTP/2.0等
$server_addr;
# 保存了服务器的ip地址
$server_name;
# 请求的服务器的主机名
$server_port;
# 请求的服务器的端口号
$http_name;
# name为任意请求报文首部字段, 表示记录请求报文的首部字段
$http_user_agent;
# 客户端浏览器的详细信息
$http_cookie;
# 客户端的cookie信息
$cookie_name;
# name为任意请求报文首部字段cookie的key名
- 范例: $args
[18:53:45 root@nginx /apps/nginx/conf.d]#vim pc.conf
server {
listen 80;
server_name pc.wang.org;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
location / {
root /data/nginx/html/pc;
}
location /main {
index index.html;
default_type text/html;
echo "hello world,main-->";
echo $remote_addr;
echo $args;
echo_reset_timer;
echo_location /sub1;
echo_location /sub2;
echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
echo_sleep 1;
echo sub1;
}
location /sub2 {
echo_sleep 1;
echo sub2;
}
}
[18:55:03 root@nginx /apps/nginx/conf.d]#nginx -s reload
图片.png
- 范例: $document_root
server {
listen 80;
server_name pc.wang.org;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
location / {
root /data/nginx/html/pc;
}
location /main {
index index.html;
default_type text/html;
echo "hello world,main-->";
echo $remote_addr;
echo $document_root;
}
}
[19:11:22 root@nginx /apps/nginx/conf.d]#nginx -s reload
[19:11:23 root@nginx /apps/nginx/conf.d]#curl http://pc.wang.org/main/
hello world,main-->
10.0.0.86
/apps/nginx/html # 因为location /main中没有定义document_root, 而且访问/main不会匹配/, 因此会用编译安装时定义的编译路径+html, 和server中的设置无关
- 范例: $document_uri
- 范例: $host
server {
listen 80;
server_name pc.wang.org;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
location / {
root /data/nginx/html/pc;
}
location /main {
index index.html;
default_type text/html;
echo "hello world,main-->";
echo $remote_addr;
echo $document_root;
echo $document_uri;
echo $host;
}
}
nginx -s reload
[19:17:57 root@nginx /apps/nginx/conf.d]#curl 'http://pc.wang.org/main/index.do?id=202020202&partner=search'
hello world,main-->
10.0.0.86
/apps/nginx/html
/main/index.do # $document_uri的返回结果, 不带域名, 不带参数
pc.wang.org # 请求的主机头
- 范例: $scheme
- 范例: $http_user_agent
- 范例: $http_cookie
- 范例: $cookie_name
- 范例:
$scheme://$host$document_uri?$args # 可以显示用户访问的完整路径
server {
listen 80;
server_name pc.wang.org;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
location / {
root /data/nginx/html/pc;
}
location /main {
index index.html;
default_type text/html;
echo "hello world,main-->";
echo $remote_addr;
echo $document_root;
echo $scheme;
echo $host;
echo $document_uri;
echo $args;
echo $scheme://$host$document_uri?$args;
}
}
nginx -s reload
# curl -b "cookie_key=cookie_name;key=name;key=name", curl -b可以模拟浏览器携带cookie访问
[19:28:36 root@nginx /apps/nginx/conf.d]#curl -b name=admin 'http://pc.wang.org/main/index.do?id=202020202&partner=search'
hello world,main-->
10.0.0.86
/apps/nginx/html
http # $scheme返回值
pc.wang.org $host返回值, FQDN
/main/index.do $request_uri返回值, 除了FQDN和参数, 剩下的部分
id=202020202&partner=search # $args, 返回URL中的参数
http://pc.wang.org/main/index.do?id=202020202&partner=search # 访问的整个URL路径
3.3.2 自定义变量
假如需要自定义变量名称和值, 可以使用指令set $variable value
; 另外自定义变量也可引用内置变量的值
语法格式:
set $variable value;
可以用在 server, location, if中
范例: 自定义变量的使用
location /main {
index index.html;
default_type text/html;
echo "hello world,main-->";
set $name admin;
echo $name;
set $client_ip $remote_addr;
echo $client_ip;
}
[19:42:57 root@nginx /apps/nginx/conf.d]#curl pc.wang.org/main
hello world,main-->
admin # echo $name
10.0.0.86 # 把$remote_addr的值, 赋值给$client_ip, 然后打印
3.4 Nginx自定义访问日志
访问日志是记录客户端即用户的具体请求内容信息, 全局配置模块中的error_log是记录nignx服务器运行时的错误日志, 错误日志一般只有一个, 但是访问日志可以在不同的虚拟主机中定义多个
定义一个日志需要使用access_log指定的日志保存路径, 使用log_format指定日志的格式, 格式中定义要保存的具体日志内容
访问日志由ngx_http_log_module模块实现
注意: log_format只支持在http语句块中定义, 因此, 如果想实现不同虚拟主机使用不同的日志, 那么需要在http语句块中定义多个日志格式, 之后在server语句块中利用access_log去调用不同的格式, access_log支持在不同的语句块设置
3.4.1 自定义默认格式日志
定义日志格式 #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 logs/access.log main;
10.0.0.86 - - [17/Mar/2021:19:43:21 +0800] "GET /main HTTP/1.1" 200 57 "-" "curl/7.61.1"
如果想要保留日志的原始格式, 只是添加相应的日志内容, 则配置如下:
范例: 给pc和mobile两个站点, 定制不同的默认格式access日志
# 先在主配置文件的http语句块定义两个不同的日志格式
http {
include 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 logs/access.log main;
log_format pc_log '$remote_addr [$time_local] "$request" $status ' '"$http_user_agent"';
log_format mobile_log '$remote_addr [$time_local] "$request" ' '$status $body_bytes_sent';
# 在pc和mobile的子配置文件中, 定义访问日志存放路径, 并且调用响应的格式
server {
listen 80;
server_name pc.wang.org;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
access_log /data/nginx/logs/pc_access.log pc_log;
location / {
root /data/nginx/html/pc;
}
location /main {
index index.html;
default_type text/html;
echo "hello world,main-->";
set $name admin;
echo $name;
set $client_ip $remote_addr;
echo $client_ip;
}
}
server {
listen 80;
server_name m.wang.org;
root /data/nginx/html/mobile;
index index index.html;
access_log /data/nginx/logs/mobile_access.log mobile_log;
}
# 重新加载nginx验证
nginx -s reload
[20:19:35 root@nginx ~]#ll /data/nginx/logs/
total 8
-rw-r--r-- 1 root root 0 Mar 17 20:18 mobile_access.log
-rw-r--r-- 1 root root 73 Mar 17 20:18 pc_access.log
图片.png
图片.png
3.4.2 自定义JSON格式日志
Nginx的默认访问日志记录内容相对比较单一, 默认的格式也不方便后期做日志统计分析, 生成环境中通常将Nginx日志转换为JSON日志, 然后配置使用ELK做日志收集-统计和分析
- 范例: 将访问日志定义为JSON格式, 利用Python脚本提取信息
key:value
#定义JSON格式访问日志
log_format access_json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,' # 总的处理时间
'"upstreamtime":"$upstream_response_time",' # 后端应用服务器处理时间
'"upstreamhost":"$upstream_addr",'
'"http_host":"$host",'
'"uri":"$uri",'
'"xff":"$http_x_forwarded_for",'
'"referer":"$http_referer",'
'"tcp_xff":"$proxy_protocol_addr",'
'"http_user_agent":"$http_user_agent",'
'"status":"$status"}';
# 虚拟主机中调用JSON格式日志
access_log logs/access_json.log access_json;
[21:16:14 root@naruto ~]#tail /apps/nginx/logs/access_json.log -f
{"@timestamp":"2021-03-17T21:16:41+08:00","host":"172.18.152.251","clientip":"120.78.154.82","size":0,"responsetime":0.000,"upstreamtime":"0.000","upstreamhost":"127.0.0.1:9000","http_host":"120.78.154.82","uri":"/wp-cron.php","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"WordPress/5.3.2; http://120.78.154.82","status":"499"}
{"@timestamp":"2021-03-17T21:16:41+08:00","host":"172.18.152.251","clientip":"113.228.11.154","size":22702,"responsetime":0.069,"upstreamtime":"0.069","upstreamhost":"127.0.0.1:9000","http_host":"120.78.154.82","uri":"/index.php","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0","status":"200"}
- 利用python脚本提取返回状态码和所有的ip地址
[21:34:16 root@nginx ~]#vim log.py
#!/usr/bin/python3
status_200 = []
status_404 = []
with open("/apps/nginx/logs/access_json.log") as f:
for line in f.readlines():
line = eval(line)
if line.get("status") == "200":
status_200.append(line.get)
elif line.get("status") == "404":
status_404.append(line.get)
else:
print("状态码 ERROR")
print(line.get("clientip"))
f.close()
print("状态码200的有--:",len(status_200))
print("状态码404的有--:",len(status_404))
[21:34:15 root@nginx ~]#python3 log.py
10.0.0.86
10.0.0.1
10.0.0.1
状态码200的有--: 1
状态码404的有--: 2
- 补充: python2代码转换成python3代码工具
2to3
[21:34:38 root@nginx ~]#pip3 install 2to3
# 查看需要改动的代码
[21:35:19 root@nginx ~]#2to3 log.py
# 直接让工具修改
[21:35:19 root@nginx ~]#2to3 -w log.py
3.5 Nginx压缩功能
Nginx支持对指定类型的文件进行压缩, 然后再传输给客户端, 而且压缩还可以设置压缩比例, 压缩后的文件大小将比源文件显著变小, 这样有助于降低出口带宽的利用率, 降低企业的IT支出, 不会占用相应的CPU资源
Nginx对文件的压缩功能依赖于模块: ngx_http_gzip_module
- 配置指令
# 启用或禁用gzip压缩, 默认关闭
gzip on | off;
# 压缩比由低到高从1到9, 默认为1
gzip_comp_level level;
# 禁用IE6 gzip功能
gzip_disable "MSIE [1-6]\.";
# gzip压缩的最小文件, 小于设置值的文件将不会压缩
gzim_min_length 1k;
# 启用压缩功能时, 协议的最小版本, 默认为HTTP/1.1
gzip_http_version 1.0 | 1.1;
# 指定Nginx服务需要向服务器申请的缓存空间的个数和大小, 平台不同, 默认, 32 4k 或者 16 8k
gzip_buffers number size;
# 指明仅对哪些类型的资源执行压缩操作, 默认为gzip_types text/html, 不用显示指定, 否则出错
gzip_types mime-type ...;
# 如果启用压缩, 是否在响应报文头部插入"Vary: Accept-Encoding", 一般建议打开
gzip_vary on | off;
- 范例:
[22:41:19 root@nginx ~]#ll /var/log/messages -h
-rw-------. 1 root root 2.1M Mar 17 22:06 /var/log/messages
[22:42:34 root@nginx ~]#cp /var/log/messages /data/nginx/html/pc/messages
[22:47:21 root@nginx ~]#chmod +r /data/nginx/html/pc/messages # 日志文件默认只有root能读, 需要修改权限
mv /data/nginx/html/pc/messages /data/nginx/html/pc/m.txt # 修改成压缩支持的mime格式
# 把日志文件拷贝到pc.wang.org站点的家目录下, 测试对其压缩
# 压缩前
图片.png
# 修改pc.wang.org站点的配置文件
# gzip可以配置在server语句块
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/gif image/png;
gzip_vary on;
nginx -s reload
# 压缩后
图片.png
10.0.0.86 [17/Mar/2021:22:59:36 +0800] "GET /m.txt HTTP/1.1" 200 297417
3.6 Nginx实现https
Nginx的https功能基于模块ngx_http_ssl_module实现, 因此编译安装时, 需要添加参数,ngx_http_ssl_module, 开启ssl功能, --with-http_ssl_module
3.6.1 https配置参数
配置参数:
ssl on | off;
listen 443 ssl;
# 指向包含当前虚拟主机的证书和CA的两个证书信息的文件, 一般是crt文件(nginx证书一个有两个文件, 一个是服务器私钥, 一个是服务器的证书和CA的证书)
ssl_certificate /path/to/file;
# 当前虚拟主机使用的私钥文件, 一般是key文件
ssl_certificate_key /path/to/file;
# 支持ssl协议版本, 早期为ssl, 现在是tls, 默认为后三个
ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2]
# 配置ssl缓存:
off 关闭缓存
none 通知客户端支持ssl session cache, 但是实际不支持
builtin[:size] 使用OpenSSL内建缓存, 是每个worker进程私有的
[shared:name:size] 在各woker之间使用一个共享的缓存, 需要定义一个缓存名称和缓存空间大小, 一兆可以存储4000个会话信息, 多个虚拟主机可以使用相同的缓存名称
# 客户端连接可以复用ssl session cache中缓存的有效时长, 默认5m
ssl_session_timeout time;
3.6.2 自签名证书
[23:15:17 root@nginx ~]#cd /apps/nginx/
[23:24:54 root@nginx /apps/nginx]#mkdir certs
[23:24:56 root@nginx /apps/nginx]#cd certs
# 生成CA的自签名证书
[23:38:56 root@nginx /apps/nginx/certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
Generating a RSA private key
.............................................................................................++++
...........................................................................................++++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
# CA信息
Country Name (2 letter code) [XX]:CN # 所属国家
State or Province Name (full name) []:LN # 所属省份
Locality Name (eg, city) [Default City]:AS # 所属城市
Organization Name (eg, company) [Default Company Ltd]:wang.org # CA公司名称
Organizational Unit Name (eg, section) []:IT # 所属部门
Common Name (eg, your name or your server's hostname) []:ca.wang.org # CA域名
Email Address []:anshan88@qq.com # 邮箱
[23:39:21 root@nginx /apps/nginx/certs]#ll
total 8
-rw-r--r-- 1 root root 2090 Mar 17 23:39 ca.crt
-rw------- 1 root root 3272 Mar 17 23:38 ca.key
3.6.3 CA制作服务器私钥和证书申请文件
[23:41:01 root@nginx /apps/nginx/certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout pc.wang.org.key -out pc.wang.org.csr
Generating a RSA private key
........++++
.......................++++
writing new private key to 'pc.wang.org.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
# 网站信息
-----
Country Name (2 letter code) [XX]:CN # 网站所属国家
State or Province Name (full name) []:LN # 网站所属省份
Locality Name (eg, city) [Default City]:AS # 网站所属城市
Organization Name (eg, company) [Default Company Ltd]:wang.org # 网站所属公司
Organizational Unit Name (eg, section) []:IT # 部门
Common Name (eg, your name or your server's hostname) []:pc.wang.org # 网站域名
Email Address []:anshan88@qq.com # 邮箱
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
3.6.4 CA签发证书
[23:42:46 root@nginx /apps/nginx/certs]#openssl x509 -req -days 3650 -in pc.wang.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out pc.wang.org.crt
Signature ok
subject=C = CN, ST = LN, L = AS, O = wang.org, OU = IT, CN = pc.wang.org, emailAddress = anshan88@qq.com
Getting CA Private Key
[23:43:05 root@nginx /apps/nginx/certs]#ll
total 24
-rw-r--r-- 1 root root 2090 Mar 17 23:39 ca.crt
-rw------- 1 root root 3272 Mar 17 23:38 ca.key
-rw-r--r-- 1 root root 1968 Mar 17 23:42 pc.wang.org.crt
-rw-r--r-- 1 root root 1728 Mar 17 23:41 pc.wang.org.csr
-rw------- 1 root root 3272 Mar 17 23:41 pc.wang.org.key
3.6.5 验证证书内容
[23:43:05 root@nginx /apps/nginx/certs]#openssl x509 -in pc.wang.org.crt -noout -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
09:95:d7:63:66:c8:bd:70:6a:2b:a0:36:ad:61:33:c7:82:21:25:40
Signature Algorithm: sha256WithRSAEncryption
#证书发布者 Issuer: C = CN, ST = LN, L = AS, O = wang.org, OU = IT, CN = ca.wang.org, emailAddress = anshan88@qq.com
Validity
Not Before: Mar 17 15:42:54 2021 GMT
Not After : Mar 15 15:42:54 2031 GMT
#证书接收者 Subject: C = CN, ST = LN, L = AS, O = wang.org, OU = IT, CN = pc.wang.org, emailAddress = anshan88@qq.com
3.6.6 将ca的自签名证书和颁发给pc.wang.org的证书合并
apache的ssl证书有三个文件:
apache私钥
apache的证书
chain证书链, 指向上级ca信息
nginx的ssl证书有两个文件:
nginx私钥
nginx和ca的证书, 放在一个文件pem文件中
[00:16:09 root@nginx /apps/nginx/certs]#cat pc.wang.org.crt ca.crt > pc.wang.org.pem # 需要先cat服务器证书, 再cat上级CA证书, 否则会报错
3.6.7 配置nginx支持https
server {
listen 80;
listen 443 ssl;
server_name pc.wang.org;
ssl_certificate /apps/nginx/certs/pc_wang.org.pem;
ssl_certificate_key /apps/nginx/certs/pc.wang.org.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
error_page 404 /index.html;
error_log /data/nginx/logs/pc_wang_org_error.log;
access_log /data/nginx/logs/pc_access.log mobile_log;
location / {
root /data/nginx/html/pc;
}
}
~
[23:47:37 root@nginx /apps/nginx/certs]#nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[23:47:38 root@nginx /apps/nginx/certs]#nginx -s reload
图片.png
图片.png
图片.png
3.6.8 实现多域名https
Nginx支持基于多个IP实现多域名的功能, 并且还支持单个IP多域名的基础之上实现HTTPS, 其功能是基于Nginx的SNI(Server Name Indicatioin)功能实现, SNI是为了解决一个Nginx服务器内使用一个IP绑定多个域名和证书的功能, 其具体功能是客户端在连接到服务器建立SSL连接之前先发送要访问站点的域名(Hostname), 这样服务器再根据这个域名返回给客户端一个合适的证书
- 范例: SNI功能
[00:00:04 root@nginx /apps/nginx/certs]#nginx -V
nginx version: nginx/1.18.0
built by gcc 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC)
built with OpenSSL 1.1.1g FIPS 21 Apr 2020
TLS SNI support enabled # SNI功能启用
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/echo-nginx-module-master
# 给m.wang.org站点制作证书
[00:00:10 root@nginx /apps/nginx/certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout m.wang.org.key -out m.wang.org.csr
Generating a RSA private key
...............................................................................................................................................................................++++
..........++++
writing new private key to 'm.wang.org.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:LN
Locality Name (eg, city) [Default City]:AS
Organization Name (eg, company) [Default Company Ltd]:wang.org
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:m.wang.org
Email Address []:anshan88@qq.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[00:02:15 root@nginx /apps/nginx/certs]#openssl x509 -req -days 3650 -in m.wang.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out m.wang.org.crt
Signature ok
subject=C = CN, ST = LN, L = AS, O = wang.org, OU = IT, CN = m.wang.org, emailAddress = anshan88@qq.com
Getting CA Private Key
[00:23:53 root@nginx /apps/nginx/certs]#ll
total 40
-rw-r--r-- 1 root root 2090 Mar 17 23:39 ca.crt
-rw------- 1 root root 3272 Mar 17 23:38 ca.key
-rw-r--r-- 1 root root 2090 Mar 18 00:13 m.wang.org.crt
-rw-r--r-- 1 root root 1724 Mar 18 00:02 m.wang.org.csr
-rw------- 1 root root 3272 Mar 18 00:01 m.wang.org.key
-rw-r--r-- 1 root root 1968 Mar 17 23:42 pc.wang.org.crt
-rw-r--r-- 1 root root 1728 Mar 17 23:41 pc.wang.org.csr
-rw------- 1 root root 3272 Mar 17 23:41 pc.wang.org.key
-rw-r--r-- 1 root root 4058 Mar 18 00:21 pc.wang.org.pem
[00:23:55 root@nginx /apps/nginx/certs]#cat m.wang.org.crt ca.crt > m.wang.org.pem
[00:24:25 root@nginx /apps/nginx/certs]#ll
total 48
-rw-r--r-- 1 root root 2090 Mar 17 23:39 ca.crt
-rw------- 1 root root 3272 Mar 17 23:38 ca.key
-rw-r--r-- 1 root root 2090 Mar 18 00:13 m.wang.org.crt
-rw-r--r-- 1 root root 1724 Mar 18 00:02 m.wang.org.csr
-rw------- 1 root root 3272 Mar 18 00:01 m.wang.org.key
-rw-r--r-- 1 root root 4180 Mar 18 00:24 m.wang.org.pem
-rw-r--r-- 1 root root 1968 Mar 17 23:42 pc.wang.org.crt
-rw-r--r-- 1 root root 1728 Mar 17 23:41 pc.wang.org.csr
-rw------- 1 root root 3272 Mar 17 23:41 pc.wang.org.key
-rw-r--r-- 1 root root 4058 Mar 18 00:21 pc.wang.org.pem
# 配置mobile站点
server {
listen 80;
server_name m.wang.org;
listen 443 ssl;
ssl_certificate /apps/nginx/certs/m.wang.org.pem;
ssl_certificate_key /apps/nginx/certs/m.wang.org.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
root /data/nginx/html/mobile;
index index index.html;
access_log /data/nginx/logs/mobile_access.log mobile_log;
}
[00:39:29 root@nginx ~]#nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[00:39:31 root@nginx ~]#nginx -s reload
图片.png
图片.png
注意: 使用了SSL证书后, 需要全站的连接都是HTTPS, 否则证书会无效, 浏览器访问网站时仍然会显示不安全
3.6.9 实现HSTS
- 配置文件
server {
listen 443 ssl;
server_name pc.wang.org
add_header Strict-Transport-Security "max-age=3153600; includeSubDomains" always;
localtion / {
....
}
}
- 范例: 在pc.wang.org站点开启HSTS
[01:01:42 root@nginx /data/nginx/html/pc/images]#vim /apps/nginx/conf.d/pc.conf
# 添加在server语句块
add_header Strict-Transport-Security "max-age=3153600; includeSubDomains" always;
[01:01:42 root@nginx /data/nginx/html/pc/images]#vim /apps/nginx/conf.d/pc.conf
[01:05:08 root@nginx /data/nginx/html/pc/images]#nginx -s reload
- 验证
[01:05:35 root@nginx /data/nginx/html/pc/images]#curl -ikL https://pc.wang.org
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Wed, 17 Mar 2021 17:05:55 GMT
Content-Type: text/html
Content-Length: 11
Last-Modified: Mon, 15 Mar 2021 12:57:27 GMT
Connection: keep-alive
ETag: "604f59b7-b"
Strict-Transport-Security: max-age=3153600; includeSubDomains
Accept-Ranges: bytes
pc website
3.7 关于favicon.so
favicon.so文件是浏览器打开网站时, 显示的小图标, 当客户端使用浏览器访问页面时, 浏览器会自动主动发起请求获取页面的favicon.ico文件, 但是当浏览器请求的favicon.ico文件不存在时, 服务器会记录404日志, 而且浏览器也会显示404报错
方法1: 服务器不记录访问日志
lcation = /favicon.ico {
log_not_found off;
access_log off;
}
方法2: 将图标保存到指定目录访问
location = /favicon.ico {
root /data/nginx/html/pc/images;
expires 365d;
}
[00:58:18 root@nginx /data/nginx/html/pc]#mkdir images
[00:58:22 root@nginx /data/nginx/html/pc]#cd images/
[00:58:54 root@nginx /data/nginx/html/pc/images]#ls
favicon.ico
10.0.0.86 - - [17/Mar/2021:20:18:44 +0800] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1"
3.8 升级OpenSSL版本
# 当前OpenSSL版本
built with OpenSSL 1.1.1g FIPS 21 Apr 2020
# 准备升级到1.1.1h
# 当前的nginx二进制文件
[01:08:18 root@nginx ~]#ll /apps/nginx/sbin/
total 22768
-rwxr-xr-x 1 root root 8126344 Mar 17 18:21 nginx
-rwxr-xr-x 1 nginx nginx 7591104 Mar 15 15:22 nginx.bak
-rwxr-xr-x 1 nginx nginx 7591104 Mar 15 15:22 nginx.old
# 下载最新版本OpenSSL源码包
[01:08:22 root@nginx ~]#cd /usr/local/src
[01:09:19 root@nginx /usr/local/src]#wget https://www.openssl.org/source/openssl-1.1.1h.tar.gz
[01:10:57 root@nginx /usr/local/src]#tar xvf openssl-1.1.1h.tar.gz
[01:14:54 root@nginx /usr/local/src/nginx-1.18.0]#cd nginx-1.18.0/
[01:14:54 root@nginx /usr/local/src/nginx-1.18.0]#./configure --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/echo-nginx-module-master --with-openssl=/usr/local/src/openssl-1.1.1h
[01:15:40 root@nginx /usr/local/src/nginx-1.18.0]#make && make install
# 编译后
[01:20:13 root@nginx /apps/nginx/sbin]#ll
total 26672
-rwxr-xr-x 1 root root 11587608 Mar 18 01:19 nginx # 新的二进制文件
-rwxr-xr-x 1 nginx nginx 7591104 Mar 15 15:22 nginx.bak
-rwxr-xr-x 1 root root 8126344 Mar 17 18:21 nginx.old
# 无需重启nginx, 即可生效
[01:20:13 root@nginx /apps/nginx/sbin]#nginx -V
nginx version: nginx/1.18.0
built by gcc 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC)
built with OpenSSL 1.1.1h 22 Sep 2020
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/echo-nginx-module-master --with-openssl=/usr/local/src/openssl-1.1.1h