Nginx高性能web服务器

Nginx介绍

Nginx是一个高性能的HTTP和反向代理服务器,也是一个邮件代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。所以其特点是占有内存少,并发能力强,事实上Nginx的并发能力确实在同类型的网页服务器中表现较好。

Nginx基础特性

模块化设计,较好的扩展性
高可靠性
支持热部署:不停机更新配置文件,升级版本,更换日志文件
低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
event-driven,aio,mmap,sendfile

Nginx架构与进程

web请求处理机制

        多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直 到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务 器资源耗尽而无法提供请求
        多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客 户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器 对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可 以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作 了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。

主进程(master process)的功能:

对外接口:接收外部的操作(信号)
对内转发:根据外部的操作的不同,通过信号管理 Worker
监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
读取Nginx 配置文件并验证其有效性和正确性
建立、绑定和关闭socket连接 按照配置生成、管理和结束工作进程
接受外界指令,比如重启、升级及退出服务器等指令
不中断服务,实现平滑升级,重启服务并应用新的配置
开启日志文件,获取文件描述符
不中断服务,实现平滑升级,升级失败进行回滚处理
编译和处理perl脚本

工作进程(worker process)的功能:

所有 Worker 进程都是平等的
实际处理:网络请求,由 Worker 进程处理
Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争 CPU资源
增加上下文切换的损耗 接受处理客户的请求 将请求依次送入各个功能模块进行处理
I/O调用,获取响应数据 与后端服务器通信,接收后端服务器的处理结果
缓存数据,访问缓存索引,查询和调用缓存数据 发送请求结果,响应客户的请求
接收主程序指令,比如重启、升级和退出等

Nginx模块介绍

核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件 驱动机制 、进程管理等核心功能
标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应 头设置 等等
可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash
多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的 支持
Stream服务模块: 实现反向代理功能,包括TCP协议代理
第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支 持等

Nginx编译安装

编译器介绍

源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),其有GNU开发,并以 GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语 言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objective C, java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块 需要依赖第三方库,比如: pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块) 等。

官方源码包下载地址:https://nginx.org/en/download.html

编译安装示例:

[root@Nginx ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
 
[root@Nginx nginx]# tar zxf nginx-1.24.0.tar.gz #解压压缩包
[root@Nginx nginx-1.24.0]# useradd -s /sbin/nologin -M nginx
[root@Nginx nginx]# cd nginx-1.24.0/
[root@Nginx nginx-1.24.0]# ls
auto     CHANGES.ru configure html     Makefile objs   src
CHANGES conf       contrib   LICENSE man       README
 
 
[root@Nginx nginx-1.24.0]# ./configure --prefix=/usr/local/nginx \
--user=nginx \ # 指定nginx运行用户
--group=nginx \ # 指定nginx运行组
--with-http_ssl_module \ # 支持https://
--with-http_v2_module \ # 支持http版本2
--with-http_realip_module \ # 支持ip透传
--with-http_stub_status_module \ # 支持状态页面 
--with-http_gzip_static_module \ # 支持压缩 
--with-pcre \ # 支持正则
--with-stream \ # 支持tcp反向代理
--with-stream_ssl_module \ # 支持tcp的ssl加密
--with-stream_realip_module # 支持tcp的透传ip
 
[root@Nginx nginx-1.24.0]# make && make install
 
nginx完成安装以后,有四个主要的目录
[root@Nginx nginx-1.24.0]# ls /usr/local/nginx/
conf html logs sbin
 
 
conf:保存nginx所有的配置文件,其中nginx.conf是nginx服务器的最核心最主要的配置文件,其他
的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params
两个文件,配置文件一般都有一个样板配置文件,是以.default为后缀,使用时可将其复制并将default后缀
去掉即可。
html目录中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50x的web
文件是默认的错误页面提示页面。
logs:用来保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比
如/var/logs/nginx里面。
sbin:保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能。
 
 
[root@Nginx ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin
[root@Nginx ~]# source ~/.bash_profile
[root@Nginx ~]# nginx -V
nginx version: nginx/1.24.0
built by gcc 11.4.1 20231218 (Red Hat 11.4.1-3) (GCC)
built with OpenSSL 3.0.7 1 Nov 2022
TLS SNI support enabled
configure arguments: --group=nginx --with-http_ssl_module --with-http_v2_module--with-http_realip_module --with-http_stub_status_module --withhttp_gzip_static_module
 --with-pcre --with-stream --with-stream_ssl_module --
with-stream_realip_module
 
 
 

配置nginx启动文件

[root@Nginx ~]# vim /lib/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
[root@Nginx ~]# systemctl daemon-reload
[root@Nginx ~]# systemctl start nginx 

平滑升级和回滚

[root@Nginx nginx]# tar zxf nginx-1.26.1.tar.gz
[root@Nginx nginx]# cd nginx-1.26.1/
#开始编译新版本
[root@Nginx nginx-1.26.1]# ./configure --with-http_ssl_module --withhttp_v2_module
 --with-http_realip_module --with-http_stub_status_module --withhttp_gzip_static_module
 --with-pcre --with-stream --with-stream_ssl_module --
with-stream_realip_module
[root@Nginx nginx-1.26.1]# make
#查看两个版本
[root@Nginx nginx-1.26.1]# ll objs/nginx /usr/local/nginx/sbin/nginx
-rwxr-xr-x 1 root root 1239416 Jul 18 15:08 objs/nginx
-rwxr-xr-x 1 root root 5671488 Jul 18 11:41 /usr/local/nginx/sbin/nginx
#把之前的旧版的nginx命令备份
[root@Nginx ~]# cd /usr/local/nginx/sbin/
[root@Nginx sbin]# cp nginx nginx.24
#把新版本的nginx命令复制过去
[root@Nginx sbin]# \cp -f /root/nginx/nginx-1.26.1/objs/nginx 
/usr/local/nginx/sbin
#检测一下有没有问题
[root@Nginx sbin]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@Nginx sbin]# kill -USR2 39014 #nginx worker ID
#USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的
nginx
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进
程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。
#回收旧版本
[root@Nginx sbin]# kill -WINCH 48732
[root@Nginx sbin]# ps aux | grep nginx
root       48732 0.0 0.1   9868 2436 ?       Ss   14:17   0:00 nginx: master 
process /usr/local/nginx/sbin/nginx
root       52075 0.0 0.3   9876 6528 ?       S   15:41   0:00 nginx: master 
process /usr/local/nginx/sbin/nginxnobody     52076 0.0 0.2 14208 4868 ?       S   15:41   0:00 nginx: worker process
#回滚
#如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker
[root@Nginx sbin]# cp nginx nginx.26
[root@Nginx sbin]# ls
nginx nginx.24 nginx.26
[root@Nginx sbin]# mv nginx.24 nginx
[root@Nginx sbin]# kill -HUP 48732
[root@Nginx sbin]# ps aux | grep nginx
root       48732 0.0 0.1   9868 2436 ?       Ss   14:17   0:00 nginx: master 
process /usr/local/nginx/sbin/nginx
root       52075 0.0 0.3   9876 6528 ?       S   15:41   0:00 nginx: master 
process /usr/local/nginx/sbin/nginx
nobody     52076 0.0 0.2 14208 5124 ?       S   15:41   0:00 nginx: worker 
process
nobody     52130 0.0 0.2 14200 4868 ?       S   16:30   0:00 nginx: worker 
process
 
 
[root@Nginx sbin]# kill -WINCH 52075
root       48732 0.0 0.1   9868 2436 ?       Ss   14:17   0:00 nginx: master 
process /usr/local/nginx/sbin/nginx
root       52075 0.0 0.3   9876 6528 ?       S   15:41   0:00 nginx: master 
process /usr/local/nginx/sbin/nginx
nobody     52130 0.0 0.2 14200 4868 ?       S   16:30   0:00 nginx: worker 
process
root       52137 0.0 0.1 221664 2176 pts/0   S+   16:31   0:00 grep --
color=auto nginx
 

Nginx核心配置

Nginx的配置文件的组成部分:

主配置文件:nginx.conf
子配置文件: include conf.d/*.conf
fastcgi, uwsgi,scgi 等协议相关的配置文件
mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动 使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
nginx 配置文件格式说明

​
配置文件由指令与指令块构成
每条指令以;分号结尾,指令与值之间以空格符号分隔
可以将多条指令放在同一行,用分号分隔即可,但可读性差,不推荐
指令块以{ }大括号将多条指令组织在一起,且可以嵌套指令块
include语句允许组合多个配置文件以提升可维护性
使用#符号添加注释,提高可读性
使用$符号使用变量
部分指令的参数支持正则表达式

​

Nginx 主配置文件的配置指令方式:

directive value [value2 ...];
注意
(1) 指令必须以分号结尾
(2) 支持使用配置变量
 内建变量:由Nginx模块引入,可直接引用
 自定义变量:由用户使用set命令定义,格式: set variable_name value;
 引用变量:$variable_name

主配置文件结构:四部分

main block:主配置段,即全局配置段,对http,mail都有效
#事件驱动相关的配置
event {
 ...
}  
#http/https 协议相关配置段
http {
...
} 
#默认配置文件不包括下面两个块
#mail 协议相关配置段
mail {
 ...
}
#stream 服务器相关配置段
stream {
 ...
} 

默认的nginx.conf 配置文件格式说明

#全局配置端,对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路径,日志路径等。
user nginx nginx;
 
worker_processes  1;   #启动工作进程数数量
 
events { #events #设置快,主要影响nginx服务器与用户的网络连接,比如是否允许同时接受多个网络连接,使用哪种事件驱动模型 #处理请求,每个工作进程可以同时支持的最大连接数,是否开启对多工作进程下的网络连接进行序列化等。
 
worker_connections  1024;   #设置单个nginx工作进程可以接受的最大并发,作为web服务器的时候最大并发数为1024 
worker_processes,作为反向代理的时候为
 #(worker_connections * worker_processes)/2
}
 
http { 
    #http块是Nginx服务器配置中的重要部分,缓存、代理和日志格式定义等绝大多数功能和第三方模块都 #可以在这设置,http块可以包含多个server块,而一个server块中又可以包含多个location块
 
 server块可以配置文件引入、MIME-Type定义、日志自定义、是否启用sendfile、连接超时时间和 #单个链接的请求上限等。
   include       mime.types;
   default_type application/octet-stream;
   sendfile       on; #作为web服务器的时候打开sendfile加快静态文件传输,指定是否使用sendfile系统调用来传输文件  #sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作)#从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝,
 
#硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈。
 
 keepalive_timeout  65;   #长连接超时时间,单位是秒
 
 server { #设置一个虚拟机主机,可以包含自己的全局快,同时也可以包含多个location模块
   
#比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server 可以使用一个端口比如都使用 #80端口提供web服务
   
       listen       80;   #配置server监听的端口
      server_name localhost;   #本server的名称,当访问此名称的时候nginx会调用当前serevr
内部的配置进程匹配。
       
       location / { #location其实是server的一个指令,为nginx服务器提供比较
多而且灵活的指令
       #都是在location中体现的,主要是基于nginx接受到的请求字符串
       #对用户请求的UIL进行匹配,并对特定的指令进行处理
       #包括地址重定向、数据缓存和应答控制等功能都是在这部分实现
       #另外很多第三方模块的配置也是在location模块中配置。
       
        root   html; #相当于默认页面的目录名称,默认是安装目录的相对路径,可以使用绝对路径配置。
        index index.html index.htm; #默认的页面文件名称
                 }
       
        error_page   500 502 503 504 /50x.html; #错误页面的文件名称
        location = /50x.html { #location处理对应的不同错误码的页面定义到/50x.html
       #这个跟对应其server中定义的目录下。
           root   html;   #定义默认页面所在的目录
       }
   }
    
#和邮件相关的配置
#mail {
#               ...
#       }         mail 协议相关配置段
#tcp代理配置,1.9版本以上支持
#stream {
#               ...
#       }       stream 服务器相关配置段
#导入其他路径的配置文件
#include /apps/nginx/conf.d/*.conf
}

全局配置

Main 全局配置段常见的配置指令分类

正常运行必备的配置

优化性能相关的配置

用于调试及定位问题相关的配置

事件驱动相关的配置

全局配置说明:

user nginx nginx; #启动Nginx工作进程的用户和组
worker_processes [number | auto]; #启动Nginx工作进程的数量,一般设为和CPU核心数相同worker_cpu_affinity 00000001 00000010 00000100 00001000 | auto ; 
#将Nginx工作进程绑定到指定的CPU核心,默认Nginx是不进行进程绑定的,绑定并不是意味着当前nginx进程独占以一核心CPU,但是可以保证此进程不运行在其他核心上,这就极大减少了nginx的工作进程在不同的cpu核心上的来回跳转,减少了CPU对进程的资源分配与回收以及内存管理等,因此可以有效的提升nginx服务器的性能。
CPU MASK: 00000001:0号CPU
 00000010:1号CPU
 10000000:7号CPU
 
#示例
worker_cpu_affinity 0001 0010 0100 1000;第0号---第3号CPU
worker_cpu_affinity 0101 1010; 
#示例
worker_processes  4;
worker_cpu_affinity 00000010 00001000 00100000 10000000;
[root@centos8 ~]# ps axo pid,cmd,psr | grep nginx
31093 nginx: master process /apps   1
34474 nginx: worker process         1
34475 nginx: worker process         3
34476 nginx: worker process         5
34477 nginx: worker process         7
#错误日志记录配置,语法:error_log file [debug | info | notice | warn | error | crit 
| alert | emerg]
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log /usr/local/nginx/logs/error.log error; 
#pid文件保存路径
pid       /usr/local/nginx/logs/nginx.pid;
worker_priority 0; #工作进程优先级,-20~20(19)
worker_rlimit_nofile 65536; #所有worker进程能打开的文件数量上限,
 #包括:Nginx的所有连接(例如与代理服务器的连接等)
 #而不仅仅是与客户端的连接
 #另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件数的限制
 #最好与ulimit -n 或者limits.conf的值保持一致,
#修改pam限制
[root@Nginx ~]# sudo -u nginx ulimit -n
1024
[root@Nginx ~]# vim /etc/security/limits.conf
*               -       nofile         100000
[root@Nginx ~]# sudo -u nginx ulimit -n
100000
daemon off;   #前台运行Nginx服务用于测试、docker等环境。
master_process off|on; #是否开启Nginx的master-worker工作模式,仅用于开发调试场景,默认为on
events {worker_connections 65535;   #设置单个工作进程的最大并发连接数
   use epoll; #使用epoll事件驱动,
   #Nginx支持众多的事件驱动,
   #比如:select、poll、epoll,只能设置在events模块中设置
    
   accept_mutex on;   #on为同一时刻一个请求轮流由work进程处理,
   #而防止被同时唤醒所有worker
   #避免多个睡眠进程被唤醒的设置,默认为off
   #新请求会唤醒所有worker进程,此过程也称为"惊群"
   #因此nginx刚安装完以后要进行适当的优化。建议设置为on
   
   multi_accept on; #on时Nginx服务器的每个工作进程可以同时接受多个新的网络连接
   #此指令默认为off,
   #即默认为一个工作进程只能一次接受一个新的网络连接
   #打开后几个同接受多个。建议设置为on
   
}

示例: 实现 nginx 的高并发配置

[root@Nginx ~]# ulimit -n 102400
[root@Nginx ~]# ab -c 5000 -n 10000 http://10.0.0.8/
#默认配置不支持高并发,会出现以下错误日志
[root@Nginx ~]# tail /apps/nginx/logs/error.log
2020/09/24 21:19:33 [crit] 41006#0: *1105860 open() "/apps/nginx/html/50x.html" 
failed (24: Too many open files), client: 10.0.0.7, server: localhost, request: 
"GET / HTTP/1.0", host: "10.0.0.8"
2020/09/24 21:19:33 [crit] 41006#0: accept4() failed (24: Too many open files)
2020/09/24 21:19:33 [crit] 41006#0: *1114177 open() 
"/apps/nginx/html/index.html" failed (24: Too many open files), client: 10.0.0.7, 
server: localhost, request: "GET / HTTP/1.0", host: "10.0.0.8"
#修改配置
[root@Nginx ~]# vim /etc/security/limits.conf 
*   - nproc 100000
[root@Nginx ~]# vim /apps/nginx/conf/nginx.conf
worker_rlimit_nofile 100000; 
[root@Nginx ~]# systemctl restart nginx

location详解

在一个server中location配置段可存在多个,用于实现从uri到文件系统的路径映射
ngnix会根据用户请求的URI来检查定义的所有location,按一定的优先级找出一个最佳匹配, 而后应用其配置在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最高的一个uri
uri是用户请求的字符串,即域名后面的web文件路径 然后使用该location模块中的正则url和字符串,如果匹配成功就结束搜索,并使用此location处理 此请求。

#语法规则:
location [ = | ~ | ~* | ^~ ] uri { ... }
= #用于标准uri前,需要请求字串与uri精确匹配,大小敏感,如果匹配成功就停止向下匹配并立
即处理请求
^~   #用于标准uri前,表示包含正则表达式,并且匹配以指定的正则表达式开头
 #对uri的最左边部分做匹配检查,不区分字符大小写
 
~   #用于标准uri前,表示包含正则表达式,并且区分大小写
~*   #用于标准uri前,表示包含正则表达式,并且不区分大写
不带符号 #匹配起始于此uri的所有的uri
\   #用于标准uri前,表示包含正则表达式并且转义字符。可以将 . * ?等转义为普通符号
#匹配优先级从高到低:
=, ^~, ~/~*, 不带符号

Nginx账户认证功能

由 ngx_http_auth_basic_module 模块提供此功能

[root@Nginx ~]# htpasswd -cmb /usr/local/nginx/conf/.htpasswd admin lee   #-b 表示非交互建立用户认证
Adding password for user admin
[root@Nginx ~]# htpasswd -mb /usr/local/nginx/conf/.htpasswd lee lee
Adding password for user lee
[root@Nginx ~]# cat /usr/local/nginx/conf/.htpasswd
admin:$apr1$haGCKgCT$myogggALmqNecTyNupsWQ/
lee:$apr1$H97AyQPF$kGU.Tc4zn1E4Zkp/M4R6G.
[root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/login
[root@Nginx ~]# echo login > /webdata/nginx/timinglee.org/lee/login/index.html
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
 server {
       listen 80;
       server_name lee.timinglee.org;
       location /login {
           root /webdata/nginx/timinglee.org/lee;
           index index.html;
           auth_basic "login password";
           auth_basic_user_file "/usr/local/nginx/conf/.htpasswd";
       }
}
#重启Nginx并访问测试
[root@node100 ~]# curl lee.timinglee.org/login/ -u lee:lee
login
[root@node100 ~]# curl lee.timinglee.org/login/ -u admin:lee
login

自定义错误页面

自定义错误页,同时也可以用指定的响应状态码进行响应, 可用位置:http, server, location, if in location

error_page code ... [=[response]] uri;
[root@Nginx ~]# mkdir /webdata/nginx/timinglee/lee/errors -p
[root@Nginx ~]# echo error page > /webdata/nginx/timinglee/lee/errors/40x.html
server {
   listen 80;
   server_name lee.timinglee.org;
   error_page 404 /40x.html
   location = /40x.html {
       root /webdata/nginx/timinglee/lee/errors;
   }
}
测试:
[root@node100 ~]# curl lee.timinglee.org/haha
error page

自定义错误日志

[root@Nginx ~]# mkdir "/var/log/nginx" -p
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
   listen 80;
   server_name lee.timinglee.org;
   error_page 404 /40x.html;
   access_log /var/log/nginx/access.log;
   error_log /var/log/nginx/error.log;
   location = /40x.html {
       root /webdata/nginx/timinglee/lee/errors;
   }
} 
#重启nginx并访问不存在的页面进行测试并验证是在指定目录生成新的日志文件

检查文件是否存在

try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如 果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一 个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内 部500错误

[root@Nginx ~]# echo "index.html is not exist" > 
/webdata/nginx/timinglee.org/lee/error/default.html
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
   listen 80;
   server_name lee.timinglee.org;
   root /webdata/nginx/timinglee.org/lee;
   error_page 404 /40x.html;
   access_log /var/log/nginx/access.log;
   error_log /var/log/nginx/error.log;
   try_files $uri $uri.html $uri/index.html /error/default.html;
   location = /40x.html {
       root /webdata/nginx/timinglee/lee/errors;
   }
}

Nginx高级配置

nginx状态页

基于nginx 模块 ngx_http_stub_status_module 实现

在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module 否则配置完成之后监测会是提示法错误

#配置示例:
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;
 }
#状态页用于输出nginx的基本状态信息:
#输出信息示例:
Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
 上面三个数字分别对应accepts,handled,requests三个值
Reading: 6 Writing: 179 Waiting: 106
Active connections: #当前处于活动状态的客户端连接数
 #包括连接等待空闲连接数=reading+writing+waiting
 
accepts: #统计总值,Nginx自启动后已经接受的客户端请求连接的总数。
handled: #统计总值,Nginx自启动后已经处理完成的客户端请求连接总数
 #通常等于accepts,除非有因worker_connections限制等被拒绝的
连接
 
requests: #统计总值,Nginx自启动后客户端发来的总的请求数
Reading: #当前状态,正在读取客户端请求报文首部的连接的连接数
 #数值越大,说明排队现象严重,性能不足
 
Writing: #当前状态,正在向客户端发送响应报文过程中的连接数,数值越大,说明
访问量很大
Waiting: #当前状态,正在等待客户端发出请求的空闲连接数
 开启 keep-alive的情况下,这个值等于active – 
(reading+writing)

 Nginx版本隐藏

用户在访问nginx的时候,我们可以从报文中获得nginx的版本,相对于裸漏版本号的nginx,我们把其隐 藏起来更安全

[root@Nginx nginx-1.26.1]# vim src/core/nginx.h
#define nginx_version     1026001
#define NGINX_VERSION     "1.0"
#define NGINX_VER         "HAHA/" NGINX_VERSION

Nginx变量使用

nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用

变量可以分为内置变量和自定义变量

内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值。

常用内置变量

$remote_addr; 
#存放了客户端的地址,注意是客户端的公网IP
$args; 
#变量中存放了URL中的所有参数
#例如:https://search.jd.com/Search?keyword=手机&enc=utf-8
#返回结果为: keyword=手机&enc=utf-8
$is_args
#如果有参数为? 否则为空
$document_root; 
#保存了针对当前资源的请求的系统根目录,例如:/webdata/nginx/timinglee.org/lee。
$document_uri;
#保存了当前请求中不包含参数的URI,注意是不包含请求的指令
#比如:http://lee.timinglee.org/var?\id=11111会被定义为/var 
#返回结果为:/var
$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请求生成的文件绝对路径,
#如:webdata/nginx/timinglee.org/lee/var/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为任意请求报文首部字段,表示记录请求报文的首部字段,name的对应的首部字段名需要为小写,如果有
横线需要替换为下划线
#示例: 
echo $http_user_agent; 
echo $http_host;
$sent_http_<name>
#name为响应报文的首部字段,name的对应的首部字段名需要为小写,如果有横线需要替换为下划线,此变量有
问题
echo $sent_http_server;
$arg_<name>
#此变量存放了URL中的指定参数,name为请求url中指定的参数
echo $arg_id;
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
 listen 80;
 server_name lee.timinglee.org;
 root /webdata/nginx/timinglee.org/lee;
 location /var {
   default_type text/html;
   echo $remote_addr;
   echo $args;
   echo $document_root;
   echo $document_uri;
   echo $host;
   echo $http_user_agent;
   echo $request_filename;
   echo $scheme;
   echo $scheme://$host$document_uri?$args;
   echo $http_cookie;
   echo $cookie_key2;
   echo $http_Accept;
 }
}
 

Nginx Rewrite相关功能

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

使用正则表达式对变量进行匹配,匹配成功时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
location /test {
   index index.html;
   default_type text/html;
   if ( $scheme = http ){
     echo "if ---------> $scheme";
   }
   if ( $scheme = https ){
     echo "if ---------> $scheme";
   }
 }
 location /test2 {
   if ( !-e $request_filename ){
       echo "$request_filename is not exist";
       return 409;
   }
 }
测试:
[root@client ~]# curl lee.timinglee.org/test/
if ---------> http
[root@client ~]# curl lee.timinglee.org/test2/test
/webdata/nginx/timinglee.org/lee/test2/test is not exist

set指令

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

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
 listen 80;
 server_name lee.timinglee.org;
 root /webdata/nginx/timinglee.org/lee;
 location /test3{
     set $name lee;
     echo $name;
 }
}
测试:
[root@client ~]# curl lee.timinglee.org/test3
lee

break指令

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

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
 listen 80;
 server_name lee.timinglee.org;
 root /webdata/nginx/timinglee.org/lee;
 location /break{
     default_type text/html;
     set $name lee;
     echo $name;
     break;
     set $port $server_port;
     echo $port;
   }
}
 
[root@client ~]# curl lee.timinglee.org/break #当未添加break时
lee
80
[root@client ~]# curl lee.timinglee.org/break #添加break后
lee

return指令

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

server {
 listen 80;
 server_name lee.timinglee.org;
 root /webdata/nginx/timinglee.org/lee;
 location /return {
     default_type text/html;
     if ( !-e $request_filename){
       return 301 http://www.baidu.com;
       #return 666 "$request_filename is not exist";
     }
     echo "$request_filename is exist";
   }
}
测试:
[root@client ~]# curl lee.timinglee.org/return
/webdata/nginx/timinglee.org/lee/return is exist
[root@client ~]# curl lee.timinglee.org/return1
/webdata/nginx/timinglee.org/lee/return1 is not exist
#测试return 301 http://www.baidu.com;
可在浏览器直接访问lee.timinglee.org/return1

rewrite指令

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

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

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

rewrite flag 使用介绍
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时 重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种代理型

跳转型指由客户端浏览器重新对新地址进行请求
代理型是在WEB服务器内部实现跳转
flag说明

redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端
#由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302
permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端
#由客户端重新发起请求,状态码:301
break;
#重写完成后,停止对当前URL在当前location中后续的其它重写操作
#而后直接跳转至重写规则配置块之后的其它配置,结束循环,建议在location中使用
#适用于一个URL一次重写
last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,
#而后对新的URL启动新一轮重写检查,不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户

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

[root@nginx]# mkdir /data/web/html/{test1,test2,break,last}
[root@nginx]# echo test1 > /data/web/html/test1/index.html
[root@nginx]# echo test2 > /data/web/html/test2/index.html
[root@nginx]# echo last > /data/web/html/last/index.html
[root@nginx]# echo break > /data/web/html/break/index.html
[root@nginx nginx]# vim conf.d/vhosts.conf
server {
   listen 80;
   server_name www.timinglee.org;
   root /data/web/html;
   index index.html;
   location /break {
       root /data/web/html;
       rewrite ^/break/(.*) /test1/$1 break;
       rewrite ^/test1/(.*) /test2/$1 ;
   }
   location /last {
       root /data/web/html;
       rewrite ^/last/(.*) /test1/$1 last;
       rewrite ^/test1/(.*) /test2/$1 ;
   }
   location /test1 {
       default_type text/html;
       return 666 "new test1";
   }
   location /test2 {
       root /data/web/html;
   }
}
#测试:
[root@client ~]# curl -L www.timinglee.org/break/index.html
test1
[root@client ~]# curl -L www.timinglee.org/last/index.html
new test1

Nginx防盗链

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

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

实现盗链

准备一个web服务器(172.25.254.10),写入网站内容,在该站点盗取另一(172.25.254.100)的图片资源。

<html>
 
  <head>
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>盗链</title>
</head>
 
  <body>
    <img src="http://www.timinglee.org/images/1.png" >
    <h1 style="color:red">欢迎大家</h1>
    <p><a href=http://www.timinglee.org</a>出门见喜</p>
  </body>
 
</html>

在172.25.254.100的服务器的images文件夹内上传图片1.png。

浏览器输入:http://172.25.254.10可以看到该站点自动连接到100服务器的图片

实现防盗链

在100服务器http的发布目录内上传盗链图片,意味着当其他站点盗链1.png时,会自动替换成盗链图片。

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
   listen 80;
   server_name www.timinglee.org;
   root /data/web/html;
   index index.html;
   location / {
       valid_referers none blocked server_names *.timinglee.org ~/.baidu/.;
        if ($invalid_referer){
           return 404;
       }
   }
   location /images {
       valid_referers none blocked server_names *.timinglee.org ~/.baidu/.;
        if ($invalid_referer){
       rewrite ^/ http://www.timinglee.org/daolian.png permanent; #注意此图片不能和正常图片放在一个目录中
       }
   }
}
 
#重启Nginx并访问测试
http://172.25.254.20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值