深入解析Nginx常见模块2

内容分享2天前发布
2 0 0

在Web服务器和反向代理服务器领域,Nginx凭借其高性能、稳定性和丰富的功能获得了广泛的应用。本文将介绍一些Nginx中常见的模块,帮助你更好地理解和使用它们。
点击这里跳转到上一篇文章https://blog.csdn.net/weixin_43663196/article/details/151015697?spm=1001.2014.3001.5501

Nginx常见模块

Nginx 状态页

基于nginx 模块 ngx_http_stub_status_module 实现,在编译安装nginx的时候需要添加编译参数 –with-http_stub_status_module,否则配置完成之后监测会是提示语法错误 注意:状态页显示的是整个服务器的状态,而非虚拟主机的状态
指令


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

Syntax: stub_status;
Default:   —
Context:   server, location

示例


#配置示例:
location  /nginx_status {
    stub_status;
    auth_basic       "auth login";
    auth_basic_user_file  /apps/nginx/conf/.htpasswd;
    allow 192.168.0.0/16;
    allow 127.0.0.1;
    deny all;
    access_log off;
  }

#状态页用于输出nginx的基本状态信息:
#输出信息示例:
Active connections: 2 
server accepts handled requests
5 5 22 
#上面三个数字分别对应accepts,handled,requests三个值
Reading: 0 Writing: 1 Waiting: 1

Active connections: #当前处于活动状态的客户端连接数,包括连接等待空闲连接数=reading+writing+waiting
accepts:#统计总值,Nginx自启动后已经接受的客户端请求连接的总数。
handled:#统计总值,Nginx自启动后已经处理完成的客户端请求连接总数,通常等于accepts,除非有因worker_connections限制等被拒绝的失败连接,即失败连接数=accepts-handled
requests:#统计总值,Nginx自启动后客户端发来的总的请求数。因为长连接的原因此值大于上面的accept数
Reading:#当前状态,正在读取客户端请求报文首部的连接的连接数,数值越大,说明排队现象严重,性能不足
Writing:#当前状态,正在向客户端发送响应报文过程中的连接数,数值越大,说明访问量很大
Waiting:#当前状态,正在等待客户端发出请求的空闲连接数,开启keep-alive时,Waiting+reading+writing=active connections

分析当前网站访问量


[root@ubuntu2404 ~]#curl -s http://www.caoge.com/nginx_status |awk -F: 'NR==1{print $NF}'
1 
[root@ubuntu2404 ~]#curl -s http://www.caoge.com/nginx_status 2> /dev/null |awk '/Reading/{print $2,$4,$6}'
0 1 0

Nginx 第三方模块

第三模块是对nginx 的功能扩展,第三方模块需要在编译安装Nginx 的时候使用参数–add-module=PATH指定路径添加,有的模块是由公司的开发人员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到github进行开源的模块,nginx的第三方模块需要从源码重新编译进行支持。

nginx-module-vts 模块实现流量监控


https://github.com/vozlt/nginx-module-vts

示例


[root@rocky9 app]# cd /usr/local/src/
[root@rocky9 src]# git clone  https://github.com/vozlt/nginx-module-vts.git
Cloning into 'nginx-module-vts'...
remote: Enumerating objects: 1058, done.
remote: Counting objects: 100% (258/258), done.
remote: Compressing objects: 100% (88/88), done.
remote: Total 1058 (delta 179), reused 196 (delta 162), pack-reused 800 (from 1)
Receiving objects: 100% (1058/1058), 1.16 MiB | 1.18 MiB/s, done.
Resolving deltas: 100% (702/702), done.
[root@rocky9 src]# ls
nginx-1.26.2  nginx-1.26.2.tar.gz  nginx-module-vts
[root@rocky9 src]# cd nginx-1.26.2
[root@rocky9 nginx-1.26.2]# ./configure --prefix=/app/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/nginx-module-vts
[root@rocky9 nginx-1.26.2]# make && make install
[root@rocky9 app]# vim nginx/conf/nginx.conf
http {
    vhost_traffic_status_zone;
    server {
        listen       80;
        server_name  localhost;
        charset utf-8;
        location / {
            root   /app/nginx/html;
            index  index.html index.htm;
        }
         location /status {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format html;            
        }
[root@rocky9 app]# nginx

深入解析Nginx常见模块2

echo 模块实现信息显示

开源的echo模块可以用来打印信息,变量等


https://github.com/openresty/echo-nginx-module

示例


[root@rocky9 app]# systemctl stop nginx
[root@rocky9 app]# cd /usr/local/src/

[root@rocky9 nginx-1.26.2]# git clone https://github.com/openresty/echo-nginx-module.git

[root@rocky9 nginx-1.26.2]# cd nginx-1.26.2/

[root@rocky9 nginx-1.26.2]# ./configure --prefix=/app/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  
--add-module=/usr/local/src/nginx-module-vts

[root@rocky9 nginx-1.26.2]# make && make install 

[root@rocky9 nginx-1.26.2]# /app/nginx/sbin/nginx -t
nginx: the configuration file /app/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /app/nginx/conf/nginx.conf test is successfull

#编译新模块需要重启nginx才能访问测试,不支持reload
[root@rocky9 nginx-1.26.2]# systemctl restart nginx
[root@rocky9 app]# vim m.caoge.com.conf
server {
    server_name m.caoge.com;
    location /  {
        root /data/nginx;
        index index.html;
        echo "hello word,main";
        echo $remote_addr;
        echo_reset_timer;
        echo "took $echo_timer_elapsed sec for total";
    }
 }
[root@rocky9 app]# nginx -t
nginx: the configuration file /app/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /app/nginx/conf/nginx.conf test is successful
[root@rocky9 app]# nginx -s reload

[root@centos7 ~]# curl m.caoge.com
hello word,main
192.168.101.11
took 0.000 sec for total

Nginx 变量使用

nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用变量可以分为内置变量和自定义变量。内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值

内置变量
官方文档


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

常用内置变量


$remote_addr; 
#存放了客户端的地址,注意是客户端的公网IP

$proxy_add_x_forwarded_for
#此变量表示将客户端IP追加请求报文中X-Forwarded-For首部字段,多个IP之间用逗号分隔,如果请求中没有X-Forwarded-For,就使用$remote_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://www.wang.org/main/index.do?id=20190221&partner=search
#返回结果为: id=20190221&partner=search

$is_args
#如果有参数为? 否则为空
“?” if a request line has arguments, or an empty string otherwise

$document_root; 
#保存了针对当前资源的请求的系统根目录,例如:/apps/nginx/html。

$document_uri;
#保存了当前请求中不包含参数的URI,注意是不包含请求的指令,比如:http://www.caoge.org/main/index.do?id=20190221&partner=search会被定义为/main/index.do 
#返回结果为:/main/index.do

$host; 
#存放了请求的host名称

limit_rate 10240;
echo $limit_rate;
#如果nginx服务器使用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

$request_uri;
#包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args,例如:/main/index.do?id=20190221&partner=search 

$scheme;
#请求的协议,例如:http,https,ftp等

$server_protocol;
#保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等

$server_addr;
#保存了服务器的IP地址

$server_name;
#请求的服务器的主机名

$server_port;
#请求的服务器的端口号

$http_user_agent;
#客户端浏览器的详细信息

$http_cookie;
#客户端的所有cookie信息

$cookie_<name>
#name为任意请求报文首部字部cookie的key名

$http_<name>
#name为任意请求报文首部字段,表示记录请求报文的首部字段,ame的对应的首部字段名需要为小写,如果有横线需要替换为下划线
arbitrary request header field; the last part of a variable name is the field 
name converted to lower case with dashes replaced by underscores #用下划线代替横线

#示例: 
echo $http_user_agent; 
echo $http_host;

$sent_http_<name>
#name为响应报文的首部字段,name的对应的首部字段名需要为小写,如果有横线需要替换为下划线,此变量有问题
echo $sent_http_server;

$arg_<name>
#此变量存放了URL中的指定参数,name为请求url中指定的参数
echo $arg_id;

$uri;
#和$document_uri相同

示例


[root@rocky9 app]# vim m.caoge.com.conf 
server {
    server_name m.caoge.com;
    location /  {
        root /data/nginx;
        index index.html;
        echo "hello word,main";
        echo $remote_addr;
        echo_reset_timer;
        echo $host;
        echo $remote_user;
        echo $remote_port;
        echo $request_uri;
        echo $scheme;
        echo $server_addr;
        echo $server_port;
        echo $http_cookie;
        echo $http_user_agent;
        echo $document_root;
        echo $server_name;
        echo "took $echo_timer_elapsed sec for total";
    }
 }
[root@centos7 ~]# curl m.caoge.com/dnaoewnoefnowenoangoangname=wang
hello word,main
192.168.101.11
m.caoge.com

38414
/dnaoewnoefnowenoangoangname=wang
http
192.168.101.5
80

curl/7.29.0
/data/nginx
m.caoge.com
took 0.000 sec for total

[root@rocky9 app]# vim m.caoge.com.conf 
server {
    server_name m.caoge.com;
    location /  {
        root /data/nginx;
        index index.html;
        echo "hello word,main";
        echo $remote_addr;
        echo $proxy_add_x_forwarded_for;
        echo $args;
        echo $cookie_key1;
        echo $host;
        echo $remote_user;
        echo $remote_port;
        echo $request_uri;
        echo $scheme;
        echo $server_addr;
        echo $server_port;
        echo $http_cookie;
        echo $http_user_agent;
        echo $document_root;
        echo $server_name;
        echo "took $echo_timer_elapsed sec for total";
    }
 }

[root@centos7 ~]# curl m.caoge.com/dnaoewnoefnowenoangoangname=wang 
hello word,main
192.168.101.11
192.168.101.11

m.caoge.com

38420
/dnaoewnoefnowenoangoangname=wang
http
192.168.101.5
80

curl/7.29.0
/data/nginx
m.caoge.com
took 0.000 sec for total

自定义变量
假如需要自定义变量名称和值,使用指令 set $variable value
语法格式


Syntax: set $variable value;
Default:  —
Context:  server, location, if

示例


[root@rocky9 app]# vim m.caoge.com.conf
server {
    server_name m.caoge.com;
    set $name caoge;
    set $my_port $server_port;
    location /  {
        root /data/nginx;
        index index.html;
        echo "hello word,main";
        echo $remote_addr;
        echo $name;
        echo "$my_port:$server_port";
        echo $proxy_add_x_forwarded_for;
        echo $args;
        echo $cookie_key1;
        echo $host;
        echo "took $echo_timer_elapsed sec for total";
    }
 }
[root@centos7 ~]# curl m.caoge.com/
hello word,main
192.168.101.11
caoge
80:80
192.168.101.11

m.caoge.com
took 0.000 sec for total

Nginx 自定义访问日志

访问日志是记录客户端即用户的具体请求内容信息,而在全局配置模块中的error_log是记录nginx服务器运行时的日志保存路径和记录日志的level,因此两者是不同的,而且Nginx的错误日志一般只有一个,但是访问日志可以在不同server中定义多个,定义一个日志需要使用access_log指定日志的保存路径,使用log_format指定日志的格式,格式中定义要保存的具体日志内容。
访问日志由 ngx_http_log_module模块实现。

官方帮助文档


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

语法格式


Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
          access_log off; #关闭访问日志,比如在反向代理上可以关闭日志功能
Default:  access_log logs/access.log combined;
Context:  http, server, location, if in location, limit_except

日志格式的常见变量


$remote_addr # 记录客户端IP地址
$remote_user # 记录客户端用户名
$time_local # 记录通用的本地时间
$time_iso8601 # 记录ISO8601标准格式下的本地时间
$request # 记录请求的方法以及请求的http协议
$status # 记录请求状态码(用于定位错误信息)
$body_bytes_sent # 发送给客户端的资源字节数,不包括响应头的大小
$bytes_sent # 发送给客户端的总字节数$msec # 日志写入时间。单位为秒,精度是毫秒。
$http_referer # 记录从哪个页面链接访问过来的
$http_user_agent # 记录客户端浏览器相关信息
$http_x_forwarded_for #记录客户端IP地址
$request_length # 请求的长度(包括请求行,请求头和请求正文)。
$request_time # 请求花费的时间,单位为秒,精度毫秒
# 注:如果Nginx位于负载均衡器,nginx反向代理之后,web服务器无法直接获取到客户端真实的IP地址。
# $remote_addr获取的是反向代理的IP地址。 反向代理服务器在转发请求的http头信息中,
# 增加X-Forwarded-For信息,用来记录客户端IP地址和客户端请求的服务器地址

默认日志格式


#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;

自定义默认格式日志
如果是要保留日志的源格式,只是添加相应的日志内容,则配置如下


#注意:此指令只支持http块,不支持server块
log_format  access_log_format  '$remote_addr - $remote_user [$time_local] 
               "$request" '
               '$status $body_bytes_sent "$http_referer" '
               '"$http_user_agent" "$http_x_forwarded_for"'
               '$server_name:$server_port';

#注意:此指令一定要在放在log_format命令后
access_log  logs/access.log   access_log_format;

#重启nginx并访问测试日志格式


[root@rocky9 app]# vim m.caoge.com.conf 
log_format test_log '$remote_addr - $remote_user [$time_local]  "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"'
                     '$server_name:$server_port';
server {
    server_name m.caoge.com;
    access_log  logs/access.log test_log;
    location /  {
        root /data/nginx;
        index index.html;
    }
 }

[root@centos7 ~]# curl m.caoge.com/
pc web 
[root@rocky9 nginx]# tail -f /app/nginx/logs/access.log 
192.168.101.11 - - [01/Dec/2024:16:11:01 +0800]  "GET / HTTP/1.1" 200 8 "-" "curl/7.29.0" "-"m.caoge.com:80
192.168.101.11 - - [01/Dec/2024:16:11:03 +0800]  "GET / HTTP/1.1" 200 8 "-" "curl/7.29.0" "-"m.caoge.com:80
192.168.101.11 - - [01/Dec/2024:16:19:01 +0800]  "GET / HTTP/1.1" 200 8 "-" "curl/7.29.0" "-"m.caoge.com:80

自定义 json 格式日志
Nginx 的默认访问日志记录内容相对比较单一,默认的格式也不方便后期做日志统计分析,生产环境中通常将nginx日志转换为json日志,然后配合使用ELK做日志收集,统计和分析。


 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"}';
  access_log  /apps/nginx/logs/access_json.log  access_json;

#重启Nginx并访问测试日志格式,参考链接:http://json.cn/
[root@rocky9 app]# vim m.caoge.com.conf 
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"}';
server {
    server_name m.caoge.com;
    access_log  logs/access_json.log access_json;
    location /  {
        root /data/nginx;
        index index.html;
    }
 }
[root@ubuntu2404 data]#systemctl restart nginx.service 

[root@ubuntu2404 ~]#curl www.caoge.com
www.caoge.com

[root@ubuntu2404 ~]#tail /apps/nginx/logs/access_json.log -f
{"@timestamp":"2025-07-03T23:12:43+08:00","host":"192.168.1.50","clientip":"192.168.1.60","size":14,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.caoge.com","uri":"//index.html","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"curl/8.5.0","status":"200"}

[root@ubuntu2404 ~]#echo '{"@timestamp":"2025-07-03T23:12:43+08:00","host":"192.168.1.50","clientip":"192.168.1.60","size":14,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.caoge.com","uri":"//index.html","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"curl/8.5.0","status":"200"}'|jq
{
  "@timestamp": "2025-07-03T23:12:43+08:00",
  "host": "192.168.1.50",
  "clientip": "192.168.1.60",
  "size": 14,
  "responsetime": 0.000,
  "upstreamtime": "-",
  "upstreamhost": "-",
  "http_host": "www.caoge.com",
  "uri": "//index.html",
  "xff": "-",
  "referer": "-",
  "tcp_xff": "-",
  "http_user_agent": "curl/8.5.0",
  "status": "200"
}

不记录访问日志
一个网站会包含很多元素,尤其是有大量的images、js、css等静态资源。这样的请求可以不用记录日志


#请求 favicon.ico 时,不记录日志
location /favicon.ico {
  access_log off;
  return 200;
}

#当有人访问gif、png等资源时,将日志丢入空
location ~* .*.(gif|jpg|png|css|js)$ {
    access_log /dev/null;
}

关于 favicon.ico

favicon.ico文件是浏览器收藏网址时显示的图标,当客户端使用浏览器问页面时,浏览器会自己主动发起请求获取页面的favicon.ico文件,但是当浏览器请求的favicon.ico文件不存在时,服务器会记录404日志,而且浏览器也会显示404报错。
解决办法


#方法一:服务器不记录访问日志:
location = /favicon.ico {
    log_not_found off;
    access_log off;
}

#方法二:将图标保存到指定目录访问:
#location ~ ^/favicon.ico$ {
 location = /favicon.ico {
     root   /data/nginx/html/pc/images;
     expires 365d;    #设置文件过期时间
     access_log off;
}

Nginx 压缩功能

Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,这样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相应的CPU资源。
Nginx对文件的压缩功能是依赖于模块ngx_http_gzip_module,默认是内置模块。
官方文档: https://nginx.org/en/docs/http/ngx_http_gzip_module.html
配置指令如下


#启用或禁用gzip压缩,默认关闭
gzip on | off; 

#压缩比由低到高从1到9,默认为1
gzip_comp_level level;

#禁用IE6 gzip功能
gzip_disable "MSIE [1-6]."; 

#gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_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; 

#预压缩,即直接从磁盘找到对应文件的gz后缀的式的压缩文件返回给用户,无需消耗服务器CPU
#注意: 来自于ngx_http_gzip_static_module模块
gzip_static on | off;

示例


[root@rocky9 app]# vim nginx/conf/nginx.conf
        location /pc {
            root /app/nginx/html;
            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;
}
[root@rocky9 nginx]# cat /app/nginx/logs/access_json.log >/app/nginx/html/pc/test1.html
[root@rocky9 nginx]# nginx -s reload
[root@centos7 ~]# curl --head --compressed http://192.168.101.5/test.html
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 01 Dec 2024 12:40:09 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 474140
Last-Modified: Sun, 01 Dec 2024 12:29:11 GMT
Connection: keep-alive
ETag: "674c5697-73c1c"
Accept-Ranges: bytes

https 加密

Web网站的登录页面通常都会使用https加密传输的,加密数据以保障数据的安全,HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议,HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。
深入解析Nginx常见模块2


https 实现过程如下:
1.客户端发起HTTPS请求:
客户端访问某个web端的https地址,一般都是443端口
2.服务端的配置:
采用https协议的服务器必须要有一套证书,可以通过一些组织申请,也可以自己制作,目前国内很多网站都
自己做的,当你访问一个网站的时候提示证书不可信任就表示证书是自己做的,证书就是一个公钥和私钥匙,
就像一把锁和钥匙,正常情况下只有你的钥匙可以打开你的锁,你可以把这个送给别人让他锁住一个箱子,里
面放满了钱或秘密,别人不知道里面放了什么而且别人也打不开,只有你的钥匙是可以打开的。
3.传送证书:
服务端给客户端传递证书,其实就是公钥,里面包含了很多信息,例如证书得到颁发机构、过期时间等等。
4.客户端解析证书:
这部分工作是有客户端完成的,首先回验证公钥的有效性,比如颁发机构、过期时间等等,如果发现异常则会
弹出一个警告框提示证书可能存在问题,如果证书没有问题就生成一个随机值,然后用证书对该随机值进行加
密,就像2步骤所说把随机值锁起来,不让别人看到。
5.传送4步骤的加密数据:
就是将用证书加密后的随机值传递给服务器,目的就是为了让服务器得到这个随机值,以后客户端和服务端的
通信就可以通过这个随机值进行加密解密了。
6.服务端解密信息:
服务端用私钥解密5步骤加密后的随机值之后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进
行对称加密,对称加密就是将信息和私钥通过算法混合在一起,这样除非你知道私钥,不然是无法获取其内部
的内容,而正好客户端和服务端都知道这个私钥,所以只要机密算法够复杂就可以保证数据的安全性。
7.传输加密后的信息:
服务端将用私钥加密后的数据传递给客户端,在客户端可以被还原出原数据内容。
8.客户端解密信息:
客户端用之前生成的私钥获解密服务端传递过来的数据,由于数据一直是加密的,因此即使第三方获取到数据
也无法知道其详细内容。

https 配置参数
nginx 的https 功能基于模块ngx_http_ssl_module实现,因此如果是编译安装的nginx要使用参数 ngx_http_ssl_module开启ssl功能,但是作为nginx的核心功能,yum安装的nginx默认就是开启的,编译安装的nginx需要指定编译参数–with-http_ssl_module开启。
官方文档


https://nginx.org/en/docs/http/ngx_http_ssl_module.html

配置参数如下


ssl on | off;   
#为指定的虚拟主机配置是否启用ssl功能,此功能在1.15.0废弃,使用listen [ssl]替代
listen 443 ssl http2;

ssl_certificate /path/to/file;
#指向包含当前虚拟主机和CA的两个证书信息的文件,一般是crt文件

ssl_certificate_key /path/to/file;
#当前虚拟主机使用的私钥文件,一般是key文件

ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];  
#支持ssl协议版本,早期为ssl现在是TLS,默认为后三个,最新的浏览器已经不再支持TLS1.0和TLS1.1

ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
#配置ssl缓存
  off: #关闭缓存
  none:  #通知客户端支持ssl session cache,但实际不支持
  builtin[:size]:#使用OpenSSL内建缓存,为每worker进程私有,使用此内置缓存可能会导致内存碎片
  [shared:name:size]:#在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,1M可以存储4000个会话信息,多个虚拟主机可以使用相同的缓存名称

ssl_session_timeout time; #客户端连接可以复用ssl session cache中缓存的有效时长,默认5分钟

官方性能优化


https://nginx.org/en/docs/http/ngx_http_ssl_module.html
 
To reduce the processor load it is recommended to
set the number of worker processes equal to the number of processors,
enable keep-alive connections,enable the shared session cache,disable the built-in session cache,
and possibly increase the session lifetime (by default, 5 minutes):

worker_processes auto;

http {
    ...
    
    server {
        listen     443 ssl http2;          
        keepalive_timeout   70;

        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
        ssl_certificate     /usr/local/nginx/conf/cert.pem;
        ssl_certificate_key /usr/local/nginx/conf/cert.key;
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 10m;
        
        ...    
    }

自签名证书


#自签名CA证书
[root@ubuntu2404 ~]#cd /data/
[root@ubuntu2404 data]#mkdir certs
[root@ubuntu2404 data]#cd certs
[root@ubuntu2404 certs]#openssl req  -newkey rsa:4096 -nodes -sha256 -keyout ca.key  -x509 -days 3650 -out ca.crt
......+...+.....+...+.......+..+.+.......................+.+...........+.......+..+.+...+..+.............+..+.........+....+.....+.+........+.+..+..........+..+.......+......+...+..+.........+.........+....+........+...+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+.......+.....+....+..............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+..........................+.+........+.+.....+....+..+.........+.........+..........+.....+......+.+............+.....+.+.....+.........+.+..+...+.+..............+...................+.....+.......+.....+......+.......+...+.........+........+...+..........+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.+............+..+.+.....+...+......+.+...+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+..+................+..+.+............+..+............+.+........+.......+..+...+.........+....+.....+.+...+.....+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...................+..+......+............+....+.....+.+.....+.........+...............+.............+..+...+................+..+...+.+....................+....+...........+...+.............+...+.....+......+.+............+........+.......+...+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
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) [AU]:CN #国家代码
State or Province Name (full name) [Some-State]:Bejing   #省份
Locality Name (eg, city) []:Bejing  #城市
Organization Name (eg, company) [Internet Widgits Pty Ltd]:caoge  #公司名称
Organizational Unit Name (eg, section) []:it   #部门
Common Name (e.g. server FQDN or YOUR name) []:caoge.com #通用名称
Email Address []:  #邮箱

[root@ubuntu2404 certs]#ls -l
total 8
-rw-r--r-- 1 root root 2013 Jul  4 09:28 ca.crt
-rw------- 1 root root 3268 Jul  4 09:27 ca.key

#自制key和csr文件
[root@ubuntu2404 certs]#openssl req  -newkey rsa:4096 -nodes -sha256 -keyout www.caoge.com.key  -out  www.caoge.com.csr
.+.......+.....+....+...........+...+...+....+...+.....+.+......+...........+...+.......+...+.....+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+.......+......+...+.........+......+.....+.......+..+.......+......+..................+..+.......+......+..............+.......+........+.+..+.......+...+.................+.......+...+...+.....+....+......+.....+...+.........+.+.........+......+......+...+.....+.+.....................+.....+.+............+...........+......+....+.........+...+..................+......+..............+......+....+..............+...+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.+...+....+..+..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*......+.+...+...+........+....+.................+....+..+....+......+.....+.......+...+..+.......+...........+.........+.+.....+...+.+...+........+...............+....+.........+..+...+....+......+.........+...+........+.......+..+......+............+...+............+..........+...+..+....+...............+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....................+....+.....+...+......+.+...+..................+..+.+..+...........................+.+......+.....+...............+....+..+.......+...+..............+.+........+......+......+.............+..+....+.........+.....+.+..............+......+....+......+......+..+................+..+.......+..+..........+...+...........+.+........+............+.+...+.....+.........+............+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
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) [AU]:CN
State or Province Name (full name) [Some-State]:Beijing
Locality Name (eg, city) []:Beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:caoge.com
Organizational Unit Name (eg, section) []:caoge.com
Common Name (e.g. server FQDN or YOUR name) []:www.caoge.com
Email Address []:123@123

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@ubuntu2404 certs]#ls -l
total 16
-rw-r--r-- 1 root root 2013 Jul  4 09:28 ca.crt
-rw------- 1 root root 3268 Jul  4 09:27 ca.key
-rw-r--r-- 1 root root 1744 Jul  4 09:34 www.caoge.com.csr
-rw------- 1 root root 3268 Jul  4 09:32 www.caoge.com.key

#签发证书
[root@ubuntu2404 certs]#openssl x509 -in www.caoge.com.crt  -noout -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            1e:4a:a3:d9:49:cf:f9:13:45:58:a5:19:3b:bf:f3:82:24:e7:69:0e
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = Bejing, L = Bejing, O = caoge, OU = it, CN = caoge.com
        Validity
            Not Before: Jul  4 01:36:27 2025 GMT
            Not After : Jul  2 01:36:27 2035 GMT
        Subject: C = CN, ST = Beijing, L = Beijing, O = caoge.com, OU = caoge.com, CN = www.caoge.com, emailAddress = 123@123
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)

#合并CA和服务器证书成一个文件,注意服务器证书必须在前,ca证书在后,否则会出错
[root@ubuntu2404 certs]#cat www.caoge.com.crt ca.crt >www.caoge.com.pem

https配置


server{
    listen 80;
    listen 443 ssl;
    server_name www.caoge.com;
    keepalive_timeout 20 100;
    ssl_certificate /data/certs/www.caoge.com.pem;
    ssl_certificate_key /data/certs/www.caoge.com.key;
    ssl_session_cache shared:sslcache:20m;
    ssl_session_timeout 10m;
    location / {
      	root /opt/;
        log_not_found off;
      	access_log off;
}
}

实现多域名 https
Nginx 支持基于单个IP实现多域名的功能,并且还支持单IP多域名的基础之上实现HTTPS,其实是基于 Nginx的 SNI(Server Name Indication)功能实现,SNI是为了解决一个Nginx服务器内使用一个IP绑定多个域名和证书的功能,其具体功能是客户端在连接到服务器建立SSL链接之前先发送要访问站点的域名 (Hostname),这样服务器再根据这个域名返回给客户端一个合适的证书。
SNI功能


[root@rocky9 app]# nginx -V
nginx version: nginx/1.26.2
built by gcc 11.5.0 20240719 (Red Hat 11.5.0-2) (GCC) 
built with OpenSSL 3.2.2 4 Jun 2024
TLS SNI support enabled
configure arguments: --prefix=/app/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 --add-module=/usr/local/src/nginx-module-vts

示例


server{
    listen 80 default_server;
    server_name  www.caoge.com;
    rewrite ^(.*)$ https://$server_name$1 permanent;
}
server{
    listen 443 ssl ;
    server_name www.caoge.com;
    keepalive_timeout 20 100;
    ssl_certificate /data/certs/www.caoge.com.pem;
    ssl_certificate_key /data/certs/www.caoge.com.key;
    ssl_session_cache shared:sslcache:20m;
    ssl_session_timeout 10m;
    location / {
      	root /opt/;
        log_not_found off;
      	access_log off;
}

实现 HSTS
官方文档


https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

注意:配置rewrite才能实现http跳转到https


[root@ubuntu2404 data]#cat www.cao.com.conf 
server {    
     listen 80;
     listen 443 ssl;
     server_name  www.cao.com;
     ssl_certificate /data/certs/www.caoge.com.pem;
     ssl_certificate_key /data/certs/www.caoge.com.key;
     ssl_session_cache shared:sslcache:20m;
     ssl_session_timeout 10m;
     location / {
	  root /opt/;
	  if ( $scheme = http ) {
	  rewrite ^/(.*)$ https://www.cao.com/$1 redirect;                
	  }
}
}
[root@ubuntu2404 data]#systemctl restart nginx.service 

[root@ubuntu2404 ~]#curl -ikL https://www.cao.com
HTTP/1.1 200 OK
Server: nginx/1.28.0
Date: Fri, 04 Jul 2025 04:42:31 GMT
Content-Type: text/html
Content-Length: 14
Last-Modified: Sun, 29 Jun 2025 12:56:59 GMT
Connection: keep-alive
Keep-Alive: timeout=65
ETag: "6861381b-e"
Accept-Ranges: bytes

www.caoge.com

升级 OpenSSL 版本

OpenSSL程序库当前广泛用于实现互联网的传输层安全(TLS)协议。心脏出血(Heartbleed),也简称为心血漏洞,是一个出现在加密程序库OpenSSL的安全漏洞,此漏洞于2012年被引入了软件中, 2014年4月首次向公众披露。只要使用的是存在缺陷的OpenSSL实例,无论是服务器还是客户端,都可能因此而受到攻击。此问题的原因是在实现TLS的心跳扩展时没有对输入进行适当验证(缺少边界检查),因此漏洞的名称来源于“心跳”(heartbeat)。该程序错误属于缓冲区过读,即可以读取的数据比应该允许读取的还多。

升级 OpenSSL 版本解决安全漏洞


#准备OpenSSL源码包
[root@ubuntu2404 ~]#cd /usr/local/src/
[root@ubuntu2404 src]#wget https://github.com/openssl/openssl/releases/download/openssl-3.5.1/openssl-3.5.1.tar.gz
[root@ubuntu2404 src]#tar -xf openssl-3.5.1.tar.gz 

#编译安装Nginx并制定新版本OpenSSL路径
[root@ubuntu2404 src]#cd nginx-1.28.0/
[root@ubuntu2404 nginx-1.28.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/nginx-module-vts --with-openssl=/usr/local/src/openssl-3.5.1
[root@ubuntu2404 nginx-1.28.0]#make && make install 

#验证并启动Nginx
[root@ubuntu2404 nginx-1.28.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
[root@ubuntu2404 nginx-1.28.0]#systemctl restart nginx.service 
[root@ubuntu2404 nginx-1.28.0]#nginx -V
nginx version: nginx/1.28.0
built by gcc 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04) 
built with OpenSSL 3.5.1 1 Jul 2025
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/nginx-module-vts --with-openssl=/usr/local/src/openssl-3.5.1

Rewrite 模块

Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠PCRE(perl compatible regular expression),因此编译之前要安装PCRE库。
rewrite是nginx服务器的重要功能之一,用于实现常用的URL的重写,比如可以在改变网站结构之后, 不需要客户端修改原来的书签,也无需修改其它网站的链接地址,仍可继续访问原有内容,另外还可以在一定程度上提高网站的安全性。
利用rewrite 模块可以实现下面网站URL的跳转


http://www.58.com/bj --> http://beijing.58.com
http://baoji.58.com
http://www.360buy.com  --> http://www.jd.com/

ngx_http_rewrite_module 模块指令
官方文档: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
if指令
官方文档


https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if

用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断。
语法如下


Syntax: if (condition) { ... }
Default:  —
Context:  server, location

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接


=   #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!=  #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~   #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~  #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假

~*  #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真

-f 和 !-f     #判断请求的文件是否存在和是否不存在
-d 和 !-d     #判断请求的目录是否存在和是否不存在
-x 和 !-x     #判断文件是否可执行和是否不可执行
-e 和 !-e     #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)

#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false

#官方示例
if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}
if ($request_method = POST) {
    return 405;
}
if ($slow) {
    limit_rate 10k;
}
if ($invalid_referer) {
    return 403;
}

示例


[root@rocky9 app]# vim m.caoge.com.conf 
server {
    server_name m.caoge.com;
    #access_log  logs/access_json.log access_json;
    location /  {
        root /data/nginx;
        index index.html;
        if (!-e $request_filename) {
                echo "$request_filename is not exist";
        }
    }
 }
[root@centos7 ~]# curl m.caoge.com/xxx
/data/nginx/xxx is not exist

set 指令
指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $key value,value可以是text, variables和两者的组合。
语法如下


Syntax: set $variable value;
Default:   —
Context:   server, location, if

location /pc {
        root /app/nginx/html/;
        index test.html;
        set $name cao;
        echo $name;
        set $my_port $server_port;
        echo $my_port;
   }

根据网络判断是否限速


server {
  .....
  location  /set {
   set $slow 1; #如果为0,则不限速,非0限速
   if ($slow) {
            limit_rate 10k;
        }
    }
 }

break 指令
用于中断当前相同作用域(location)中的其他Nginx配置,与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效,位于后面的 ngx_http_rewrite_module 模块中指令就不再执行,Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在 server块和locationif块中使用。
注意:如果break指令在location块中后续指令还会继续执行,只是不执ngx_http_rewrite_module 模块的指令,其它指令还会执行
语法如下


Syntax: break;
Default:    —
Context:    server, location, if

location /break {
        default_type text/html;
        set $name cao;
        echo "break_before:name=$name" ;
        break;   #location块中break后面指令还会执行
        set $my_port $server_port;
        echo "break_after:my_port=$my_port" ;
        echo "break_after:name=$name" ;
}
#测试结果
[root@centos7 ~]#curl  http://www.wang.org/break/
break_before:name=cao
break_after:my_port= 
break_after:name=cao

return 指令
return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if 和location块进行配置。
语法格式


Syntax: return code [text];
return code URL;
return URL;
Default:    —
Context:    server, location, if

return code; #返回给客户端指定的HTTP状态码
return code [text]; #返回给客户端的状态码及响应报文的实体内容,可以调用变量,其中text如果有空格,需要用单或双引号
return code URL; #返回给客户端的URL地址
return URL; #302跳转返回给客户端的URL地址,注意:URL必须是完整的URL包括scheme,如:http://www.caoge.com/

   location /pc {
        root /app/nginx/html/;
        index test.html;
        if ( $scheme = http ){
                return 500 "service error";  #return后面的将不再执行
                echo "if----->$scheme";
        }
}
[root@centos7 ~]# curl m.caoge.com/pc
service error

return


location /test {
 default_type application/json;
 return 200 '{"status:"success"}';
}

防止压力测试等工具


if ( $http_user_agent ~* "Wget|apachebench" ) {
 set $user_agent_deny 1;
}
 if ( $user_agent_deny =1 ) {
 return 403;
}

http跳转到https


#方法0:死循环,不要使用
server {
    listen 80 ;
    listen 443 ssl;
    ssl_certificate /apps/nginx/ssl/www.caoge.com.crt;
    ssl_certificate_key /apps/nginx/ssl/www.caoge.com.key;
    ssl_session_cache shared:sslcache:20m;
    ssl_session_timeout 10m;
    server_name www.caoge.com ;
    root /data/nginx/html/pc;
    return  https://www.caoge.com/;
 }
#方法1
 server {
   listen 80;
   server_name www.caoge.com;
   return 302 https://$server_name$request_uri;
 }
 server {
   listen 443 ssl http2;
   server_name www.caoge.com;
   ssl_certificate    /etc/nginx/ssl/www.caoge.com.crt;
   ssl_certificate_key /etc/nginx/ssl/www.caoge.com.key;
   location / {
     root  /data/www/html; 
}
}

#方法2
server {
    listen 80 ;
    listen 443 ssl;
    ssl_certificate /apps/nginx/ssl/www.caoge.com.crt;
    ssl_certificate_key /apps/nginx/ssl/www.caoge.com.key;
    ssl_session_cache shared:sslcache:20m;
    ssl_session_timeout 10m;
    server_name www.caoge.com ;
    root /data/nginx/html/pc;
if ($scheme = http) {
        return  https://www.caoge.com/;
    }
    location = /nginx_status {
        stub_status;
    }
}

rewrite 指令
通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理
官方文档


https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite

rewrite可以配置在 server、location、if
语法格式


Syntax: rewrite regex replacement [flag];
Default:   —
Context:   server, location, if

rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI。
注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制。如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端,即永久重定向301。
正则表达式格式


.   #匹配除换行符以外的任意字符
w  #匹配字母或数字或下划线或汉字
s  #匹配任意的空白符
d  #匹配数字,相当于[0-9]
  #匹配单词的开始或结束
^   #匹配字付串的开始
$   #匹配字符串的结束
*   #匹配重复零次或更多次
+   #匹配重复一次或更多次
?   #匹配重复零次或一次
(n) #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*?  #匹配重复任意次,但尽可能少重复
+?  #匹配重复1次或更多次,但尽可能少重复
??  #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
W  #匹配任意不是字母,数字,下划线,汉字的字符
S  #匹配任意不是空白符的字符
D  #匹配任意非数字的字符
B  #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^caoge] #匹配除了caoge 这几个字母以外的任意字符

官方例子


http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
Example:

server {
    ...
    rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra  last;
    return  403;
    ...
 }
But if these directives are put inside the “/download/” location, the last flag 
should be replaced by break, or otherwise nginx will make 10 cycles and return 
the 500 error:

location /download/ {
    rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 break;
    rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra  break;
    return   403;
}
If a replacement string includes the new request arguments, the previous request 
arguments are appended after them. If this is undesired, putting a question mark 
at the end of a replacement string avoids having them appended, for example:

rewrite ^/users/(.*)$ /show?user=$1? last;

rewrite flag 使用介绍
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种是代理型跳转型指由客户端浏览器重新对新地址进行请求,客户端的浏览器地址信息会发生变化,如:301,302 代理型是在WEB服务器内部实现跳转,客户端的浏览器地址信息不会发生变化,如:last,break。
rewrite格式


Syntax: rewrite regex replacement [flag]; #通过正则表达式处理用户请求并返回替换后的数据包。
Default:   —
Context:   server, location, if

flag说明


redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302

permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301

break;
#重写完成后,停止对当前URL在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块之后的其它配置;结束循环,建议在location中使用
#适用于一个URL一次重写

last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户

[root@rocky9 app]# vim mobile.conf 
server {
    listen 80;
    server_name caoge.cn;
    root /data/site;
    location / {
        rewrite /1.html /2.html;  #如果没有flag,rewrite会继续执行后面的指令
        rewrite /2.html /3.html;
    }
    location /2.html {
        rewrite /2.html /a.html;
    }
    location /3.html {
        rewrite /3.html /b.html;
    }
}

[root@centos7 ~]# curl caoge.cn/1.html
b.html
[root@centos7 ~]# curl caoge.cn/2.html
a.html

break 与 last
break案例


[root@rocky9 app]# vim caoge.cn.conf 
server {
    listen 80;
    server_name caoge.cn;
    root /data/site;
    location / {
        rewrite /1.html /2.html break;
        rewrite /2.html /3.html;
    }
    location /2.html {
        rewrite /2.html /a.html;
    }
    location /3.html {
        rewrite /3.html /b.html;
    }
}
[root@centos7 ~]# curl caoge.cn/1.html
2.html
#测试结果: 当请求/1.html,最终会访问/2.html
#原因:在location{}内部,遇到break,本location{}内以及后面的所有location{}内的所有指令都不再执行。

last 案例
last:对某个location的URL匹配成功后,会停止当前location的后续rewrite规则,并结束当前location, 然后将匹配生成的新URL跳转至其他location继续匹配,直到没有location可匹配后,将最后一次location 的数据返回给客户端。
last 适用于要不改变客户端访问方式但是需做多次目的URL重写的场景。


[root@rocky9 app]# vim caoge.cn.conf 
server {
    listen 80;
    server_name caoge.cn;
    root /data/site;
    location / {
        rewrite /1.html /2.html last;
        rewrite /2.html /3.html;
    }
    location /2.html {
        rewrite /2.html /a.html;
    }
    location /3.html {
        rewrite /3.html /b.html;
    }
}
[root@centos7 ~]# curl caoge.cn/1.html
a.html
[root@centos7 ~]# curl caoge.cn/2.html
a.html
[root@centos7 ~]# curl caoge.cn/3.html
b.html
# 测试结果:当请求/1.html,最终会访问/a.html
# 原因:在location{}内部,遇到last,本location{}内后续指令不再执行,
# 而重写后的url会对所在的server{...}标签重新发起请求,从头到尾匹配一遍规则,哪个匹配则执行哪个。

last死循环


server {
    listen 80;
    server_name caoge.cn;
    root /data/site;
    location / {
        rewrite /1.html /2.html last;
        rewrite /2.html /1.html last;
    }
    location /3.html {
        rewrite /3.html /b.html;
    }
}
# 测试结果:出现500的错误
# 原因: 死循环

break 和 last 区别
rewrite指令中的break和last都属于服务器内部跳转,客户端链接地址不变,客户端无感知。
当rewrite规则遇到break指令后,本location{}后续的指令与其他location{}的所有指令都不执行。
当rewrite规则遇到last指令后,本location{}里后续规则不执行,但重写后的url会再次从头开始匹配所有Location,也包括本location,哪个location先匹配到就执行哪个,可能会造成死循环500错误。

永久与临时重定向
域名的临时的调整,后期可能会变,之前的域名或者URL可能还用、或者跳转的目的域名和URL还会跳转,这种情况浏览器不会缓存跳转,临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存。
示例


location  / {
    root /data/nginx/html/pc;
    index index.html;
    rewrite / http://www.baidu.com permanent;
    #rewrite / http://www.baidu.com redirect;
  }
#重启Nginx并访问域名 http://www.wang.org 进行测试

永久重定向301
域名永久型调整,即域名永远跳转至另外一个新的域名,之前的域名再也不使用,跳转记录可以缓存到客户端浏览器。
永久重定向会缓存DNS解析记录,浏览器中有from disk cache信息,即使nginx服务器无法访问,浏览器也会利用缓存进行重定向。
比如: 京东早期的域名 www.360buy.com 由于与360公司类似,于是后期永久重定向到了 www.jd.com

redirect 302临时重定向


[root@rocky9 app]# vim caoge.cn.conf 
server {
    listen 80;
    server_name caoge.cn;
    root /data/site;
    location / {
        rewrite /1.html /2.html redirect;
        rewrite /2.html /3.html;
    }
    location /2.html {
        rewrite /2.html /a.html;
    }
}
[root@centos7 ~]# curl caoge.cn/1.html -I
HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Mon, 02 Dec 2024 07:40:01 GMT
Content-Type: text/html
Content-Length: 138
Location: http://caoge.cn/2.html
Connection: keep-alive
#测试结果: 当请求/1.html,最终会访问/2.html
#原因:在location{}内部遇到redirect,客户端会重新发起新请求到新的重定向地址进行访问,而且url会修改为后面的新URL

redirect与permanent区别
redirect与permanent都会导致客户端上重新发起的请求,链接地址会发生变化,客户端可以感知到变化。


Flag  		状态码   说明		特点
permanent  	301		永久跳转	旧网站排名会被清空,新跳转网站继承原网站的排名,跳转会缓 存下来,主要用于旧域名废弃和新域名网站启用时使用  
redirect  	302		零时跳转	旧网站无影响,新网站会有排名,跳转不会缓存  

自动跳转https


 server {
   listen 80;
   server_name www.caoge.com;
   return 302 https://$server_name$request_uri;
 }
 server {
   listen 443 ssl http2;
   server_name www.caoge.com;
   ssl_certificate    /etc/nginx/ssl/www.caoge.com.crt;
   ssl_certificate_key /etc/nginx/ssl/www.caoge.com.key;
   location / {
   root  /data/www/html; 
  }
}

 server {
  listen 443 ssl;
  listen 80;
  ssl_certificate /apps/nginx/certs/www.caoge.com.crt;
  ssl_certificate_key /apps/nginx/certs/www.caoge.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  server_name www.caoge.com;
  location  / {    #针对全站跳转
    root /data/nginx/html/pc;
    index index.html;
    if ($scheme = http ){  #如果没有加条件判断,会导致死循环
        rewrite ^/(.*) https://$host/$1 redirect;
   }  
}
  location /login {     #针对特定的URL进行跳转https 
    if ($scheme = http ){  #如果没有加条件判断,会导致死循环
    rewrite / https://$host/login redirect;
    } 
  }
}
#重启Nginx并访问测试
[root@centos7 ~]#curl -ikL  www.caoge.com

判断文件是否存在


server{
   listen 80;
   server_name www.caoge.com;
   location /pc {
        root /app/nginx/;
        index test.html;
        if (!-e $request_filename){
              rewrite .* http://192.168.101.5/; #实现客户端浏览器的302跳转
              echo "if----->$scheme";
              #rewrite .*  /index.html; #web服务器内部跳转
    }
  }
}
[root@centos7 ~]# curl m.caoge.com/pc/xxxx -I
HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Mon, 02 Dec 2024 08:45:22 GMT
Content-Type: text/html
Content-Length: 138
Connection: keep-alive
Location: http://192.168.101.5/

指定客户端类型跳转新的域名


server {
    listen 80;
    server_name www.caoge.com;
    root /data/nginx/html/pc;
    if ($http_user_agent ~* "android|iphone|ipad") {
          rewrite ^/(.*)$ http://m.caoge.com/$1  redirect;
          #return 302 http://www.caoge.com$request_uri ;
    }
}

网站维护跳转


server {
    listen 80;
    server_name www.caoge.com;
    root /data/site;
    index index.html;
    #在server层下设定ip变量值为0
    set $ip 0;
    #如果来源IP是192.168.1.10或102则设定变量为ip变量为1。
    if ($remote_addr = 192.168.1.10) {
     set $ip 1;
     }
    if ($remote_addr = 192.168.1.11) {
     set $ip 1;
    }
    #如果来源IP不是192.168.1.10或11、则跳转至/data/site/maintain.html这个页面,否则不做任何处理
    if ($ip = 0) {
        rewrite ^(.*)$ /maintain.html break;
     }
    #如果想针对某个location进行操作,则将如上配置写入location中即可
}

Nginx防盗链

防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前的那个网站域名。
正常通过搜索引擎搜索web 网站并访问该网站的referer信息如下


[root@rocky9 nginx]# tail -f /app/nginx/logs/access.log 
192.168.101.11 - - [02/Dec/2024:16:40:48 +0800] "GET / HTTP/1.1" 200 8 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:41:56 +0800] "GET /pc/xxxxx.html HTTP/1.1" 302 138 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:42:00 +0800] "HEAD /pc/xxxxx.html HTTP/1.1" 302 0 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:43:59 +0800] "GET / HTTP/1.1" 200 8 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:44:07 +0800] "GET /xxx HTTP/1.1" 200 40 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:44:49 +0800] "GET /pc/xxx HTTP/1.1" 302 138 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:44:51 +0800] "HEAD /pc/xxx HTTP/1.1" 302 0 "-" "curl/7.29.0"
192.168.101.11 - - [02/Dec/2024:16:45:15 +0800] "HEAD /pc/xxx HTTP/1.1" 302 0 "-" "curl/7.29.0"

实现防盗链


#新建一个主机www.caoge.com,盗取另一台主机www.cao.com的图片
#盗链服务器配置如下
[root@rocky9 app]# vim nginx/conf/nginx.conf
server{
    listen 80;
    server_name www.caoge.com;
      location / {
            root   /data/nginx/html;
            index  daolian.html;
            access_log /app/nginx/logs/access.log;
           
 }
}
#准备盗链web页面
[root@rocky9 nginx]# vim html/daolian.html
<html>
 <head>
 <meta http-equiv=Content-Type content="text/html;charset=utf-8">
 <title>盗链</title>
 </head>
 <body>
 <img src="http://www.caoge.com/images/logo.jpg" >
 <h1>欢迎大家</h1>
 <p><a href=http://www.caoge.com>盗图</a>欢迎你</p>
 </body>
 </html>
[root@rocky9 nginx]# nginx -s reload
[root@rocky9 nginx]# tail -f /app/nginx/logs/access.log 
192.168.101.1 - - [02/Dec/2024:17:46:48 +0800] "GET / HTTP/1.1" 403 548 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
192.168.101.1 - - [02/Dec/2024:17:47:35 +0800] "GET / HTTP/1.1" 200 293 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"

实现防盗链
基于访问安全考虑,nginx支持通过ngx_http_referer_module模块,检查访问请求的referer信息是否有效实现防盗链功能。
官方文档


https://nginx.org/en/docs/http/ngx_http_referer_module.html

语法


Syntax: valid_referers none | blocked | server_names | string ...;
Default:  -
Context:  server, location

none:#请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。
blocked:#请求报文有referer首部,但无有效值,比如为空。
server_names:#referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string:#自定义指定字符串,但可使用*作通配符。示例: *.caoge.com www.caoge.*
regular expression:#被指定的正则表达式模式匹配到的字符串,要使用~开头,例如: ~.*.caoge.com

location   /images {
    root /data/nginx/html/pc;
    index index.html;
    valid_referers none blocked server_names
          *.example.com example.* www.example.org/galleries/
          ~.google.;
    if ($invalid_referer) {
      return 403;
}
}

定义防盗链


[root@rocky9 app]# vim caoge.cn.conf 
server {
    listen 80;
    server_name caoge.cn;
    root /data/nginx/;
    valid_referers none blocked server_names  *.wang.com *.wang.org   ~.google.
    ~.baidu.  ~.bing. ~.so. ; #定义有效的referer
    if ($invalid_referer){  #假如是使用其他的无效的referer访问
        return 403 "Foridden access";  #返回状态码403
        #return 302 http://www.caoge.com/testdir/daotu.jpg; 会出现死循环,用下面方式解决
        #rewrite ^(.*)$ /daolian.jpg break; 或者返回错误图片
    }
}   
#重启Nginx并访问测试
[root@centos7 ~]# curl -e 'www.baidu.com' caoge.cn
pc web

如何选择和使用模块
在实际应用中,选择合适的模块组合对于构建高效、安全的Web服务器至关重要。大多数情况下,Nginx的默认安装已经包含了大部分常用模块,但有些高级或特定用途的模块可能需要手动编译添加。
了解每个模块的功能和配置方法,可以帮助你更精确地满足项目需求。例如,如果你需要为你的网站增加HTTPS支持,就需要确保加载并正确配置ngx_http_ssl_module。

结语
Nginx的模块系统为其强大的功能和灵活性奠定了基础。通过合理利用这些模块,你可以轻松应对各种复杂的网络服务场景。希望这篇博客能为你开启探索Nginx模块的大门,助你在Web服务器管理的道路上越走越远。

请继续关注我们的博客,获取更多关于Nginx及其他技术主题的深度分析!

© 版权声明

相关文章

暂无评论

none
暂无评论...