Nginx

⼀、 Nginx应用指南

源码地址:https://trac.nginx.org/nginx/browser

1.1 Nginx基本简述

Nginx是⼀个开源且⾼性能、可靠的HTTP Web服务器中间件、代理服务、负载均衡。
开源: 直接获取源代码
⾼性能: ⽀持海量并发
可靠: 服务稳定

常⻅的HTTP服务:
1.HTTPD -> Apache基⾦会
2.IIS -> 微软 Windows
3.GWS -> Google
4.openrestry OpenResty 使⽤介绍 | 菜⻦教程 (runoob.com)
5.tengline -> 淘宝基于Nginx开发

Nginx应⽤场景:
静态处理
反向代理
负载均衡
资源缓存
安全防护
访问限制
访问认证

1.2 Nginx优秀特性

二进制版本地址:nginx.org

为什么选择Nginx?
  1. ⾼性能和⾼并发。

  2. 处理静态⽂件效率⾼。

  3. 轻量级和低内存消耗。

  4. 可扩展性强。

  5. ⽀持反向代理和负载均衡。

  6. 社区活跃和丰富的⽂档资源。

IO 和多路复⽤的概念

介绍⼀下 IO 和多路复⽤的概念。

IO是指计算机系统中⽤于输⼊/输出的技术,在⾼负载的应⽤场景中, IO会成为系统 资源瓶颈 ,因为IO操作通常是阻塞的 ,即应⽤程序等待IO操作完成后才能继续执⾏。这意味着应⽤程序在等待IO时会被“挂起”,不能充分地利⽤处理器等其他资源,从⽽导致性能下降。

多路复⽤是⼀种技术,允许单个进程从多个套接字中同时等待IO事件。多路复⽤充分利⽤了计算机的并发特性和现代操作系统的特殊API,可以⼤⼤提⾼IO性能和系统吞吐量,减少资源浪费和系统延迟。

Nginx采⽤IO多路复⽤

IO复⽤解决的是并发性的问题,处理多个并发请求,对于中间件就会产⽣多个Socket作为复⽤,socket最为复⽤,完成整个IO处理
IO多路复⽤(串⾏的⽅式来进⾏请求流的处理,容易产⽣阻塞)
IO复⽤(多线程的⽅式进⾏IO流的处理,管理线程对服务端消耗⼤)
IO多路复⽤(主动上报)
多个描述符的I/O操作都能在⼀个线程内并发交替地顺序完成 ,这就叫I/O多路复⽤,这⾥的 "复⽤"指的是复⽤同⼀个线程。
IO多路复⽤的实现⽅式有select、 poll、 Epool

什么是select

select缺点

1.能够监视⽂件描述符的数量存在最⼤限制
2.线性遍历扫描效率低下

epool模型

1.每当FD就绪,采⽤系统的回调函数之间将fd放⼊,效率更⾼。
2.最⼤连接⽆限制

轻量级

1.功能模块少(源代码仅保留http与核⼼模块代码,其余不够核⼼代码会作为插件来安装)
2.代码模块化(易读,便于⼆次开发,对于开发⼈员是⾮常友好)

CPU亲和(affinity)
将CPU核⼼和Nginx⼯作进程绑定⽅式,把每个worker进程固定在⼀个cpu上执⾏,减少切换cpu的 cachemiss ,获得更好的性能。

sendfile
传统⽂件传输, 在实现上其实是⽐较复杂的, 其具体流程细节如下:

1.调⽤read函数,⽂件数据被复制到内核缓冲
2.read函数返回,⽂件数据从内核缓冲区复制到⽤户缓冲区
3.write函数调⽤,将⽂件数据从⽤户缓冲区复制到内核与socket相关的缓冲区。
4.数据从socket缓冲区复制到相关协议引擎。
传统⽂件传输数据实际上是经过了四次复制操作:
硬盘—>内核buf—>⽤户buf—>socket缓冲区(内核)—>协议引擎
也就是说传统的⽂件传输需要经过多次上下⽂的切换才能完成拷⻉或读取, 效率不⾼。

sendfile⽂件传输是在内核中操作完成的, 函数直接在两个⽂件描述符之间传递数据, 从⽽避免了内核缓冲区数据和⽤户缓冲区数据之间的拷⻉, 操作效率很⾼, 被称之为 零拷⻉ 。

1.系统调⽤sendfile函数通过 DMA 把硬盘数据拷⻉到 kernel buffer,
2.数据被 kernel 直接拷⻉到另外⼀个与 socket 相关的 kernel buffer。
3.DMA把数据从kernel buffer直接拷⻉给协议栈。
这⾥没有⽤户空间和内核空间之间的切换,在内核中直接完成了从⼀个buffer到另⼀个buffer的拷⻉。

DMA(直接内存访问, Direct Memory Access)是⼀种数据传输⽅式,它允许外设(如硬盘、⽹络适配器等)直接访问主存中的数据,⽽不需要 CPU 参与数据传输。这样可以减轻 CPU 的负担,提⾼数据传输效率,减少数据传输延迟,提升系统性能。
当应⽤程序调⽤ `sendfile()` 系统调⽤时,内核会使⽤ DMA 将数据从⽂件系统中复制到⽹络适配器的缓冲区中,然后通过⽹络适配器将数据发送到⽹络中。在整个过程中, CPU 不需要参与数据传输过程,只需要进⾏⼀些准备⼯作和协调⼯作,从⽽⼤⼤提⾼了数据传输效率。

⼆、 Nginx快速安装

2.1 yum安装

Mainline version 开发版
Stable version 稳定版
Legacy version 历史版本
基础环境准备:Centos7

//确认系统⽹络
[root@Nginx ~]# pyuan baidu.com

//关闭firewalld
[root@Nginx ~]# systemctl stop firewalld
[root@Nginx ~]# systemctl disable firewalld

//临时关闭selinux
[root@Nginx ~]# setenforce 0

//初始化基本⽬录
[root@Nginx ~]# mkdir /soft/{code,logs,package,backup} -p

//基本安装包
[root@Nginx ~]# yum install -y gcc gcc-c++ autoconf \
pcre pcre-devel make automake wget httpd-tools vim tree

//配置Nginx官⽅Yum源
[root@Nginx ~]# vim /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

//安装Nginx
[root@Nginx ~]# yum install nginx -y

//查看Nginx当前版本
[root@Nginx ~]# nginx -v
nginx version: nginx/1.24.0

Nginx安装⽬录

为了让⼤家更清晰的了解 Nginx 软件的全貌,有必要介绍下 Nginx 安装后整体的⽬录结构及⽂件功能。

[root@Nginx ~]# rpm -ql nginx

如下表格对 Nginx 安装⽬录做详细概述

路径 类型 作⽤
/etc/nginx /etc/nginx/nginx.conf /etc/nginx/conf.d /etc/nginx/conf.d/default.conf 配置 ⽂件 Nginx主配置⽂件
/etc/nginx/fastcgi_params /etc/nginx/scgi_params /etc/nginx/uwsgi_params 配置 ⽂件 Cgi、 Fastcgi、 Uwcgi 配置⽂件
/etc/nginx/win-utf /etc/nginx/koi-utf /etc/nginx/koi-win 配置 ⽂件 Nginx编码转换映射⽂件(简单了解及下)
/etc/nginx/mime.types 配置 ⽂件 http协议的Content Type与扩展名
/usr/lib/systemd/system/nginx.service 配置 ⽂件 配置系统守护进程管 理器
/etc/logrotate.d/nginx 配置 ⽂件 Nginx⽇志轮询,⽇志 切割
/usr/sbin/nginx /usr/sbin/nginx-debug 命令 Nginx终端管理命令
/etc/nginx/modules /usr/lib64/nginx /usr/lib64/nginx/modules ⽬录 Nginx模块⽬录
/usr/share/nginx /usr/share/nginx/html /usr/share/nginx/html/50x.html /usr/share/nginx/html/index.html ⽬录 Nginx默认站点⽬录
/usr/share/doc/nginx-1.12.2 /usr/share/man/man8/nginx.8.gz ⽬录 Nginx的帮助⼿册
/var/cache/nginx ⽬录 Nginx的缓存⽬录
/var/log/nginx ⽬录 Nginx的⽇志⽬录

Nginx编译参数

查看Nginx编译参数

[root@Nginx ~]# nginx -V

下表展示了Nginx编译参数选项以及作⽤(简单了解)

编译选项 作⽤
--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock path=/var/run/nginx.lock 程序安装 ⽬录和路 径
--http-client-body-temp-path=/var/cache/nginx/client_tem --http-proxy-temp path=/var/cache/nginx/proxy_temp --http-fastcgi-temp path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp 临时缓存 ⽂件
--user=nginx --group=nginx 设定 Nginx进 程启动⽤ 户和组(安 全)
--with-cc-opt 设置额外 的参数将 被添加到 CFLAGS 变量
--with-ld-opt 设置附加 的参数, 链 接系统库

Nginx常⽤模块

Nginx模块分为 Nginx官⽅模块以及Nginx第三⽅模块

Nginx编译选项 模块作⽤
ngx_http_core_module 包含⼀些核⼼的http参数配置,对应Nginx的配置区块部分
ngx_http_access_module 访问控制模块,⽤来控制⽹站⽤户对Nginx的访问
ngx_http_gzip_module 压缩模块,对Nginx返回的数据压缩,属于性能优化模块
ngx_http_fastcgi_module fastci模块,和动态应⽤相关的模块,例如PHP
ngx_http_proxy_module proxy代理模块
ngx_http_upstream_module 负载均衡模块,可以实现⽹站的负载均衡功能及节点的健康检查。
ngx_http_rewrite_module URL地址重写模块
ngx_http_limit_conn_module 限制⽤户并发连接数及请求数模块
ngx_http_limit_req_module 限制Nginx request processyuan rate根据定义的key
ngx_http_log_module 访问⽇志模块,以指定的格式记录Nginx客户访问⽇志等信息
ngx_http_auth_basic_module Web认证模块,设置Web⽤户通过账号密码访问Nginx
nginx_http_ssl_module ssl模块,⽤于加密的http连接,如https

Nginx内置变量

http核⼼模块的内置变量

http请求变量
Nginx内置变量
⾃定义变量

$uri: 当前请求的uri,不带参数 ⽐如访问:xx.com/url?name=yuan 获取到 xx.com/url
$request_uri: 请求的uri,带完整参数 ⽐如访问:xx.com/url?name=yuan 获取到 xx.com/url?name=yuan
$host: http请求报⽂中host⾸部,如果没有则以处理此请求的虚拟主机的主机名代替
$hostname: nginx服务运⾏在主机的主机名
$remote_addr: 客户端IP
$remote_port: 客户端端⼝
$remote_user: 使⽤⽤户认证时客户端⽤户输⼊的⽤户名
$request_filename: ⽤户请求中的URI经过本地root或alias转换后映射的本地⽂件路径
$request_method: 请求⽅法, GET POST PUT DELET
$server_addr: 服务器地址
$server_name: 服务器名称
$server_port: 服务器端⼝
$server_protocol: 服务器向客户端发送响应时的协议, 如http/1.1 http/1.0
$scheme:在请求中使⽤scheme, 如http://xxx.com中的http
$http_HEADER: 匹配请求报⽂中指定的HEADER
$http_host: 匹配请求报⽂中的host⾸部
$document_root: 当前请求映射到的root配置

2.2 Nginx编译安装

安装依赖

prce(重定向⽀持)和openssl(https⽀持,如果不需要https可以不安装。)

yum install -y pcre-devel
yum -y install gcc make gcc-c++ wget
yum -y install openssl openssl-devel

编译安装参数说明

参数 说明
--prefix= Nginx安装路径。如果没有指定,默认为 /usr/local/nginx
--sbin-path= Nginx可执⾏⽂件安装路径。只能安装时指定,如果没有指定,默认为 /sbin/nginx。
--conf-path= 在没有给定-c选项下默认的nginx.conf的路径。如果没有指定,默认为 /conf/nginx.conf。
--pid-path= 在nginx.conf中没有指定pid指令的情况下,默认的nginx.pid的路径。如果没有指定,默认 为 /logs/nginx.pid。
--lock-path= nginx.lock⽂件的路径。
--error-log-path= 在nginx.conf中没有指定error_log指令的情况下,默认的错误⽇志的路径。如果没有指定, 默认为 /- logs/error.log。
--http-log-path= 在nginx.conf中没有指定access_log指令的情况下,默认的访问⽇志的路径。如果没有指 定,默认为 /- logs/access.log。
--user= 在nginx.conf中没有指定user指令的情况下,默认的nginx使⽤的⽤户。如果没有指定,默 认为 nobody。
--group= 在nginx.conf中没有指定user指令的情况下,默认的nginx使⽤的组。如果没有指定,默认 为 nobody。
--builddir=DIR 指定编译的⽬录
--with-rtsig_module 启⽤ rtsig 模块
--with-select_module --without select_module 允许或不允许开启SELECT模式,如果 configure 没有找到更合适的模式,⽐如: kqueue(sun os),epoll (linux kenel 2.6+), rtsig(- 实时信号)或者/dev/poll(⼀种类似select的 模式,底层实现与SELECT基本相 同,都是采⽤轮训⽅法) SELECT模式将是默认安装模式
--with-poll_module --without poll_module Whether or not to enable the poll module. This module is enabled by, default if a more suitable method such as kqueue, epoll, rtsig or /dev/poll is not discovered by configure.
--with-http_ssl_module Enable ngx_http_ssl_module. Enables SSL support and the ability to handle HTTPS requests. Requires OpenSSL. On Debian, this is libssl-dev. 开启HTTP SSL模块,使 NGINX可以⽀持HTTPS请求。这个模块需要已经安装了OPENSSL,在DEBIAN上是libssl
--with-http_realip_module 启⽤ ngx_http_realip_module
--with-http_addition_module 启⽤ ngx_http_addition_module
--with-http_sub_module 启⽤ ngx_http_sub_module
--with-http_dav_module 启⽤ ngx_http_dav_module
--with-http_flv_module 启⽤ ngx_http_flv_module
--with-http_stub_status_module 启⽤ "server status" ⻚ 监控
--without-http_charset_module 禁⽤ ngx_http_charset_module
--without-http_gzip_module 启⽤ ngx_http_gzip_module. 如果启⽤,需要 zlib 。
--without-http_ssi_module 启⽤ ngx_http_ssi_module
--without-http_userid_module 禁⽤ ngx_http_userid_module
--without-http_access_module 禁⽤ ngx_http_access_module
--without http_auth_basic_module 禁⽤ ngx_http_auth_basic_module
--without http_autoindex_module 禁⽤ ngx_http_autoindex_module
--without-http_geo_module 禁⽤ ngx_http_geo_module
--without-http_map_module 禁⽤ ngx_http_map_module
--without-http_referer_module 禁⽤ ngx_http_referer_module
--without-http_rewrite_module 禁⽤ ngx_http_rewrite_module. 如果启⽤需要 PCRE 。
--without-http_proxy_module 禁⽤ ngx_http_proxy_module
--without-http_fastcgi_module 禁⽤ ngx_http_fastcgi_module
--without http_memcached_module 禁⽤ ngx_http_memcached_module
--without http_limit_zone_module 禁⽤ ngx_http_limit_zone_module
--without http_empty_gif_module 禁⽤ ngx_http_empty_gif_module
--without-http_browser_module 禁⽤ ngx_http_browser_module
--without http_upstream_ip_hash_module 禁⽤ ngx_http_upstream_ip_hash_module
--with-http_perl_module 启⽤ ngx_http_perl_module
--with perl_modules_path=PATH 指定 perl 模块的路径
--with-perl=PATH 指定 perl 执⾏⽂件的路径
--http-log-path=PATH Set path to the http access log
--http-client-body-temp path=PATH Set path to the http client request body temporary files
--http-proxy-temp-path=PATH Set path to the http proxy temporary files
--http-fastcgi-temp-path=PATH Set path to the http fastcgi temporary files
--without-http 禁⽤ HTTP server
--with-mail 启⽤ IMAP4/POP3/SMTP 代理模块
--with-mail_ssl_module 启⽤ ngx_mail_ssl_module
--with-cc=PATH 指定 C 编译器的路径
--with-cpp=PATH 指定 C 预处理器的路径
--with-cc-opt=OPTIONS Additional parameters which will be added to the variable CFLAGS. With the use of the system library PCRE in FreeBSD, it is necessary to indicate --with-cc-opt="-I /usr/local/include". If we are usyuan select() and it is necessary to increase the number of file descriptors, then this also can be assigned here: --with-cc-opt="-D FD_SETSIZE=2048".
--with-ld-opt=OPTIONS Additional parameters passed to the linker. With the use of the system library PCRE in - FreeBSD, it is necessary to indicate --with-ld-opt="-L /usr/local/lib".
--with-cpu-opt=CPU 为特定的 CPU 编译,有效的值包括: pentium, pentiumpro, pentium3, pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64
--without-pcre 禁⽌ PCRE 库的使⽤。同时也会禁⽌ HTTP rewrite 模块。在 "location" 配置指令中的正则 表达式也需要 PCRE 。
--with-pcre=DIR 指定 PCRE 库的源代码的路径。
--with-pcre-opt=OPTIONS Set additional options for PCRE buildyuan.
--with-md5=DIR Set path to md5 library sources.
--with-md5-opt=OPTIONS Set additional options for md5 buildyuan.
--with-md5-asm Use md5 assembler sources.
--with-sha1=DIR Set path to sha1 library sources.
--with-sha1-opt=OPTIONS Set additional options for sha1 buildyuan.
--with-sha1-asm Use sha1 assembler sources.
--with-zlib=DIR Set path to zlib library sources.
--with-zlib-opt=OPTIONS Set additional options for zlib buildyuan.
--with-zlib-asm=CPU Use zlib assembler sources optimized for specified CPU, valid values are: pentium, pentiumpro
--with-openssl=DIR Set path to OpenSSL library sources
--with-openssl-opt=OPTIONS Set additional options for OpenSSL buildyuan
--with-debug 启⽤调试⽇志
--add-module=PATH Add in a third-party module found in directory PATH

下载

http://nginx.org/en/download.html

wget http://nginx.org/download/nginx-1.23.3.tar.gz
# 解压压缩包
tar zxf nginx-1.23.3.tar.gz

Nginx编译安装

cd nginx-1.23.3
./configure --prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-pcre \
--with-pcre-jit \
--with-threads \
--with-file-aio \
--with-http_sub_module
....
Configuration summary
\+ usyuan system PCRE library
\+ OpenSSL library is not used
\+ usyuan system zlib library
nginx path prefix: "/usr/local/nginx"
nginx binary file: "/usr/local/nginx/sbin/nginx"
nginx modules path: "/usr/local/nginx/modules"
nginx configuration prefix: "/usr/local/nginx/conf"
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
nginx pid file: "/usr/local/nginx/logs/nginx.pid"
nginx error log file: "/usr/local/nginx/logs/error.log"
nginx http access log file: "/usr/local/nginx/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp"

安装报错误的话⽐如: “C compiler cc is not found”,这个就是缺少编译环境,安装⼀下就可以了 yum -y install gcc make gcc-c++ openssl-devel
如果没有error信息,就可以执⾏下边的安装了:

make
make install

nginx测试

运⾏下⾯命令会出现两个结果,⼀般情况nginx会安装在 /usr/local/nginx ⽬录中

cd /usr/local/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

设置全局nginx命令

vim /etc/profile

将下⾯内容添加到 /etc/profile ⽂件中

PATH=$PATH:$HOME/bin:/usr/local/nginx/sbin/

运⾏命令 source /etc/profile 让配置⽴即⽣效。你就可以全局运⾏ nginx 命令了。

开机⾃启动

开机⾃启动⽅法⼀:
编辑 vi /usr/lib/systemd/system/nginx.service ⽂件,没有创建⼀个 touch nginx.service 然后将如下内容根
据具体情况进⾏修改后,添加到nginx.service⽂件中:

cat > /usr/lib/systemd/system/nginx.service <<EOF
[Unit]
Description=nginx
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forkyuan
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload

  • [Unit] :服务的说明
  • Description :描述服务
  • After :描述服务类别
  • [Service] 服务运⾏参数的设置
  • Type=forkyuan 是后台运⾏的形式
  • ExecStart 为服务的具体运⾏命令
  • ExecReload 为重启命令
  • ExecStop 为停⽌命令
  • PrivateTmp=True 表示给服务分配独⽴的临时空间

注意: [Service] 的启动、重启、停⽌命令全部要求使⽤绝对路径。
[Install] 运⾏级别下服务安装的相关设置,可设置为多⽤户,即系统运⾏级别为 3 。
保存退出。
设置开机启动,使配置⽣效:

# 启动nginx服务
systemctl start nginx.service
# 停⽌开机⾃启动
systemctl disable nginx.service
# 查看服务当前状态
systemctl status nginx.service
# 查看所有已启动的服务
systemctl list-units --type=service
# 重新启动服务
systemctl restart nginx.service
# 设置开机⾃启动
systemctl enable nginx.service
# 输出下⾯内容表示成功了
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to
/usr/lib/systemd/system/nginx.service.
systemctl is-enabled servicename.service # 查询服务是否开机启动
systemctl enable *.service # 开机运⾏服务
systemctl disable *.service # 取消开机运⾏
systemctl start *.service # 启动服务
systemctl stop *.service # 停⽌服务
systemctl restart *.service # 重启服务
systemctl reload *.service # 重新加载服务配置⽂件
systemctl status *.service # 查询服务运⾏状态
systemctl --failed # 显示启动失败的服务

注: *代表某个服务的名字,如http的服务名为httpd

开机⾃启动⽅法⼆:

vi /etc/rc.local
# 在 rc.local ⽂件中,添加下⾯这条命令
/usr/local/nginx/sbin/nginx

如果开机后发现⾃启动脚本没有执⾏,你要去确认⼀下rc.local这个⽂件的访问权限是否是可执⾏的,因为rc.local默认是不可执⾏的。修改rc.local访问权限,增加可执⾏权限:

# /etc/rc.local是/etc/rc.d/rc.local的软连接,
chmod +x /etc/rc.d/rc.local

官⽅脚本:https://www.nginx.com/resources/wiki/start/topics/examples/redhatnginxinit/

2.3 二进制安装

http://nginx.org/en/download.html

yum install gcc-c++ pcre pcre-devel zlib zlib-devel penssl openssl-devel
tar czf nginx-1.23.3.tar.gz nginx/
tar xf nginx-1.23.3.tar.gz

三、运维Nginx

3.1 服务管理

# 启动
# /usr/local/nginx/sbin/nginx
nginx

# 重新配置重启
# usr/local/nginx/sbin/nginx -s reload
nginx -s reload

# 关闭进程
# /usr/local/nginx/sbin/nginx -s stop
nginx -s stop

# 平滑关闭nginx
# /usr/local/nginx/sbin/nginx -s quit
nginx -s quit

# 强制停止
pkill -9 nginx

# 查看nginx的安装信息模块
/usr/local/nginx/sbin/nginx -V

3.2 nginx卸载

编译/⼆进制安装卸载
#停⽌nginx
nginx -s stop
#删除
rm -r /usr/local/nginx
rm /usr/lib/systemd/system/nginx.service

编译安装,删除/usr/local/nginx⽬录即可 如果配置了⾃启动脚本,也需要删除。

yum安装卸载

如果通过yum安装,使⽤下⾯命令安装。

yum remove nginx

nginx报错排障解决(个人收集版)

1.返回403

查看是否设防火墙;
是否给文件夹授权;
若都不行则添加 autoindex on; #自动索引

四、Nginx基本配置

  • Nginx配置⽂件
  • Nginx⽇志配置
  • Nginx状态监控
  • Nginx下载站点
  • Nginx访问限制
  • Nginx访问控制
  • Nginx虚拟主机

Nginx配置⽂件

Nginx主配置⽂件 /etc/nginx/nginx.conf 是⼀个纯⽂本类型的⽂件,整个配置⽂件是以 区块 的形式组织的。⼀般,每个 区块以⼀对⼤括号 {} 来表示开始与结束。

1.Main位于nginx.conf配置⽂件的最⾼层
2.Main层下可以有Event、 HTTP层
3.HTTP层下⾯有允许有多个 Server层 , ⽤于对不同的⽹站做不同的配置
4.Server层也允许有多个Location, ⽤于对不同的路径进⾏不同模块的配置

//nginx默认配置语法
user //设置nginx服务的系统使⽤⽤户
worker_processes //⼯作进程, 配置和CPU个数保持⼀致
error_log //错误⽇志, 后⾯接⼊的是路径
pid //Nginx服务启动时的pid
    
//events事件模块
events{ //事件模块
    worker_connections //每个worker进程⽀持的最⼤连接数
    use //内核模型,select,poll,epoll
}
//⾮虚拟主机的配置或公共配置定义在http{}段内, server{}段外
http{
...
	//必须使⽤虚拟机配置站点, 每个虚拟机使⽤⼀个server{}段
    'server'{
        listen 80; //监听端⼝, 默认80
        server_name localhost; //提供服务的域名或主机名

    	//控制⽹站访问路径
        'location'/{
        	root/usr/share/nginx/html; //存放⽹站路径
        	index index.html index.htm; //默认访问⾸⻚⽂件
        }

    	//指定错误代码, 统⼀定义错误⻚⾯, 错误代码重定向到新的Locaiton
        error_page 500 502 503 504/50x.html;
        'location'=/50x.html{
        	root html;
        }
	}
    ...
	//第⼆个虚拟主机配置
    'server'{
     ...
    }
}

Nginx虚拟主机

所谓虚拟主机,在web服务器⾥是⼀个独⽴的⽹站站点,这个站点对应独⽴的域名(也可能是IP或端⼝),具有独⽴的程序及资源⽬录,可以独⽴地对外提供服务供⽤户访问。

搭建之前需要用 Docker自建DNS服务器

配置基于域名虚拟主机

1.创建web站点⽬录
[root@LNMP conf]# mkdir /soft/code/{www,bbs}
[root@LNMP conf]# echo "www.yuansredevsecops.top" > /soft/code/www/index.html
[root@LNMP conf]# echo "bbs.yuansredevsecops.top" > /soft/code/bbs/index.html
2.配置虚拟主机
[root@LNMP conf]# cat conf.d/{www,bbs}.conf
server {
listen 80;
server_name www.yuansredevsecops.top;
root /soft/code/www;
}
server {
listen 80;
server_name bbs.yuansredevsecops.top;
root /soft/code/bbs;
}

# 备份配置文件
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.20230515
egrep -v "^$|.*#" /etc/nginx/nginx.conf.bak.20230515 > /etc/nginx/nginx.conf
# -v是排除 , 排除空格、#等开头的内容

配置不同端⼝访问不同虚拟主机

mkdir -p /soft/code/800{1..2}
echo "8001" > /soft/code/8001/index.html
echo "8002" > /soft/code/8002/index.html
# 仅修改listen监听端⼝即可, 但不能和系统端⼝发⽣冲突
[root@180-143 conf.d]# cat 800*
server {
listen 8001;
root /soft/code/8001;
index index.html index.htm;
}
server {
listen 8002;
root /soft/code/8002;
index index.html index.htm;
}

nginx改了任何配置都需要重启

配置虚拟主机别名

所谓虚拟主机别名,就是虚拟主机设置除了主域名以外的⼀个域名,实现⽤户访问的多个域名对应同⼀个虚拟主机⽹站的功能。

以www.yuansredevsecops.top域名的虚拟主机为例:
为其增加⼀个别名blog.yuansredevsecops.top时,出现⽹站内容和访问www.yuansredevsecops.top是⼀样的,具体配置如下:

# 默认配置
[root@LNMP ~]# vim /etc/nginx/conf.d/www.conf
server {
listen 80;
server_name www.yuansredevsecops.top;
}
# 别名配置
[root@LNMP ~]# vim /etc/nginx/conf.d/www.conf
server {
listen 80;
server_name www.yuansredevsecops.top blog.yuansredevsecops.top;
..
}
# 使⽤Linux下curl测试结果
[root@LNMP conf]# curl blog.yuansredevsecops.top
www.yuansredevsecops.top
[root@LNMP conf]# curl www.yuansredevsecops.top
www.yuansredevsecops.top
# 访问带www和带blog是⼀样的, 除了别名实现也可以通过rewrite实现

Nginx处理用户请求的逻辑

逻辑图:https://www.processon.com/diagramyuan/63f02f33e39b2d4955a8ae1e

Nginx⽇志配置

在学习⽇志之前, 我们需要先了解下HTTP请求和返回

curl -v http://www.baidu.com

image-20230509102632670

Nginx⽇志配置规范

//配置语法: 包括: error.log access.log
Syntax: log_format name [escape=default|json] stryuan ...;
Default: log_format combined "...";
Context: http
//Nginx默认配置
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
//Nginx⽇志变量
$remote_addr //表示客户端地址
$remote_user //http客户端请求nginx认证⽤户名
$time_local //Nginx的时间
$request //Request请求⾏, GET等⽅法、 http协议版本
$status //respoence返回状态码
$body_bytes_sent //从服务端响应给客户端body信息⼤⼩
$http_referer //http上⼀级⻚⾯, 防盗链、⽤户⾏为分析
$http_user_agent //http头部信息, 客户端访问设备
$http_x_forwarded_for //http请求携带的http信息

access.log

127.0.0.1 - - [14/Apr/2023:11:45:47 +0800] "GET / HTTP/1.1" 200 615 "-" "curl/7.29.0"
"-"

应⽤场景

问题排查分析⽇志 错误⽇志 访问⽇志
acess 接⼝业务统计

Nginx状态监控

--with-http_stub_status_module 记录 Nginx 客户端基本访问状态信息
http_stub_status_module是⼀个nginx模块,它提供基于HTTP请求的状态信息。当启⽤该模块时,⽤户可以通过在浏览器中输⼊http://server_address/nginx_status来获取统计信息和性能参数,⽐如活跃的连接数,响应时间和资源使⽤情况。这些数据可⽤于监控和优化nginx服务器的性能。

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

具体配置如下:

/etc/nginx/conf.d/yuansredevsecops.top.conf

server {
listen 80;
server_name yuansredevsecops.top;
root /soft/code/yuan;
index index.html;

	location /nginx_status {
	stub_status on;
	access_log off;
	# 应⽤监控获取指标 白名单
	# allow 127.0.0.1; 只允许
	# deny all; 禁止所有
	}
}

# Nginx_status概述
Active connections:2 #Nginx当前活跃连接数
server accepts handled requests
16 16 19
server表示Nginx处理接收握⼿总次数。
accepts表示Nginx处理接收总连接数。
请求丢失数=(握⼿数-连接数)可以看出,本次状态显示没有丢失请求。
handled requests,表示总共处理了19次请求。
Readyuan Nginx读取数据
Writyuan Nginx写的情况
Waityuan Nginx开启keep-alive⻓连接情况下, 既没有读也没有写, 建⽴连接情况

image-20230516165753616

Nginx下载站点

Nginx默认是不允许列出整个⽬录浏览下载。

Syntax: autoindex on | off;
Default:
autoindex off;
Context: http, server, location

//autoindex常⽤参数
autoindex_exact_size off;
默认为on, 显示出⽂件的确切⼤⼩,单位是bytes。
修改为off,显示出⽂件的⼤概⼤⼩,单位是kB或者MB或者GB。

autoindex_localtime on;
默认为off,显示的⽂件时间为GMT时间。
修改为on, 显示的⽂件时间为⽂件的服务器时间。

charset utf-8,gbk;
默认中⽂⽬录乱码,添加上解决乱码。

配置⽬录浏览功能

/etc/nginx/conf.d/yuansredevsecops.top.conf

//开启⽬录浏览
location /download {
root /soft/code/yuan;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}

image-20230516171812257

应⽤场景

举个例⼦ ⽐如在客户现场⽹络管控⽐较严格,查看⽇志⽐较麻烦,可以通过这种⽅式将⽇志映射出来,这是在没有⽇志收集系统前提下

Nginx访问限制

连接频率限制 limit_conn_module
请求频率限制 limit_req_module

http协议的连接与请求
HTTP是建⽴在TCP, 在完成HTTP请求需要先建⽴TCP三次握⼿(称为TCP连接) ,在连接的基础上在HTTP请求。

HTTP 协议的连接与请求

HTTP协议版本 连接关系
HTTP1.0 TCP不能复⽤
HTTP1.1 顺序性TCP复⽤
HTTP2.0 多路复⽤TCP复⽤

HTTP 请求建⽴在⼀次 TCP 连接基础上
⼀次 TCP 请求⾄少产⽣⼀次 HTTP 请求

Nginx连接限制配置

//Nginx连接限制语法
Syntax: limit_conn_zone key zone=name:size;
Default: —
Context: http

Syntax: limit_conn zone number;
Default: —
Context: http, server, location

//具体配置如下:
http {
//http段配置连接限制, 同⼀时刻只允许⼀个客户端IP连接
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
...
server {
...
location / {
//同⼀时刻只允许⼀个客户端IP连接
limit_conn conn_zone 1;
}

//压⼒测试
yum install -y httpd-tools
ab -n 50 -c 20 http://www.yuansredevsecops.top/index.html

`limit_conn_zone` 指令是 Nginx 提供的限制连接数模块,可以⽤来控制⽤户的连接并发数,避免服务器因为连接过多⽽宕机。该指令⽤于为限制连接数模块中的连接信息分配⼀块共享内存,以便 Nginx 能够在多个 Worker 进程之间共享这些信息。

具体的指令含义如下:
- `limit_conn_zone`: 指定需要分配共享内存的共享内存名字。在本例中为 `conn_zone`。
- `$binary_remote_addr`: 表示客户端 IP 地址对应的⼆进制字符串
- `zone`: 定义了共享内存区域的⼤⼩,这⾥为 10MB。

这条指令的作⽤是:根据客户端 IP 地址来限制每个客户端的连接数不超过某个值,共享内存⽤于跨 Worker 进程储这些连接信息。在本例中,每个客户端最多只能建⽴指定数量的连接。当⼀个客户端建⽴连接时,如果已经有`conn_zone` 内存中该 IP 的连接数超过该值,则 Nginx 将丢弃该连接,从⽽限制了连接数的并发度,防⽌服务器过载。

Nginx 请求限制配置

//压⼒测试
yum install -y httpd-tools
ab -n 50 -c 20 http://127.0.0.1/index.html/Nginx请求限制语法
Syntax: limit_req_zone key zone=name:size rate=rate;
Default: —
Context: http

Syntax: limit_conn zone number [burst=number] [nodelay];
Default: —
Context: http, server, location

//具体配置如下:
http {
//http段配置请求限制, rate限制速率,限制⼀秒钟最多⼀个IP请求
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
...
server {
...
location / {
//1r/s只接收⼀个请求,其余请求拒绝处理并返回错误码给客户端
limit_req zone=req_zone;
//请求超过1r/s,剩下的将被延迟处理,请求数超过burst定义的数量, 多余的请求返回503
#limit_req zone=req_zone burst=3 nodelay;
}

//压⼒测试
yum install -y httpd-tools
ab -n 50 -c 20 http://127.0.0.1/index.html

连接限制没有请求限制有效?

我们前⾯说过, 多个请求可以建⽴在⼀次的TCP连接之上, 那么我们对请求的精度限制,当然⽐对⼀个连接的限制会更加的有效。

因为同⼀时刻只允许⼀个连接请求进⼊。
但是同⼀时刻多个请求可以通过⼀个连接进⼊。
所以请求限制才是⽐较优的解决⽅案。

Nginx访问控制 (用的较多)

基于IP的访问控制 http_access_module
基于⽤户登陆认证 http_auth_basic_module
基于IP的访问控制

//允许配置语法
Syntax: allow address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
//拒绝配置语法
Syntax: deny address | CIDR | unix: | all;
Default: —
Context: http, server, location, limit_except
//配置拒绝某⼀个IP, 其他全部允许 √
location ~ ^/1.html {
index index.html;
deny 192.168.1.129;
allow all;
}
//只允许某⼀个⽹段访问,其它全部拒绝 √
location / {
index index.php index.html index.htm;
allow 10.1.106.0/24;
deny all;
}

基于用户登陆认证

//配置语法
Syntax: auth_basic stryuan| off;
Default: auth_basic off;
Context: http, server, location, limit_except
//⽤户密码记录配置⽂件
Syntax: auth_basic_user_file file;
Default: -
Context: http, server, location, limit_except
 
//设置账号密码才可访问web
//需要安装依赖组件 √
[root@yuan ~]# yum install httpd-tools
[root@yuan ~]# htpasswd -c /etc/nginx/auth_conf yuan
    
//可在http,server,location下添加如下信息 √
auth_basic "Auth access Blog Input your Passwd!";
auth_basic_user_file /etc/nginx/auth_conf;

/etc/nginx/conf.d/yuansredevsecops.top.conf √

location /download {
auth_basic "Auth access Blog Input your Passwd!";
auth_basic_user_file /etc/nginx/auth_conf;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}

⽤户认证局限性
1.⽤户信息依赖⽂件⽅式
2.⽤户管理⽂件过多, ⽆法联动
3.操作管理机械,效率低下

解决办法

1.Nginx 结合 LUA 实现⾼效验证
2.Nginx 结合 LDAP 利⽤ nginx-auth-ldap 模块

Nginx 获取真实客户IP

http_x_forwarded_for 是nginx服务器在处理HTTP请求时⾃动⽣成的⼀个请求头,⽤于标识当前请求的客户端IP地址。该请求头的内容是代理服务器转发请求时,在HTTP头部增加的。

在反向代理服务器中, http_x_forwarded_for 字段记录了客户端的真实IP地址,以⽅便后续的流量监控、统计、分析等⼯作。由于Nginx默认情况下不会启⽤代理协议,所以需要⼿动配置 http_x_forwarded_for 才能正确记录客户端IP地址。

使⽤这个请求头可以帮助开发者判断当前请求的发送来源,并且也可以根据这个字段实现IP地址的过滤、限制和⿊⽩名单等操作。

需要注意的是,由于HTTP请求头部内容可以被伪造,所以 http_x_forwarded_for ⽆法完全保证客户端IP的真实性。因此,在⽤户安全认证等重要场景中,应该使⽤更可靠的⼿段来确保客户端IP地址的真实性,例如使⽤HTTPS协议等。

先说下我们的测试的机器IP分布。

客户端IP 192.168.1.129
负载均衡LB 10.1.106.70
web机器 192.168.1.152

image-20230509155155617

1.客户端使⽤代理服务器访问真实WEB服务器
2.WEB服务器使⽤remote addr能捕捉到代理服务器IP
3.WEB服务器⽆法捕捉真实的客户端IP

下图是使⽤ http_x_forwarded_for 记录真实客户端IP地址以及代理服务器IP

image-20230509155345364

1.客户端使⽤代理服务器访问真实WEB服务器
2.代理服务器开启x_forwarede_for记录客户端真实IP
3.WEB服务器开启x_forwarede_for记录客户端真实IP以及代理服务器IP http x forwarded for =

slb.conf

# Nginx反向代理配置
server {
# 监听的IP和端⼝
listen 80;
# 域名
server_name slb.yuansredevsecops.top;
# 记录⽇志,使⽤⾃定义的log_format
access_log /var/log/nginx/access.log main;
# 设置代理头部
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 正常的反向代理配置
location / {
# 后端Web服务器
proxy_pass http://192.168.1.152;
}
}

解决⽅式
1.采⽤HTTP头信息控制访问, 代理以及web服务开启 http_x_forwarded_for
2.结合geo模块作
3.通过HTTP⾃动以变量传递

五、Nginx静态服务

5.1 静态资源类型

Nginx 作为静态资源 Web 服务器部署配置, 传输⾮常的⾼效, 常常⽤于静态资源处理, 请求, 动静分离

1684848886595

⾮服务器动态运⾏⽣成的⽂件属于静态资源

类型 种类
浏览器端渲染 HTML、 CSS、 JS
图⽚ JPEG、 GIF、 PNG
视频 FLV、 Mp4
⽂件 TXT、任意下载⽂件

5.2 静态资源场景

静态资源传输延迟最⼩化

1684848904369

5.3 静态资源配置语法

1.⽂件读取⾼效 sendfile
Syntax: sendfile on | off;
Default: sendfile off;
Context: http, server, location, if in location

2.提⾼⽹络传输效率 tcp_nopush
Syntax: tcp_nopush on | off;
Default: tcp_nopush off;
Context: http, server, location
作⽤: sendfile开启情况下, 提⾼⽹络包的`传输效率`

3.与 tcp_nopush 之对应的配置 tcp_nodelay
Syntax: tcp_nodelay on | off;
Default: tcp_nodelay on;
Context: http, server, location
作⽤: 在keepalive连接下,提⾼⽹络的传输'实时性'

5.4 静态资源⽂件压缩 √

Nginx 将响应报⽂发送⾄客户端之前可以启⽤压缩功能,这能够有效地节约带宽,并提⾼响应⾄客户端的速度。

1684849120791

1.gzip 压缩配置语法

Syntax: gzip on | off;
Default: gzip off;
Context: http, server, location, if in location

作⽤: 传输压缩

2.gzip 压缩⽐率配置语法

Syntax: gzip_comp_level level;
Default: gzip_comp_level 1;
Context: http, server, location

作⽤: 压缩本身⽐较耗费服务端性能

Nginx 的 `gzip_comp_level` 配置项⽤于设置 Gzip 压缩的压缩级别,可选配置值为 1 到 9,数字越⼤表示压
缩级别越⾼,压缩效果也更好,但相应地会消耗更多的 CPU 资源。

具体来说,每个数字对应的压缩级别如下:

- 1:适合进⾏最快的压缩,但压缩⽐例最低。
- 2:适合进⾏快速压缩,但压缩⽐例略低。
- 3:适合进⾏快速压缩,压缩⽐例⼀般。
- 4:适合进⾏⼀般压缩,压缩⽐例较⾼。
- 5:适合进⾏⼀般压缩,压缩⽐例更⾼。
- 6:适合进⾏较强压缩,但⽐ 5 级慢⼀些,压缩⽐例更⾼。
- 7:适合进⾏较强压缩,但⽐ 6 级慢⼀些,压缩⽐例⾮常⾼。
- 8:适合进⾏⾮常强压缩,但⽐ 7 级慢⼀些,压缩⽐例极⾼。
- 9:适合进⾏最强压缩,但⽐ 8 级慢很多,压缩⽐例最⾼。

默认值为 1,即最快速度进⾏压缩,但压缩⽐例最低,因此在实际应⽤中需要根据实际情况来进⾏调整。例如,对于⾼
带宽、低 CPU 资源的⽹络应⽤来说,可以尝试使⽤较低的压缩级别;⽽对于低带宽、⾼ CPU 资源的⽹络应⽤来说,
可以尝试使⽤较⾼的压缩级别以获取更好的压缩效果。

3.gzip 压缩协议版本

Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;
Context: http, server, location

作⽤: 压缩使⽤在http哪个协议, 主流版本1.1

4.扩展压缩模块

Syntax: gzip_static on | off | always;
Default: gzip_static off;
Context: http, server, location

作⽤: 预读gzip功能

5.图⽚压缩案例

没有压缩的配置

static_server.conf

server {
listen 80;
server_name static.yuansredevsecops.top;
root /soft/code/images;
index index.html index.htm ;
sendfile on;
access_log /var/log/nginx/static_access.log main;
location ~ .*\.(jpg|gif|png)$ {
root /soft/code/images;
}
}

开启 gzip gzip_comp_level 9;

[root@Nginx conf.d]# mkdir -p /soft/code/images
[root@Nginx conf.d]# cat static_server.conf
server {
listen 80;
server_name static.yuansredevsecops.top;
sendfile on;
access_log /var/log/nginx/static_access.log main;
location ~ .*\.(jpg|gif|png)$ {

gzip on;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text/plain application/json application/x-javascript
application/css application/xml application/xml+rss text/javascript application/xhttpd-php image/jpeg image/gif image/png;
root /soft/code/images;

}
}

6.⽂件压缩案例

[root@Nginx conf.d]# mkdir -p /soft/code/doc
[root@Nginx conf.d]# cat static_server.conf
server {
listen 80;
server_name static.yuansredevsecops.top;
sendfile on;
access_log /var/log/nginx/static_access.log main;
location ~ .*\.(txt|xml)$ {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 1;
gzip_types text/plain application/json application/x-javascript application/css
application/xml application/xml+rss text/javascript application/x-httpd-php image/jpeg
image/gif image/png;
root /soft/code/doc;
}
}

5.5 静态资源浏览器缓存

HTTP协议定义的缓存机制(如: Expires; Cache-control 等)

1.浏览器⽆缓存

浏览器请求->⽆缓存->请求WEB服务器->请求响应->呈现

2.浏览器有缓存

浏览器请求->有缓存->校验过期->是否有更新->呈现

校验是否过期 Expires HTTP1.0, Cache-Control(max-age) HTTP1.1

协议中Etag头信息校验 Etag ()
Last-Modified头信息校验 Last-Modified (具体时间)

1.缓存配置语法 expires

Syntax: expires [modified] time;
expires epoch | max | off;
Default: expires off;
Context: http, server, location, if in location

作⽤: 添加Cache-Control Expires头

2.配置静态资源缓存

static_server.conf

location ~ .*\.(js|css|html)$ {
root /soft/code/images;
expires 1h;
}
location ~ .*\.(jpg|gif|png)$ {
root /soft/code/images;
expires 7d;
}

3.开发代码没有正式上线时, 希望静态⽂件不被缓存

//取消js css html等静态⽂件缓存
location ~ .*\.(css|js|swf|json|mp4|htm|html)$ {
add_header Cache-Control no-store;
add_header Pragma no-cache;
}

阿⾥云缓存策略帮助⼿册:https://help.aliyun.com/document_detail/40077.html

Nginx静态资源缓存:http://www.web3.xin/code/1763.html

5.6 静态资源跨域访问 √

1684849808193

浏览器禁⽌跨域访问, 主要不安全, 容易出现 CSRF 攻击

1684849849864

Nginx 跨域访问配置

Syntax: add_header name value [always];
Default: —
Context: http, server, location, if in location

Access-Control-Allow-Origin

1.准备 html ⽂件
//测试origin.yuansredevsecops.top⽹站跨域访问yuan.com
//在origin.yuansredevsecops.top⽹站添加跨越访问⽂件
[root@Nginx ~]# cat /soft/code/origin/http_origin.html
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试ajax和跨域访问</title>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
    //ajax配置 √ 
$.ajax({
type: "GET",
url: "http://yuan.com",
success: function(data) {
alert("sucess!!!");
},
error: function() {
alert("fail!!,请刷新再试!");
}
});
});
</script>
<body>
<h1>测试跨域访问</h1>
</body>
</html>

2.配置 Nginx 跨域访问
//运⾏origin.yuansredevsecops.top域名跨域访问
[root@180-143 conf.d]# cat origin.conf
server {
listen 80;
server_name origin.yuansredevsecops.top;
sendfile on;
access_log /var/log/nginx/kuayu.log main;
location ~ .*\.(html|htm)$ {
root /soft/code/origin;
}
}

yuan.conf

server {
listen 80;
server_name yuan.com;
root /soft/code/yuan.com/;
index index.html index.htm;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Credentials: true;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,UserAgent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}

5.7 静态资源防盗链 √

盗链指的是在⾃⼰的界⾯展示不在⾃⼰服务器上的内容,通过技术⼿段获得他⼈服务器的资源地址,绕过别⼈资源
展示⻚⾯,在⾃⼰⻚⾯向⽤户提供此内容,从⽽减轻⾃⼰服务器的负担,因为真实的空间和流量来⾃别⼈服务器

防盗链设置思路: 区别哪些请求是⾮正常⽤户请求

基于 http_refer 防盗链配置模块

Syntax: valid_referers none | blocked | server_names | stryuan ...;
Default: —
Context: server, location

refer.conf

server {
listen 80;
server_name refer.yuansredevsecops.top ;
root /soft/code/refer/;
index index.html index.htm;
}

1.准备html⽂件
<html>
<head>
<meta charset="utf-8">
<title>pachong</title>
</head>
<body style="background-color:red;">
<img src="http://static.yuansredevsecops.top/gzip_image.png">
</body>
</html>

2.启动防盗链

static_server.conf

//⽀持IP、域名、正则⽅式
location ~ .*\.(jpg|gif|png)$ {
valid_referers none blocked static.yuansredevsecops.top;
if ($invalid_referer) {
return 403;
}
root /soft/code/images;
}

# 压缩图片并启动防盗链
server {
listen 80; 
server_name static.yuansredevsecops.top;
sendfile on; 
access_log /var/log/nginx/static_access.log main;

location ~ .*\.(jpg|gif|png)$ {
gzip on; 
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text/plain application/json application/x-javascript
application/css application/xml application/xml+rss text/javascript application/xhttpd-php image/jpeg image/gif image/png;
root /soft/code/images;
valid_referers none blocked static.yuansredevsecops.top;
if ($invalid_referer) {
return 403;
}
}

}


3.验证
# 返回403
[root@linuxprobe conf.d]# curl  -e 'http://www.baidu.com' static.yuansredevsecops.top/gzip_image.png -l
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>


//伪造协议头访问
yuan-MacBook-Pro:~ egrep $ curl -e "http://www.baidu.com" -I static.yuansredevsecops.top/gzip_image.png
HTTP/1.1 403 Forbidden
Server: nginx/1.24.0
Date: Fri, 14 Apr 2023 11:41:40 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

//伪造协议头访问
yuan-MacBook-Pro:~ egrep $ curl -v -e "http://10.1.106.70" -I
http://10.1.106.70/gzip_image.png
* Tryyuan 10.1.106.70:80...
* Connected to 10.1.106.70 (10.1.106.70) port 80 (#0)
> HEAD /gzip_image.png HTTP/1.1
> Host: 10.1.106.70
> User-Agent: curl/7.85.0
> Accept: */*
> Referer: http://10.1.106.70
>
* Mark bundle as not supportyuan multiuse
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.24.0
Server: nginx/1.24.0
< Date: Fri, 14 Apr 2023 11:42:59 GMT
Date: Fri, 14 Apr 2023 11:42:59 GMT
< Content-Type: image/png
Content-Type: image/png
< Content-Length: 173805
Content-Length: 173805
< Last-Modified: Sun, 02 Apr 2023 11:58:37 GMT
Last-Modified: Sun, 02 Apr 2023 11:58:37 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "64296ded-2a6ed"
ETag: "64296ded-2a6ed"
< Accept-Ranges: bytes
Accept-Ranges: bytes

<
* Connection #0 to host 10.1.106.70 left intact

六、Nginx代理服务

6.1 Nginx代理服务概述

代理我们往往并不陌⽣, 该服务我们常常⽤到如(代理租房、代理收货等等)
那么在互联⽹请求⾥⾯, 客户端⽆法直接向服务端发起请求, 那么就需要⽤到代理服务, 来实现客户端和服务通信
image-20230524162712368
Nginx 作为代理服务可以实现很多的协议代理, 我们主要以 http 代理为主

image-20230524162802479

正向代理(内部上⽹) 客户端<-->代理->服务端

image-20230524163030483

反向代理 客户端->代理<-->服务端

image-20230524162946471

代理区别

区别在于代理的对象不⼀样
正向代理代理的对象是客户端
反向代理代理的对象是服务端

6.1.1 Nginx代理配置语法

1. Nginx 代理配置语法
Syntax: proxy_pass URL;
Default: —
Context: location, if in location, limit_except

http://localhost:8000/uri/
http://192.168.56.11:8000/uri/
http://unix:/tmp/backend.socket:/uri/

proxy_pass 代理后⾯url加/与不加/ 区别
加/ 绝对代理代理
不加/相对路径代理
www.a.com 代理到 proxy_pass http://www.b.com 访问www.a.com/index.html 实际内容
www.b.com/index.html
www.a.com 代理到 proxy_pass http://www.b.com/ 访问www.a.com/index.html 实际内容
www.b.com/

2. 类似于 nopush 缓冲区
//尽可能收集所有头请求,
Syntax: proxy_bufferyuan on | off;
Default:
proxy_bufferyuan on;
Context: http, server, location
//扩展:
proxy_buffer_size
proxy_buffers
proxy_busy_buffer_size

3. 跳转重定向
Syntax: proxy_redirect default;
proxy_redirect off;proxy_redirect redirect replacement;
Default: proxy_redirect default;
Context: http, server, location

proxy_redirectnginx中⽤于重定向代理请求的指令。在正向代理或反向代理模式下,很多情况下需要对响应中的URL进⾏修改,使得它们能够正确的映射到客户端或服务端。

常⻅的场景包括:

  • 负载均衡:多个服务器分担相同的请求,每台服务器返回的相对地址可能不同。
  • URL重写:在客户端请求URI时,使⽤路径、查询字符串或⽚段修改URI。

语法:

proxy_redirect default replacement [flag];

default 参数是被替换的URL,默认情况下nginx不对在响应中出现的 default 字符串进⾏替换。 replacement参数是指重定向⽬标URL。当响应中出现 default 字符串时, nginx将其替换为 replacement 所指定的URL。 flag 参数是可选参数,表示对URL的重新定向⽅式,可以为以下参数之⼀。

  • off :表示禁⽤代理重定向,默认是 off ,即不进⾏重定向。
  • default :使⽤默认⽅式修改URL。默认值。
  • replace :修改所有出现的字符串,⽽不是仅修改⾸个出现的字符串。

例如:

proxy_redirect http://localhost:8080/ http://www.example.com/;

上述指令将响应中所有出现 http://localhost:8080/ 的字符串替换为 http://www.example.com/

需要注意的是, proxy_redirect 并不能⾃动修改响应中的HTML⽂本,也不能修改响应中的JavaScript、 CSS、XML等嵌⼊式资源中的URL。如果需要修改HTML⽂本中的URL,可以使⽤ sub_filter 指令进⾏替换。

4. 头信息
Syntax: proxy_set_header field value;
Default: proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context: http, server, location
//扩展:
proxy_hide_header
proxy_set_body

5. 代理到后端的 TCP 连接超时
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http, server, location
//扩展
proxy_read_timeout //以及建⽴
proxy_send_timeout //服务端请求完, 发送给客户端时间

6. Proxy 常⻅配置项具体配置如下:
[root@Nginx ~]# vim /etc/nginx/proxy_params
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# 超时时间
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

# 性能优化
proxy_buffer_size 32k;
proxy_bufferyuan on;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;

//具体location实现
location / {
proxy_pass http://127.0.0.1:8080;
include proxy_params;
}

6.1.2 Nginx正向代理示例 (了解原理)

Nginx 正向代理配置实例

image-20230524164032747

10.1.106.70 服务器 static_server.conf

//配置10.1.106.70 访问限制,仅允许同⽹段访问
location ~ .*\.(jpg|gif|png)$ {
allow 10.1.106.0/24;
deny all;
root /soft/code/images;
}

192.168.1.152 正向服务器配置

//配置正向代理
[root@Nginx ~]# cat /etc/nginx/conf.d/zy_proxy.conf
server {
listen 80;
resolver 192.168.1.152;
location / {
proxy_pass http://$http_host$request_uri;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
//客户端使⽤SwitchySharp浏览器插件配置正向代理

6.1.3 Nginx反向代理示例

Nginx 反向代理配置实例

image-20230524164250140

反向代理服务器: 10.1.106.70

/proxy代理
[root@proxy ~]# cat /etc/nginx/conf.d/proxy.conf
server {
listen 80;
server_name proxy.yuansredevsecops.top;
index index.html;
location / {
proxy_pass http://192.168.1.152:8080;
include proxy_params;
}
}

服务端或者后端服务 10.1.1.06.66:8080

//WEB站点
[root@Nginx ~]# cat /etc/nginx/conf.d/backend.conf
server {
listen 8080;
server_name 192.168.1.152;
index index.html;
root /soft/code/backend;
}

6.2 Nginx负载均衡

提升吞吐率, 提升请求性能, 提⾼容灾

image-20230524164835556

负载均衡按范围划分:GSLB全局负载均衡、 SLB

image-20230524164917776

Nginx`是⼀个典型的`SLB

image-20230524164953100

负载均衡按层级划分: 分为四层负载均衡和七层负载均衡

Nginx 是⼀个典型的七层 SLB,同时也⽀持4层
1684932630449

6.2.1 Nginx负载均衡配置场景

Nginx 实现负载均衡⽤到了 proxy_pass 代理模块核⼼配置, 将客户端请求代理转发⾄⼀组 upstream 虚拟服务池

1684932673517

Nginx upstream 虚拟配置语法

Syntax: upstream name { ... }
Default: -
Context: http

//upstream例⼦
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}

后端的节点 192.168.1.152

  1. 创建对应 html ⽂件
[root@Nginx ~]# mkdir /soft/{code1,code2,code3} -p
[root@Nginx ~]# cat > /soft/code1/index.html <<EOF
<html>
<title> Code1</title>
<body bgcolor="red">
<h1> Code1-8081 </h1>
</body>
</html>
EOF
[root@Nginx ~]# cat > /soft/code2/index.html <<EOF
<html>
<title> Coder2</title>
<body bgcolor="blue">
<h1> Code1-8082</h1>
</body>
</html>
EOF
[root@Nginx ~]# cat > /soft/code3/index.html <<EOF
<html>
<title> Coder3</title>
<body bgcolor="green">
<h1> Code1-8083</h1>
</body>
</html>
EOF

  1. 建⽴对应的 server.conf 配置⽂件

192.168.1.152

[root@Nginx ~]# cat > /etc/nginx/conf.d/server.conf <<EOF
server {
listen 8081;
root /soft/code1;
index index.html;
}

server {
listen 8082;
root /soft/code2;
index index.html;
}

server {
listen 8083;
root /soft/code3;
index index.html;
}
EOF

  1. 配置 Nginx 反向代理
[root@Nginx ~]# cat > /etc/nginx/conf.d/upsteam_proxy.conf <<EOF
upstream node {
server 192.168.1.152:8081;
server 192.168.1.152:8082;
server 192.168.1.152:8083;
}
server {
server_name upstream.yuansredevsecops.top;
listen 80;
location / {
proxy_pass http://node;
include proxy_params;
}
}
EOF

  1. 使⽤浏览器验证

1684933656325

6.2.2 Nginx负载均衡状态配置

后端服务器在负载均衡调度中的状态

状态 概述
down 当前的server暂时不参与负载均衡
backup 预留的备份服务器
max_fails 允许请求失败的次数
fail_timeout 经过max_fails失败后, 服务暂停时间
max_conns 限制最⼤的接收连接数

backup

当⼀个后端服务器被标记为 backup 时,它将仅作为备⽤服务器使⽤。这意味着在正常情况下, Nginx 不会把请求转发给它,除⾮所有的⾮备⽤服务器都不可⽤。如果所有的⾮备⽤服务器都不可⽤时, Nginx 才会将请求转发给backup 服务器,让它来处理请求。
backup 的作⽤在于,当主要服务器发⽣故障或者出现⾼负载时,备⽤服务器可以代替它来处理请求,保证服务的可⽤性和性能。

max_conns

在配置 Nginx 的 upstream 时,如果⼀个后端服务器出现了性能瓶颈,可能会导致处理速度⽐较慢,甚⾄出现负载过⾼的情况。为了避免这种情况,可以通过限制连接数来保护后端服务器。

当某个后端服务器的 `max_conns` 属性被设置为⼀个⾮零值时, Nginx 将限制与该服务器建⽴的并发连接数量。如果已经存在达到最⼤连接数的活动连接时,进⼀步的连接将会被阻塞或拒绝,以保护后端服务器不会被过多的请求占
⽤。

需要注意的是, `max_conns` 参数并不是⼀个硬性的限制,它只是⼀个建议值。具体的上限取决于后端服务器的实际性能和可⽤资源。如果后端服务器的负载过⾼,可能需要考虑增加服务器的数量或者提升服务器的硬件配置来提⾼处理能⼒。
另外,对于 Nginx 的 `max_conns` 参数,可以在 `http`、 `server` 和 `location` 块中进⾏配置,以适应不同的场景需求。

测试 backup 以及 down 状态

upstream load_pass {
server 192.168.1.152:8081 down;
server 192.168.1.152:8082 backup;
server 192.168.1.152:8083 max_fails=1 fail_timeout=10s;
}
location / {
proxy_pass http://load_pass;
include proxy_params;
}
//关闭8003测试

6.2.3 Nginx负载均衡调度策略

调度算法 概述
RR轮询 按时间顺序逐⼀分配到不同的后端服务器(默认)
weight 加权轮询,weight值越⼤,分配到的访问⼏率越⾼
ip_hash 每个请求按访问IP的hash结果分配,这样来⾃同⼀IP的固定访问⼀个后端服务器(应用于比较老的服务 pip)
url_hash 按照访问URL的hash结果来分配请求,是每个URL定向到同⼀个后端服务器
least_conn 最少链接数,那个机器链接数少就分发
hash关键数值 hash⾃定义的key

Nginx负载均衡权重轮询具体配置

nginx.conf

upstream load_pass {
server 192.168.1.152:8081;
server 192.168.1.152:8082 weight=5;
server 192.168.1.152:8083;
}

Nginx负载均衡 ip_hash 具体配置

nginx.conf

//如果客户端都⾛相同代理, 会导致某⼀台服务器连接过多
upstream load_pass {
ip_hash;
server 192.168.1.152:8081;
server 192.168.1.152:8082;
server 192.168.1.152:8083;
}
//如果出现通过代理访问会影响后端节点接收状态均衡

Nginx负载均衡url_hash具体配置

nginx.conf

upstream load_pass {
hash $request_uri;
server 192.168.1.152:8081;
server 192.168.1.152:8082;
server 192.168.1.152:8083;
}
//针对三台服务器添加相同⽂件
/soft/code1/url1.html url2.html url3.html
/soft/code2/url1.html url2.html url3.html
/soft/code3/url1.html url2.html url3.html
echo "url1 8081" > /soft/code1/url1.html
echo "url2 8081" > /soft/code1/url2.html
echo "url3 8081" > /soft/code1/url3.html
echo "url1 8082" > /soft/code2/url1.html
echo "url2 8082" > /soft/code2/url2.html
echo "url3 8082" > /soft/code2/url3.html
echo "url1 8083" > /soft/code3/url1.html
echo "url2 8083" > /soft/code3/url2.html
echo "url3 8083" > /soft/code3/url3.html

6.2.4 Nginx负载均衡TCP配置

Nginx 四层代理仅能存在于 main

nginx.conf

stream {
upstream ssh_proxy {
hash $remote_addr consistent;
server 192.168.1.152:5522;
}
upstream mysql_proxy {
hash $remote_addr consistent;
server 192.168.1.152:3306;
}
server {
listen 6666;
proxy_connect_timeout 1s;
proxy_timeout 300s;
proxy_pass ssh_proxy;
}
server {
listen 5555;
proxy_connect_timeout 1s;
proxy_timeout 300s;
proxy_pass mysql_proxy;
}
}

检查是否安装stream模块

[root@180-143 conf.d]# nginx -V 2>&1 |egrep -o "\-\-with-stream"
--with-stream
--with-stream
--with-stream
--with-stream

192.168.1.152 启动mysql

docker run -p 3306:3306 --name mysql -di -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

6.3 Nginx动静分离 √

动静分离,通过中间件将动态请求和静态请求进⾏分离, 分离资源, 减少不必要的请求消耗, 减少请求延时。
好处: 动静分离后, 即使动态服务不可⽤, 但静态资源不会受到影响

通过中间件将动态请求和静态请求分离

1684934263856

6.3.1 Nginx动静分离应用案例 √

1684934314327

  1. 环境准备
系统 服务 地址
CentOS7.4 proxy 192.168.1.170
CentOS7.4 Nginx 静态资源服务器 192.168.1.152
CentOS7.4 Tomcat 动态服务器 192.168.1.152
  1. 在 192.168.1.152 静态资源
[root@Nginx conf.d]# cat access.conf
server{
listen 80;
server_name access.yuansredevsecops.top;
root /soft/code/access/;
index index.html;
location ~ .*\.(png|jpg|gif)$ {
gzip on;
root /soft/code/images;
}
}
//准备⽬录, 以及静态相关图⽚
[root@Nginx ~]# wget -O /soft/code/images/nginx.png http://nginx.org/nginx.png

  1. 在 192.168.1.152 准备动态资源
#在官方拉取镜像
[root@Nginx ~]# docker pull tomcat:9.0.56-jdk8-temurin-focal
[root@Nginx ~]# docker run -d -p8090:8080 tomcat:9.0.56-jdk8-temurin-focal

#进入正在运行的容器
[root@Nginx soft]# docker exec -it competent_turyuan /bin/bash
#若没运行则
[root@localhost conf.d]# docker run -it fa05adc4a95b /bin/bash

root@28072b811532:/usr/local/tomcat# cd webapps
root@64bb55b5e1af:/usr/local/tomcat/webapps# mkdir -p ROOT
root@64bb55b5e1af:/usr/local/tomcat/webapps# cd ROOT
root@64bb55b5e1af:/usr/local/tomcat/webapps#/ROOT# cat > java_test.jsp <<EOF
<%@ page language="java" import="java.util.*" pageEncodyuan="utf-8"%>
<HTML>
<HEAD>
<TITLE>JSP Test Page</TITLE>
</HEAD>
<BODY>
<%
Random rand = new Random();
out.println("<h1>Random number:</h1>");
out.println(rand.nextInt(99)+100);
%>
</BODY>
</HTML>
EOF

  1. 10.1.106.70 配置负载均衡代理调度, 实现访问 jsppng

upsteam_proxy.conf

upstream static {
server 192.168.1.152:80;
}

upstream java {
server 192.168.1.152:8090;
}

server {
listen 80;
server_name upstream.yuansredevsecops.top;
root /soft/code/access/ ;
location / {
root /soft/code/access/;
index index.html;
}

location ~ .*\.(png|jpg|gif)$ {
proxy_pass http://static;
include proxy_params;
}

location ~ .*\.jsp$ {
proxy_pass http://java;
include proxy_params;
}

}

测试静态资源

image-20230526103915233

测试动态资源:

1684934568399

  1. 10.1.1.06.70 proxy 代理上编写动静整合 html ⽂件
[root@Nginx ~]# cat /soft/code/access/mysite.html
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试ajax和跨域访问</title>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type: "GET",
url: "http://upstream.yuansredevsecops.top/java_test.jsp",
success: function(data) {
$("#get_data").html(data)
},
error: function() {
alert("fail!!,请刷新再试!");
}
});
});
</script>
<body>
<h1>测试动静分离</h1>
<img src="http://upstream.yuansredevsecops.top/nginx.png">
<div id="get_data"></div>
</body>
</html>

image-20230526103757327

当停⽌ Nginx 后, 强制刷新⻚⾯会发现静态内容⽆法访问, 动态内容依旧运⾏正常

1684934994848

当停⽌ tomcat 后, 静态内容依旧能正常访问, 动态内容将不会被请求到

1684935017003

6.3.2 Nginx⼿机电脑应用案例

根据不同的浏览器, 以及不同的⼿机, 访问的效果都将不⼀样。

//通过浏览器来分别连接不同的浏览器访问不同的效果。
http {
...
upstream firefox {
server 192.168.1.152:80;
}
upstream chrome {
server 192.168.1.152:8080;
}
upstream iphone {
server 192.168.1.152:8080;
}
upstream android {
server 192.168.1.152:8081;
}
upstream default {
server 192.168.1.152:80;
}
...
}

//server根据判断来访问不同的⻚⾯
server {
listen 80;
server_name www.yuan.com;
#safari浏览器访问的效果
location / {
if ($http_user_agent ~* "Safari"){
proxy_pass http://dynamic_pools;
}

#firefox浏览器访问效果
if ($http_user_agent ~* "Firefox"){
proxy_pass http://static_pools;
}

#chrome浏览器访问效果
if ($http_user_agent ~* "Chrome"){
proxy_pass http://chrome;
}

#iphone⼿机访问效果
if ($http_user_agent ~* "iphone"){
proxy_pass http://iphone;
}

#android⼿机访问效果
if ($http_user_agent ~* "android"){
proxy_pass http://and;
}

#其他浏览器访问默认规则
proxy_pass http://dynamic_pools;
include proxy.conf;
}
}
}

1684935159280

七、Nginx缓存服务

7.1 缓存配置语法

proxy_cache 配置语法

Syntax: proxy_cache zone | off;
Default: proxy_cache off;
Context: http, server, location

//缓存路径
Syntax: proxy_cache_path path [levels=levels]
[use_temp_path=on|off] keys_zone=name:size [inactive=time]
[max_size=size] [manager_files=number] [manager_sleep=time][manager_threshold=time]
[loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default: —
Context: http

缓存过期周期

Syntax: proxy_cache_valid [code ...] time;
Default: —
Context: http, server, location
//示例
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;

  • code :返回的 HTTP 状态码,如200(成功), 404(未找到)等,也可以⽤ any 表示任何状态码。
  • time :缓存的有效时间,可以使⽤以下格式:
    • 秒数。例如: proxy_cache_valid 200 60s; 表示 对状态码为200的请求进⾏缓存,有效时间为60秒。
    • 分钟数。例如: proxy_cache_valid 200 5m; 表示 对状态码为200的请求进⾏缓存,有效时间为5分钟。
    • ⼩时数。例如: proxy_cache_valid 200 2h; 表示 对状态码为200的请求进⾏缓存,有效时间为2⼩时。
    • 天数。例如: proxy_cache_valid 200 1d; 表示 对状态码为200的请求进⾏缓存,有效时间为1天。
    • 多个时间。例如: proxy_cache_valid 200 3h 5m; 表示 对状态码为200的请求进⾏缓存,有效时间为3⼩时5分钟。

可以在 server、 location 等上下⽂中使⽤该指令。在 location 上下⽂中使⽤时,可以设置三种不同状态码的缓时间:

  • 1xx, 2xx, 3xx: syntax: proxy_cache_valid [code] time1 [time2];
  • 4xx, 5xx: syntax: proxy_cache_valid [code] time;
  • any :表示任意状态码。

缓存的维度

Syntax: proxy_cache_key stryuan;
Default: proxy_cache_key $scheme$proxy_host$request_uri;
Context: http, server, location

//示例
proxy_cache_key "$host$request_uri $cookie_user";
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
proxy_cache_key $host$uri$is_args$args

proxy_cache_key 是 Nginx 中⽤于设置缓存 Key 的指令,可以⽤来控制哪些请求会被缓存以及如何组成缓存
Key。⽽ $host$uri$is_args$args 是⼀种 Nginx 内置的变量,它们分别表示请求的 Host、 URI、是否带有 ?
以及请求参数。

因此, proxy_cache_key \(host\)uri\(is_args\)args 这条指令表示使⽤ $host$uri$is_args
$args 四个变量作为⽣成缓存 Key 的基础,并按照这个顺序组合成⼀个字符串,作为具体的缓存 Key。这样,同
⼀请求的不同参数就会⽣成不同的缓存 Key,从⽽保证缓存的准确性和有效性。

注意的是, proxy_cache_key 的设置应该根据具体业务场景进⾏调整,以达到最佳的缓存效果。在⼀些没
有参数的静态资源请求中,可以只使⽤ $host$uri 作为缓存 Key,⽽在有参数或者情况较为复杂的请求
中,需要使⽤更多的变量来⽣成缓存 Key。

7.2 缓存配置实践 √

1.缓存准备

系统 服务 地址
CentOS7.4 Nginx Proxy Cache 代理cache服务器 10.1.106.70
CentOS7.4 Nginx Web 后端 192.168.1.152

2.web节点准备

192.168.1.152

//建⽴相关⽬录
[root@nginx ~]# mkdir -p /soft/code{1..3}
//建⽴相关html⽂件
[root@nginx ~]# for i in {1..3};do echo Code1-Url$i > /soft/code1/url$i.html;done
[root@nginx ~]# for i in {1..3};do echo Code2-Url$i > /soft/code2/url$i.html;done
[root@nginx ~]# for i in {1..3};do echo Code3-Url$i > /soft/code3/url$i.html;done

//配置Nginx
[root@nginx ~]# cat /etc/nginx/conf.d/server.conf
server {
listen 8081;
root /soft/code1;
index index.html;
}
server {
listen 8082;
root /soft/code2;
index index.html;
}
server {
listen 8083;
root /soft/code3;
index index.html;
}

//检查监听端⼝
[root@nginx ~]# netstat -lntp|grep 80
tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN
50922/nginx: master
tcp 0 0 0.0.0.0:8082 0.0.0.0:* LISTEN
50922/nginx: master
tcp 0 0 0.0.0.0:8083 0.0.0.0:* LISTEN
50922/nginx: master

2.代理配置缓存

10.1.106.70

[root@proxy ~]# mkdir /soft/cache
[root@proxy ~]# cat /etc/nginx/conf.d/proxy_cache.conf
upstream cache {
server 192.168.1.152:8081;
server 192.168.1.152:8082;
server 192.168.1.152:8083;
}

#proxy_cache存放缓存临时⽂件
#levels 按照两层⽬录分级
#keys_zone 开辟空间名, 10m:开辟空间⼤⼩, 1m可存放8000key
#max_size 控制最⼤⼤⼩, 超过后Nginx会启⽤淘汰规则
#inactive 60分钟没有被访问缓存会被清理
#use_temp_path 临时⽂件, 会影响性能, 建议关闭
proxy_cache_path /soft/cache levels=1:2 keys_zone=code_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
listen 80;
server_name cache.yuansredevsecops.top;
#proxy_cache 开启缓存
#proxy_cache_valid 状态码200|304的过期为12h, 其余状态码10分钟过期
#proxy_cache_key 缓存key
#add_header 增加头信息, 观察客户端respoce是否命中
#proxy_next_upstream 出现502-504或错误, 会跳过此台服务器访问下台
location / {
                proxy_pass http://cache;
                proxy_cache_key $host$uri$is_args$args;
                proxy_cache code_cache;
                proxy_cache_valid 200 304 12h;
                proxy_cache_valid any 10m;
                add_header Nginx-Cache "$upstream_cache_status";
                proxy_next_upstream error timeout invalid_header http_500 http_502 http_503  http_504;
                include proxy_params;
        }
}

3.客户端测试

//
[root@nginx ~]# curl -s -I http://cache.yuansredevsecops.top/url3.html|grep "Nginx-Cache"
Nginx-Cache: MISS

//命中
[root@nginx ~]# curl -s -I http://cache.yuansredevsecops.top/url3.html|grep "Nginx-Cache"
Nginx-Cache: HIT

7.4 缓存清理实践 √

Nginx缓存及使⽤ngx_cache_purge进⾏缓存清除 :https://www.jianshu.com/p/1a89ab25ea78

如何清理 proxy_cache 代理缓存

  1. rm 删除已缓存数据
[root@proxy ~]# rm -rf /soft/cache/*
[root@proxy ~]# curl -s -I http://cache.yuansredevsecops.top/url3.html |grep "Nginx-Cache"
Nginx-Cache: MISS

  1. 通过 ngx_cache_purge 扩展模块清理, 需要编译安装 Nginx
//建⽴对应⽬录
[root@proxy ~]# mkdir /soft/src
[root@proxy ~]# cd /soft/src

//下载Nginx包
[root@proxy ~]# wget http://nginx.org/download/nginx-1.21.0.tar.gz
[root@proxy ~]# tar xf nginx-1.21.0.tar.gz

//下载ngx_cache_purge
[root@proxy ~]# wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
[root@proxy ~]# tar -zxvf 2.3.tar.gz

//编译Nginx
[root@nginx src]# cd nginx-1.21.0/ && ./configure --prefix=/etc/softwares/nginx \
--with-http_stub_status_module \
--with-http_ssl_module --with-stream \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-pcre \
--add-module=/soft/src/ngx_cache_purge-2.3 
[root@nginx src]# make && make install

//需要将上⽂的缓存proxy_cache.conf⽂件拷⻉⾄源码包中
[root@linuxprobe conf]# pwd
/etc/softwares/nginx/conf
[root@linuxprobe conf]# cp /etc/nginx/conf.d/proxy_cache.conf ./
//并增加如下内容
[root@linuxprobe conf]# vim proxy_cache.conf
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 192.168.1.0/24;
deny all;
proxy_cache_purge code_cache $host$1$is_args$args;
}

//检测配置重新加载
[root@nginx conf.d]# /etc/softwares/nginx/sbin/nginx -t
[root@nginx conf.d]# /etc/softwares/nginx/sbin/nginx -s reload

使⽤浏览器访问建⽴缓存

1685168215822

通过 purge 请求对应的缓存数据,自动清理缓存

1685168250223

再次刷新就会 404 因为缓存内容已清理

1685168264496

#若访问失败则检查nginx.conf配置文件并授权
[root@linuxprobe logs]# cat /etc/softwares/nginx/conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include ./conf.d/*.conf;
}
[root@linuxprobe logs]# chmod 777 -R /soft/cache/
#检查配置文件存放位置,必须在conf.d文件夹下
[root@linuxprobe conf.d]# ls
proxy_cache.conf
[root@linuxprobe conf.d]# pwd
/etc/softwares/nginx/conf/conf.d
[root@linuxprobe logs]# mkdir -p conf.d

7.5 部分页面不缓存 √

指定部分⻚⾯不进⾏ proxy_Cache 缓存

cat proxy_cache.conf
upstream cache{
server 192.168.1.152:8081;
server 192.168.1.152:8082;
server 192.168.1.152:8083;
}

proxy_cache_path /soft/cache levels=1:2 keys_zone=code_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
listen 80;
server_name cache.yuansredevsecops.top;
#选择清理url3缓存
if ($request_uri ~ ^/(url3|login|register|password)) {
set $cookie_nocache 1;
}

location / {
proxy_pass http://cache;
proxy_cache code_cache;
proxy_cache_valid 200 304 12h;
proxy_cache_valid any 10m;
proxy_cache_key $host$uri$is_args$args;
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
proxy_no_cache $http_pargma $http_authorization;
add_header Nginx-Cache "$upstream_cache_status";
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
include proxy_params;
}

}

//清理缓存
[root@nginx ~]# rm -rf /soft/cache/*

//请求测试
[root@nginx ~]# curl -s -I http://cache.yuansredevsecops.top/url3.html|grep "Nginx-Cache"
Nginx-Cache: MISS
[root@nginx ~]# curl -s -I http://cache.yuansredevsecops.top/url3.html|grep "Nginx-Cache"
Nginx-Cache: MISS
[root@nginx ~]# curl -s -I http://cache.yuansredevsecops.top/url3.html|grep "Nginx-Cache"
Nginx-Cache: MISS

7.6 缓存日志记录统计 √

通过⽇志记录 proxy_cache 命中情况与对应 url

//修改/etc/nginx/nginx.conf中log_format格式
log_format main '$http_user_agent' '$request_uri' '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"' '"$upstream_cache_status"';
//修改proxy_cache.conf, 在server标签新增access⽇志
access_log /var/log/nginx/proxy_cache.log main;

//使⽤curl访问, 最后检查⽇志命令情况
[root@linuxprobe ~]#  curl -s -I http://cache.yuansredevsecops.top/url3.html|grep "Nginx-Cache"
Nginx-Cache: MISS
[root@linuxprobe ~]#  curl -s -I http://cache.yuansredevsecops.top/url1.html|grep "Nginx-Cache"
Nginx-Cache: HIT
[root@linuxprobe ~]# tailf /var/log/nginx/proxy_cache.log
curl/7.29.0/url3.html192.168.1.170 - - [31/May/2023:16:39:20 +0800] "HEAD /url3.html HTTP/1.1" 200 0 "-" "curl/7.29.0" "-""MISS"
curl/7.29.0/url1.html192.168.1.170 - - [31/May/2023:16:39:25 +0800] "HEAD /url1.html HTTP/1.1" 200 0 "-" "curl/7.29.0" "-""HIT"

实验完成以后将nginx 停⽌

/etc/softwares/nginx/sbin/nginx -s stop

八、Nginx rewrite (用的较多)

url组成说明

URL组成 http://www.yuansredevsecops.top/download?name=docker.pdf

这个URL的格式可以分为以下⼏个部分:

  1. 协议部分:指定了访问资源的协议,这个URL使⽤了默认的协议HTTP、 HTTPS。
  2. 域名部分:指定服务器的域名和顶级域名,这个URL的域名部分是www.yuansredevsecops.top。
  3. 路径部分:指定了服务器上要访问的资源的路径,这个URL的路径部分是/download。
  4. 查询部分:包含了向服务器请求资源时所附带的数据,以键值对的形式进⾏传递,这个URL的查询部分是name=docker.pdf。

因此,这个URL的格式可以表示为:

http://www.yuansredevsecops.top/download?name=docker.pdf

协议部分使⽤了默认的HTTP协议,域名部分为www.yuansredevsecops.top,路径部分为/download,查询部分为name=docker.pdf。

8.1 Rewrite基本概述

rewrite 主要实现 url 地址重写, 以及重定向.

Rewrite使用场景

1.URL访问跳转: ⽀持开发设计, ⻚⾯跳转, 兼容性⽀持, 展示效果 www.yuansredevsecops.top/a.html 实际www.yuansredevsecops.top/b.html

2.SEO优化: 依赖于url路径,以便⽀持搜索引擎录⼊

3.维护: 后台维护, 流量转发等

4.安全: 伪静态,真实动态⻚⾯进⾏伪装

8.2 Rewrite配置语法

Syntax: rewrite regex replacement [flag];
Default: --
Context: server, location, if
//所有请求转发⾄/pages/maintain.html
rewrite ^(.*)$ /pages/maintain.html break;

正则表达式

表达式
. 匹配除换⾏符以外的任意字符
重复0次或1次
+ 重复1次或更多次
* 代表重复零次或多次。它⽤于匹配前⾯的字符、字符集或⼦表达式零次或多次。
\d 匹配数字
^ 匹配字符串的开始
$ 匹配字符串的结尾
重复n次
重复n此或更多次
[c] 匹配单个字符c
[a-z] 匹配a-z⼩写字⺟的任意⼀个

正则表达式中特殊字符

\ 转义字符
rewrite index\.php$ /pages/maintain.html break;

() ⽤于匹配括号之间的内容, 通过$1,$2调⽤
if ($http_user_agent ~ Chrome){
rewrite ^(.*)$ /chrome/$1 break;
}

正则表达式终端测试⼯具 √

[root@Nginx ~]# yum install -y pcre-tools
[root@Nginx ~]# pcretest
PCRE version 8.32 2012-11-30

re> /(\d+)\.(\d+)\.(\d+)\.(\d+)/
data> 192.168.56.11
0: 192.168.56.11
1: 192
2: 168
3: 56
4: 11

8.3 Rewrite标记Flag √

flag
last 停⽌rewrite检测 表示完成重写,不在对后⾯的规则进⾏匹配,重新对重写后的 URL 执⾏⼀ 次 URI 重写
break 停⽌rewrite检测 表示完成重写后,不再对后⾯的规则进⾏匹配,直接使⽤新的 URL 请求对 应的资源
redirect 返回302临时重定向, 地址栏会显示跳转后的地址 表示发出⼀个 HTTP 重定向,即通过 301 或 302 状态码将客户端重定向到新的 URL
permanent 返回301永久重定向, 地址栏会显示跳转后的地址 表示发出⼀个永久 HTTP 重定向,即通过 301 状态码将客户端永久性地重定向到新的 URL

对⽐flag中 break last

#创建站点目录
[root@linuxprobe ~]# mkdir /soft/code/rewrite
#配置break会返回404,重写test不会响应202请求
[root@Nginx ~]# cat /etc/nginx/conf.d/rewrite.conf
server {
listen 80;
server_name rewrite.yuansredevsecops.top;
root /soft/code;
location ~ ^/break{
rewrite ^/break /testc/ break;
}
#以last开头的都会重写到test随后响应200
location ~ ^/last{
rewrite ^/last /test/ last;
}
location /test/{
default_type application/json;
return 200 '{"status":"success"}';
}
}

测试 break

1685170655365

测试 last

1685170663589

last break对⽐总结:

last会新建⽴⼀个请求, 请求域名+/test
break匹配后不会进⾏匹配, 会查找对应root站点⽬录下包含/test⽬录

对⽐flag中 redirect permanent

[root@Nginx ~]# cat /etc/nginx/conf.d/rewrite.conf
server {
listen 80;
server_name rewrite.yuansredevsecops.top;
root /soft/code;
location ~ ^/yuan {
rewrite ^/yuan https://yuque.com/egrep redirect;
#rewrite ^/yuan https://yuque.com/egrep permanent;
}
}

测试 Nginxredirect

1685170757525

nginx -s stop 停⽌Nginx服务

1685170785833

测试 Nginx permanent

1685170809168

8.4 Rewrite使⽤场景 √

ls /soft/code/course/11/22/course_33.html
server {
listen 80;
server_name rewrite.yuansredevsecops.top;
root /soft/code/;
location / {
rewrite ^/course-(\d+)-(\d+)-(\d+)\.html /course/$1/$2/course_$3.html break;
}
location ~ ^/yuan {
# rewrite ^/yuan https://yuque.com/egrep redirect;
rewrite ^/yuan https://yuque.com/egrep permanent;
}
}

rewrite.yuansredevsecops.top/course-11-22-33.html

第⼆种场景

if ($http_user_agent ~* Chrome){
rewrite ^/nginx https://www.yuque.com/egrep redirect;
}

8.5 Rewrite额外补充

Rewrite 匹配优先级

1.执⾏server块的rewrite指令
2.执⾏location匹配
3.执⾏选定的location中的rewrite

Rewrite 优雅书写

server {
listen 80;
server_name www.yuan.com yuan.com;
if ($http_host = nginx.org){
rewrite (.*) http://www.yuan.com$1;
}
}

//改良版
server {
listen 80;
server_name yuan.com;
rewrite ^ http://www.yuan.com$request_uri?;
}

server {
listen 80;
server_name www.yuan.com;
}

九、Nginx HTTPS

9.1 HTTPS基本概述

为什么需要使⽤HTTPS, 因为HTTP不安全

1.传输数据被中间⼈盗⽤, 信息泄露
2.数据内容劫持, 篡改

9.2 HTTPS配置语法

Syntax: ssl on | off;
Default: ssl off;
Context: http, server

Syntax: ssl_certificate file;
Default: —
Context: http, server

Syntax: ssl_certificate_key file;
Default: —
Context: http, server

9.3 HTTPS配置场景 √

配置苹果要求的证书

1.服务器所有连接使⽤TLS1.2以上版本(openssl 1.0.2)
2.HTTPS证书必须使⽤SHA256以上哈希算法签名
3.HTTPS证书必须使⽤RSA 2048位或ECC256位以上公钥算法
4.使⽤前向加密技术

秘钥⽣成操作步骤

1.⽣成key密钥
2.⽣成证书签名请求⽂件(csr⽂件)
3.⽣成证书签名⽂件(CA⽂件)

1.检查当前环境

//openssl必须是1.0.2
[root@Nginx ~]# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017

//nginx必须有ssl模块
[root@Nginx ~]# nginx -V
--with-http_ssl_module

[root@Nginx ~]# mkdir /etc/nginx/ssl_key -p
[root@Nginx ~]# cd /etc/nginx/ssl_key

2.创建私钥

[root@Nginx ssh_key]# openssl genrsa -idea -out server.key 2048
Generatyuan RSA private key, 2048 bit long modulus
.....+++
//记住配置密码, 我这⾥是1234
Enter pass phrase for server.key:
Verifyyuan - Enter pass phrase for server.key:

3.⽣成使⽤签名请求证书和私钥⽣成⾃签证书

[root@Nginx ssl_key]# openssl req -days 36500 -x509 \
-sha256 -nodes -newkey rsa:2048 -keyout server.key -out server.crt

Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:BJ
Organization Name (eg, company) [Default Company Ltd]:WING
Organizational Unit Name (eg, section) []:WING
Common Name (eg, your name or your server's hostname) []:yuan.com
Email Address []: yuanyuanot@qq.com

国家名称(2个字⺟代码) [XX]: CN
州或省名称(全名) []: BJ
地区名称(如城市) [默认城市]: BJ
组织名称(如公司)【Default company Ltd】: WING
组织单位名称(如部⻔) []: WING
通⽤名称(例如,您的姓名或服务器的主机名) []: sre.yuan.com
电⼦邮件地址[]: yuanyuanot@qq.com

4.配置 Nginx

[root@Nginx ~]# cat /etc/nginx/conf.d/yuan.conf
server {
listen 443 ssl;
server_name sre.yuan.com;
root /soft/code/yuan.com/ ;
index index.html index.htm;
#ssl_session_cache share:SSL:10m;
ssl_session_timeout 10m;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
ssl_ciphers ECDHE-RSA-AES128-GCMSHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}

5.测试访问, 由于该证书⾮第三⽅权威机构颁发,⽽是我们⾃⼰签发的,所以浏览器会警告

https://sre.yuan.com/

image-20230601153827275

6.以上配置如果⽤户忘记在浏览器地址栏输⼊ https:// 那么将不会跳转⾄ https , 需要将访问 http 强制跳
转 https

[root@Nginx ~]# cat /etc/nginx/conf.d/yuan.conf
server {
listen 443 ssl;
server_name sre.yuan.com;
root /soft/code/yuan.com/ ;
index index.html index.htm;
#ssl_session_cache share:SSL:10m;
ssl_session_timeout 10m;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
ssl_ciphers ECDHE-RSA-AES128-GCMSHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}
server {
listen 80;
server_name sre.yuan.com;
rewrite ^(.*) https://$server_name$1 redirect;
}

7.检查是否⽀持苹果要求 ATS 协议

#仅能在苹果终端上使⽤
$ nscurl --ats-diagnostics --verbose https://192.168.69.113

9.4 Https公有云实践(免费买域名)√

yuansredevsecops.top
在云上签发各品牌数字证书,实现⽹站 HTTPS 化,使⽹站可信,防劫持、防篡改、防监听。并进⾏统⼀⽣命周期管理,简化证书部署,⼀键分发到云上产品。

image-20230601154017272

image-20230601154057372

上传阿⾥云证书, 并解压

[root@Nginx ssl_key]# rz
rz waityuan to receive.
Startyuan zmodem transfer. Press Ctrl+C to cancel.
Transferryuan 10257519_yuansredevsecops.top_nginx.zip...
100% 	3 KB 	3 KB/sec 	00:00:01	 0 Errors

//解压
[root@Nginx ssl_key]# unzip 10257519_yuansredevsecops.top_nginx.zip
[root@linuxprobe ssl_key]# ls
10257519_yuansredevsecops.top_nginx.zip  yuansredevsecops.top.key
server.crt                               yuansredevsecops.top.pem

配置 nginx https

[root@Nginx conf.d]# cat yuansredevsecops.top.conf
server {
listen 443 ssl;
server_name yuansredevsecops.top;
index index.html index.htm;
root /soft/code/yuan;
ssl_session_timeout 10m;
ssl_certificate ssl_key/10257519_yuansredevsecops.top.pem;
ssl_certificate_key ssl_key/10257519_yuansredevsecops.top.key;
ssl_ciphers ECDHE-RSA-AES128-GCMSHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}
server {
listen 80;
server_name yuansredevsecops.top;
rewrite ^(.*) https://$server_name$1 redirect;
}

测试访问

image-20230602113355961

苹果ATS - 证书选择及配置:
https://help.aliyun.com/document_detail/48151.html?spm=5176.2020520163.cas.40.21a92b7a90gqip

十、LNMP动态⽹站

10.1 安装LNMP架构

yum安装 nginx1.24.0 php7.2 Mriadb5.7

1.安装 Nginx

//1.使⽤Nginx官⽅提供的rpm包
[root@nginx ~]# cat /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
//2.执⾏yum安装
[root@nginx ~]# yum install nginx -y
[root@nginx ~]# systemctl start nginx
[root@nginx ~]# systemctl enable nginx

2.使⽤第三⽅扩展epel源安装php7.2

//移除旧版php
[root@nginx ~]# yum remove php-mysql-5.4 php php-fpm php-common

//安装扩展源
[root@nginx ~]# rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
[root@nginx ~]# rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm

//安装php72版本
[root@nginx ~]# yum -y install php72w php72w-cli php72w-common php72w-devel \
php72w-embedded php72w-gd php72w-mbstryuan php72w-pdo php72w-xml php72w-fpm \
php72w-mysqlnd php72w-opcache --nogpgcheck

//启动php
[root@nginx ~]# systemctl start php-fpm
[root@nginx ~]# systemctl enable php-fpm

3.安装 Mariadb

//下载官⽅扩展源, 扩展源集成mysql5.6、 5.7、 8.0,仅5.7仓库是开启
[root@nginx ~]# rpm -ivh http://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/mysql57-community-release-el7-10.noarch.rpm
[root@nginx ~]# yum install mysql-community-server -y --nogpgcheck
[root@nginx ~]# systemctl start mysqld
[root@nginx ~]# systemctl enable mysqld
[root@nginx ~]# systemctl status mysqld

//如果mysql登陆需要密码,请查看该⽂件
[root@nginx ~]# grep 'temporary password' /var/log/mysqld.log
2023-06-03T05:54:37.607361Z 1 [Note] A temporary password is generated for
root@localhost: Fk%:(-KCC3St

//登陆mysql重新配置密码
[root@nginx ~]# mysql -uroot -p'123456'
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
mysql> flush privileges;

#登不上试试以下方法
[root@linuxprobe mysql]# mysql -h 127.0.0.1 -p123456
#CREATE USER `root`@`127.0.0.1` IDENTIFIED BY '123456';

10.2 配置LNMP架构

1.配置 Nginx 实现动态请求转发⾄php

[root@nginx ~]# cat /etc/nginx/conf.d/lnmp.conf
server {
server_name lnmp.yuansredevsecops.top;
listen 80;
root /soft/code/lnmp;
index index.php index.html;

location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

2.添加php测试⻚⾯

#创建站点测试⽬录
[root@nginx ~]# mkdir -p /soft/code/lnmp
//测试phpinfo
[root@nginx ~]# cat /soft/code/lnmp/info.php
<?php
phpinfo();
?>

//使⽤mysqli模块测试连接mysql
[root@nginx ~]# cat /soft/code/lnmp/mysqli.php
<?php
$servername = "localhost";
$username = "root";
$password = "123456";

// 创建连接
$conn = mysqli_connect($servername, $username, $password);

// 检测连接
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
echo "连接成功";
?>

//使⽤pdo模块测试连接mysql
[root@nginx ~]# cat /soft/code/lnmp/mysqlpdo.php
<?php
$servername = "localhost";
$username = "root";
$password = 123456";

try {
$conn = new PDO("mysql:host=$servername;dbname=test", $username,
$password);
echo "连接成功";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>

提前创建test

mysql -uroot -p'123456' -e 'create database test;'

10.3 检测LNMP架构 √

image-20230602153023383

image-20230602153053032

10.4 Nginx与PHP原理

Nginx FastCGI的运⾏原理

image-20230602153136732

nginx fastcgi`访问`php

fastcgi 协议是⼀种标准化的协议,⽤于定义 Web 服务器和应⽤程序之间的通信⽅式。 nginx 和 PHP-FPM 之间
使⽤ fastcgi 协议来进⾏通信,并通过请求和响应消息传递数据。

1.⽤户发送http请求报⽂给nginx服务器
2.nginx会根据⽂件url和后缀来判断请求
3.如果请求的是静态内容,nginx会将结果直接返回给⽤户
4.如果请求的是动态内容,nginx会将请求交给fastcgi客户端,通过fastcgi_pass将这个请求发送给php-fpm
5.php-fpm收到请求后会通过本地监听的socket交给wrapper
6.wrapper收到请求会⽣成新的线程调⽤php动态程序解析服务器
7.如果⽤户请求的是博⽂、或者内容、 PHP会请求MySQL查询结果
8.如果⽤户请求的是图⽚、附件、 PHP会请求nfs存储查询结果
9.php会将查询到的结果交给Nginx
10.nginx会⽣成⼀个响应报⽂返还给⽤户

10.5 PHP配置文件优化

10.5.1 php-ini优化

//打开php的安全模式,控制php执⾏危险函数, 默认是Off,改为On
sql.safe_mode = Off
//关闭php头部信息, 隐藏版本号, 默认是On,该为Off
expose_php = On
//错误信息输出控制
display_error = Off
error_reportyuan = E_WARNING & E_ERROR
//记录错误⽇志⾄后台, ⽅便追溯
log_errors = On
error_log = /var/log/php_error.log
//每个脚本时间最⼤内存
memory_limit = 128M
//上传⽂件最⼤许可,默认2M, 建议调整为16,32M
upload_max_filesize = 2M
//禁⽌远程执⾏phpshell,默认On, 建议Off
allow_url_fopen = On
//时区调整,默认PRC, 建议调整为Asia/Shanghai
date.timezone = PRC

//整体优化后配置⽂件
sql.safe_mode = Off
expose_php = Off
display_error = Off
error_reportyuan = E_WARNING & E_ERROR
log_errors = On
error_log = /var/log/php_error.log
upload_max_filesize = 50M
allow_url_fopen = Off
date.timezone = Asia/Shanghai

10.5.2 php-fpm优化

PHP-FPM配置⽂件 4核16G、 8核16G

[root@nginx ~]# cat /etc/php-fpm.d/www.conf
[global]
pid = /var/run/php-fpm.pid
#php-fpm程序错误⽇志
error_log = /var/log/php/php-fpm.log
log_level = warnyuan
#进程打开⽂件的软限制,⽤来限制 PHP-FPM 进程可以同时打开的最⼤⽂件数量。
rlimit_files = 655350
#PHP-FPM 应⽤程序使⽤的事件机制,可以选⽤ select、 poll 和 epoll 三种机制。
events.mechanism = epoll

[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000
listen.owner = www
listen.group = www
listen.mode = 0660

listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 512
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 30
pm.process_idle_timeout = 15s;

pm.max_requests = 2048

#php-www模块错误⽇志
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php/php-www.log
php_admin_flag[log_errors] = on

#php慢查询⽇志
request_slowlog_timeout = 5s
slowlog = /var/log/php/php-slow.log

PHP5-FPM配置详解释

[global]
#pid设置, 记录程序启动后pid
pid = /var/run/php-fpm.pid
#php-fpm程序启动错误⽇志路径
error_log = /soft/log/php/php-fpm_error.log
# 错误级别. 可⽤级别为: alert(必须⽴即处理) ,error(错误情况) , warnyuan(警告情况) , notice(⼀般
重要信息) , debug(调试信息) . 默认: notice.
log_level = warnyuan
#进程打开⽂件的软限制,⽤来限制 PHP-FPM 进程可以同时打开的最⼤⽂件数量
rlimit_files = 65535
#PHP-FPM 应⽤程序使⽤的事件机制,可以选⽤ select、 poll 和 epoll 三种机制。
events.mechanism = epoll

#启动进程的⽤户和组
[www]
user = www
group = www

# fpm监听端⼝
listen = 127.0.0.1:9000
# unix socket设置选项,如果使⽤tcp⽅式访问,这⾥注释即可。
listen.owner = www
listen.group = www
# 允许访问FastCGI进程的IP, any不限制
listen.allowed_clients = 127.0.0.1

# pm设置动态调度
pm = dynamic
# 同⼀时刻最⼤的php-fpm⼦进程数量
pm.max_children = 200
# 动态⽅式下的起始php-fpm进程数量
pm.start_servers = 20
# 动态⽅式下服务器空闲时最⼩php-fpm进程数量
pm.min_spare_servers = 10
# 动态⽅式下服务器空闲时最⼤php-fpm进程数量
pm.max_spare_servers = 30
# 最⼤请求
pm.max_requests = 1024
pm.process_idle_timeout = 15s;
# FPM状态⻚⾯,⽤于监控php-fpm状态使⽤
pm.status_path = /status
# 错误⽇志
php_flag[display_errors] = off
php_admin_value[error_log] = /soft/log/php/php-www_error.log
php_admin_flag[log_errors] = on

# 配置php慢查询, 以及慢查询记录⽇志位置
request_slowlog_timeout = 5s
slowlog = /soft/log/php/php-slow.log

十一、LNMT动态⽹站 √

Nginx + Tomcat

Tomcat默认监听在8080端⼝
Tomcat依赖于java

0.环境准备

系统 服务 地址
CentOS7.9 Nginx Proxy 192.168.1.170
CentOS7.9 Tomcat 动态服务器 192.168.1.152

1.安装 jdk

链接: https://pan.baidu.com/s/1rBd5lAIn0Cn-JrgJDy00IQ?pwd=94he 提取码: 94he

192.168.1.152

#上传到 /soft/package/
[root@tomcat-node1-20 package]# pwd
/soft/package/
[root@tomcat-node1-20 package]# ll
-rw------- 1 root root 194151339 4⽉ 28 21:20 jdk-8u231-linux-x64.tar.gz
[root@tomcat-node1-20 package]# tar xf jdk-8u231-linux-x64.tar.gz -C /app
[root@tomcat-node1-20 ~]# cd /app/ && mv jdk1.8.0_231 jdk1.8
[root@tomcat-node1-20 ~]#cat /etc/profile.d/jdk.sh
export JAVA_HOME=/app/jdk1.8
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

[root@tomcat-node1-20 ~]# chmod +x /etc/profile.d/jdk.sh
[root@tomcat-node1-20 ~]# source /etc/profile
[root@tomcat-node1-20 ~]# java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

2.安装 tomcat

192.168.1.152

[root@tomcat-node1-20 ~]# mkdir /soft/src -p
[root@tomcat-node1-20 ~]# cd /soft/src
[root@nginx ~]# wget https://mirrors.tuna.tsyuanhua.edu.cn/apache/tomcat/tomcat-9/v9.0.74/bin/apache-tomcat-9.0.74.tar.gz --no-check-certificate

[root@tomcat-node1-20 src]# tar xf apache-tomcat-9.0.74.tar.gz -C /soft
[root@tomcat-node1-20 src]# cd ..
[root@tomcat-node1-20 soft]# mv apache-tomcat-9.0.74/ tomcat-8080
[root@tomcat-node1-20 bin]# /soft/tomcat-8080/bin/startup.sh

3.配置 Nginx proxy 负载均衡

192.168.1.170

[root@nginx nginx]# yum install nginx -y
[root@nginx nginx]# systemctl enable nginx
[root@nginx nginx]# systemctl start
[root@nginx nginx]]# cd /etc/nginx/conf.d/
[root@nginx nginx]]# pwd
/etc/nginx/conf.d
[root@nginx nginx]# cat tomcat.conf

upstream java_prod {
server 192.168.1.152:8080;
}
server {
listen 80;
server_name tomcat.yuansredevsecops.top ;
location / {
proxy_pass http://java_prod;
include proxy_params;
}
}

JVM故障排查思路

JVM 问题排查-性能优化如何排查jvm问题:https://blog.csdn.net/qq_35958391/article/details/124367955

1.jps获取java进程的PID
2.top -H -p PID 查看对应进程的哪个线程占⽤CPU过⾼。
3.jstack pid >> java.txt 导出CPU占⽤⾼进程的线程栈。
4.echo "obase=16;989"|bc 将线程的PID转换为16进制。
5.在第⼆步导出的java.txt中查找转换成为16进制的线程PID。找到对应的线程栈。
6.分析负载⾼的线程栈都是什么业务操作。优化程序并处理问题。

tomcat 性能优化参数

#最⼤线程数
maxThreads="600"
#初始化时创建的线程数
minSpareThreads="100"
#⼀旦创建的线程超过这个值, Tomcat就会关闭,不再需要的socket线程。
maxSpareHtreads="500"
#指定当所有可以使⽤的处理请求的线程数量都被使⽤时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。
acceptCount="700" />

实战操作

[root@tomcat ~]# mkdir -p tomcat
[root@tomcat ~]# cd tomcat
[root@tomcat tomcat]# pwd
/root/tomcat
[root@tomcat tomcat]# jps
48051 Bootstrap
94398 Jps
[root@tomcat tomcat]# top -Hp 48051
top - 11:41:24 up 23 days, 9:55, 2 users, load average: 0.00, 0.01, 0.05
Threads: 33 total, 0 runnyuan, 33 sleepyuan, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 7990056 total, 5457288 free, 1138616 used, 1394152 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 6158984 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
48051 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.00 java
93862 root 20 0 5677816 155780 13752 S 0.0 1.9 0:01.09 java
93863 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.02 java
93864 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.00 java
93865 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.02 java
93866 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.02 java
93867 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.08 java
93868 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.00 java
93869 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.00 java
93870 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.00 java
93871 root 20 0 5677816 155780 13752 S 0.0 1.9 0:01.07 java
93872 root 20 0 5677816 155780 13752 S 0.0 1.9 0:01.10 java
93873 root 20 0 5677816 155780 13752 S 0.0 1.9 0:01.21 java
93874 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.00 java
93875 root 20 0 5677816 155780 13752 S 0.0 1.9 0:01.12 java
93876 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.03 java
93877 root 20 0 5677816 155780 13752 S 0.0 1.9 0:00.01 java

[root@tomcat tomcat]# jstack 48051 >> java.txt
[root@tomcat tomcat]# echo "obase=16;48051"|bc
BBB3
[root@tomcat tomcat]# egrep -ri "BBB3" java.txt
"main" #1 prio=5 os_prio=0 tid=0x00007fc64c00a000 nid=0xbbb4 runnable [0x00007fc6521d1000]
"main" #1 prio=5 os_prio=0 tid=0x00007fc64c00a000 nid=0xbbb4 runnable [0x00007fc6521d1000]

condition [0x00007f9a7db65000]
java.lang.Thread.State: TIMED_WAITING (parkyuan)
at sun.misc.Unsafe.park(Native Method)
- parkyuan to wait for <0x00000000db8b4110> (a
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Abstra
ctQueuedSynchronizer.java:2078)
at
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadP
oolExecutor.java:1093)
at
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadP
oolExecutor.java:809)
at
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at
org.apache.tomcat.util.threads.TaskThread$WrappyuanRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

这是 Tomcat Web 服务器进程中的⼀个线程,线程名为 Catalina-utility-2。根据堆栈信息,该线程处于
TIMED_WAITING 状态,即等待某个条件,在指定时间过后将会⾃动唤醒。

堆栈信息显示该线程被阻塞在`java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take` ⽅法上,该⽅法是⼀个被调度的线程池队列(DelayedWorkQueue)。该线程进⼊了 Wait(等待)状态并在等待某个任务添加到队列中。

该线程池中可能存在某个任务⽆法完成或其它线程池问题。可以使⽤ jstack 和 JMX 等⽅式,查看线程池的上下⽂以及任务队列中是否存在某些任务在等待执⾏。如果任务等待时间过⻓,可以调整线程池的参数;如果任务本身有问题,则需要对其实现进⾏修复。

jstack

jstack 是 JDK ⾃带的⼀个命令⾏⼯具,可以⽤来打印出⼀个 Java 进程的线程堆栈信息。它可以⾮常⽅便地帮助开发者和运维⼈员分析 Java 进程在运⾏时出现的问题,⽐如死锁、性能瓶颈等。

jstack 可以⽤来查看 Java 进程中所有线程的状态,包括线程ID、线程名称、线程状态、堆栈信息等。根据堆栈信息,可以分析出每个线程正在执⾏的代码,以及线程间的互相依赖关系,从⽽帮助定位问题并进⾏排查和解决。

使⽤ jstack 命令时需要提供⽬标 Java 进程的 ID 或者⽂件描述符。如果不指定任何参数,则默认会将堆栈信息打印到标准输出中,也可以将结果存储到⽂件中进⾏分析。

jstack 命令的语法如下:

jstack [-l] [-m] [-h] [-F] [-v] <pid or core>

其中主要参数的含义如下:

  • -l : 输出关于锁的附加信息
  • -m : 如果调⽤本地⽅法,则显示C/C++堆栈信息
  • -h : 帮助信息
  • -F : 当正常输出阻塞时,强制输出线程的堆栈信息
  • -v : 输出所有JVM相关信息

可以通过官⽅⽂档或者命令⾏输⼊ jstack -h 获取更详细的使⽤说明。

十二、.Nginx+Lua实战

12.1 Lua脚本基础语法

Lua是⼀个简洁、轻量、可扩展的脚本语⾔
Nginx+Lua优势

充分的结合Nginx的并发处理epool优势和Lua的轻量实现简单的功能且⾼并发的场景
统计IP
统计⽤户信息
安全WAF

2.lua 的运⾏⽅式

//命令⾏执⾏, 交互式
[root@Nginx-Lua ~]# lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print("Hello,World")
Hello,World

//⽂件执⾏⽅式, ⾮交互式
[root@nginx-php-k-1 lua]# pwd
/soft/lua
[root@Nginx-Lua ~]# cat test.lua
#!/usr/bin/lua
print("Hi is yuan!")

[root@Nginx-Lua ~]# lua ./test.lua
Hi is yuan!

3.Lua的注释语法

// --⾏注释
#!/usr/bin/lua
--print("Hi is yuan!")

//块注释
--[[
	注释代码
--]]

4.Lua的基础语法

变量定义

a = 123

// 注意事项
//布尔类型只有true和false
//数字0,空字符串都是true
//lua中的变量如果没有特殊说明, 全是全局变量

while 循环语句

计算1+2+3..+100

[root@nginx lua]# cat while.lua
#!/usr/bin/lua
sum =0
num =1
while num <= 100 do
sum = sum + num
num = num + 1
end
print("sum=",sum)
//执⾏结果
[root@nginx lua]# lua while.lua
sum= 5050

//Lua没有++或是+=这样的操作

for 循环语句

循环1..100个数,sum每次+1到100

[root@nginx lua]# cat for.lua
#!/usr/bin/lua
sum = 0
for i = 1,100 do
sum = sum + 1
print("i=",i,"sum",sum)
end
print("sum=", sum)
//执⾏结果
[root@nginx ~]# lua for.lua
sum= 100

if 判断语句

[root@nginx lua]# cat if.lua
#!/usr/bin/lua
age=30
sex="Man"
if age == 40 and sex == "Man" then
print("男⼈⼤于40")
elseif age > 60 and sex ~= "Woman" then
print("⾮⼥⼈⽽且⼤于60")
else
local age = io.read()
print("Your age is",age)
end

//~=是不等于
//字符串的拼接操作符".."
//io库的分别从stdin和stdout读写, read和write函数

[root@nginx lua]# lua if.lua
10
Your age is 1

12.2 Nginx加载Lua环境

默认情况下 Nginx 不⽀持Lua模块, 需要安装LuaJIT解释器, 并且需要重新编译 Nginx , 本次使⽤openrestry

LuaJIT
Ngx_devel_kit和lua-nginx-module

LuaJIT是⼀种⾼性能的 Just-In-Time (JIT) 编译器实现的Lua解释器,它基于 Lua 5.1 版本,但是它不仅仅是⼀个解释器,更是⼀个集成了 JIT 编译器、动态类型机制、⾼效 GC 等新特性的 Lua 实现。 LuaJIT 通过使⽤⼀种叫做“ Trace 编译”的技术,将 Lua 代码动态地翻译成本地机器码,因此 LuaJIT 具有⾮常⾼的执⾏性能和内存利⽤率。相应地, LuaJIT 还对 Lua 语法进⾏了扩充和改进,同时保留了原有的语法和 API 接⼝,完全兼容 Lua5.1。

与原⽣的 Lua 解释器相⽐, LuaJIT 可以将 Lua 代码的执⾏速度提升数⼗倍,这使得 LuaJIT 在需要⾼性能和低延迟的场合下⼗分适⽤,⽐如在计算机游戏开发、⽹络服务器和嵌⼊式系统等领域,都能发挥出⾮常显著的优势。另外,在某些特定场景中,例如进⾏⼤量矩阵运算的科学计算和数学模拟等, LuaJIT 可以⽐纯 C 代码还要快。

除了性能和语⾔扩展⽅⾯的改进之外, LuaJIT 还具有良好的可移植性和稳定性,⽀持多平台(包括 x64、 arm 和MIPS 等);还提供了 C 语⾔ API 接⼝,⽅便 LuaJIT 与其他语⾔集成使⽤。综上, LuaJIT 是⼀个⾮常优秀的Lua 实现,⼴泛应⽤于众多场合。

1.环境准备

[root@nginx ~]# yum -y install gcc gcc-c++ make pcre-devel zlib-devel openssl-devel

2.下载最新的luajitngx_devel_kit 以及 lua-nginx-module

[root@nginx ~]# mkdir -p /soft/src && cd /soft/src
[root@nginx ~]# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
[root@nginx ~]# wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
[root@nginx ~]# wget https://github.com/openresty/lua-nginxmodule/archive/v0.10.13.tar.gz

[root@nginx ~]#https://github.com/openresty/echo-nginxmodule/archive/refs/tags/v0.63.tar.gz

3.解压 ngx_devel_kitlua-nginx-module

//解压后为ngx_devel_kit-0.2.19
[root@nginx ~]# tar xf v0.2.19.tar.gz
//解压后为lua-nginx-module-0.9.16
[root@nginx ~]# tar xf v0.10.13.tar.gz

4.安装 LuaJIT LuajitLua即时编译器

[root@nginx ~]# tar zxvf LuaJIT-2.0.4.tar.gz
[root@nginx ~]# cd LuaJIT-2.0.4
[root@nginx ~]# make && make install

5.安装 echo 模块

tar xf v0.63.tar.gz

6.安装 Nginx 并加载模块

[root@nginx ~]# cd /soft/src
[root@nginx ~]# wget http://nginx.org/download/nginx-1.21.0.tar.gz
[root@nginx ~]# tar xf nginx-1.21.0.tar.gz
[root@nginx ~]# cd nginx-1.21.0
./configure --prefix=/usr/local/nginx/ --with-http_ssl_module \
--with-http_stub_status_module --with-http_dav_module \
--add-module=../ngx_devel_kit-0.2.19/ \
--add-module=../lua-nginx-module-0.10.13 \
--add-module=../echo-nginx-module-0.63
[root@nginx ~]# make -j2 && make install

//建⽴软链接, 不建⽴会出现share object错误
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2

//4.加载lua库,加⼊到ld.so.conf⽂件
echo "/usr/local/LuaJIT/lib" >> /etc/ld.so.conf
ldconfig

开源配置 √

也可以直接部署春哥的开源项⽬OpenResty : http://openresty.org/cn/

# 安装依赖包
[root@linuxprobe]# yum install -y readline-devel pcre-devel openssl-devel
[root@linuxprobe]# cd /soft/src

# 下载并编译安装openresty
[root@linuxprobe src]# wget https://openresty.org/download/ngx_openresty-1.9.3.2.tar.gz
[root@linuxprobe src]# tar zxf ngx_openresty-1.9.3.2.tar.gz
[root@linuxprobe src]# cd ngx_openresty-1.9.3.2
[root@linuxprobe ngx_openresty-1.9.3.2]# ./configure --prefix=/soft/openresty-1.9.3.2 \
--with-luajit --with-http_stub_status_module \
--with-pcre --with-pcre-jit
[root@linuxprobe ngx_openresty-1.9.3.2]# gmake && gmake install
[root@linuxprobe ngx_openresty-1.9.3.2]# ln -s /soft/openresty-1.9.3.2/ /soft/openresty

#配置
[root@180-143 conf]# cd /soft/openresty-1.9.3.2/nginx/conf
[root@180-143 conf]# cat nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;

include ./conf.d/*.conf ;
}
# 测试openresty安装
# vim /soft/openresty/nginx/conf/nginx.conf
server {
listen 80;
server_name www.yuansredevsecops.top;
    location /hello {
    	default_type text/html;     
        content_by_lua 'ngx.say("hello ,lua scripts")';
        }
	}

# 启动openresty
[root@nginx-php-k-1 conf.d]# /soft/openresty/nginx/sbin/nginx

image-20230615161547509

12.3 Nginx调⽤Lua指令

Nginx 调⽤ Lua 模块指令, Nginx的可插拔模块加载执⾏

语法
set_by_lua set_by_lua_file 设置Nginx变量,可以实现负载的赋值逻辑
access_by_lua access_by_lua_file 请求访问阶段处理, ⽤于访问控制
content_by_lua content_by_lua_file 内容处理器, 接受请求处理并输出响应

Nginx 调⽤ Lua API

变量
ngx.var nginx变量
ngx.req.get_headers 获取请求头
ngx.req.get_uri_args 获取url请求参数
ngx.redirect 重定向
ngx.print 输出响应内容体
ngx.say 输出响应内容体,最后输出⼀个换⾏符
ngx.header 输出响应头

set_by_lua 和 set_by_lua_file

set_by_lua 和 set_by_lua_file :这两个模块都⽤于设置 Nginx 变量。 set_by_lua 通过 inline Lua 代码设置变量的值, set_by_lua_file 则可以通过引⼊ Lua 脚本⽂件来设置变量。这两个模块通常⽤于实现负载的赋值逻辑,如根据请求的 headers 头部信息等进⾏动态变量设置。

/soft/openresty-1.9.3.2/nginx/conf/conf.d/luasetbylua.conf

upstream backend {
server 192.168.1.152:8081 weight=1;
server 192.168.1.152:8082 weight=1;
}

server {
listen 80;
server_name luasetbylua.yuansredevsecops.top;
location /hello {
default_type text/html;
content_by_lua_block {
ngx.say("HelloWorld")
}
}

location / {
set $backend 'backend';
set_by_lua_file $backend_lua_file /soft/openresty-1.9.3.2/nginx/conf/lua/backend.lua;
proxy_pass http://$backend;
}
}

/soft/openresty-1.9.3.2/nginx/conf/lua/backend.lua

# cat /soft/openresty-1.9.3.2/nginx/conf/lua/backend.lua
-- backend.lua

if ngx.var.remote_addr == '127.0.0.1' then
-- Use 10.1.106.66:8081 for local requests
ngx.var.backend = '192.168.1.152:8081';
else
-- Use 10.1.106.66:8082 for remote requests
ngx.var.backend = '192.168.1.152:8082';
end

//上述脚本内容是判断ngx.var.remote_addr请求地址是否等于127.0.0.1,是则返回8081,否则返回8082

[root@nginx-php-k-1 conf.d]# cat /etc/hosts
127.0.0.1 luasetbylua.yuansredevsecops.top

access_by_lua 和 access_by_lua_file

access_by_lua 和 access_by_lua_file :这两个模块⽤于在 Nginx 处理请求的访问阶段(access phase)执⾏ Lua代码,⼀般⽤于请求的认证和访问控制。例如,可以使⽤ Lua 脚本从请求的 headers 中提取⽤户凭证,然后进⾏⽤户认证并判断权限,以决定是否允许请求继续执⾏。

假设我们有⼀个 API,需要进⾏鉴权,只有拥有正确的 token 的请求才能访问。

我们可以使⽤ access_by_lua 或 access_by_lua_file 在 Nginx 的 access 阶段进⾏鉴权逻辑的实现,例如:

192.168.1.170

[root@180-143 conf.d]# cat luaaccess.conf
upstream backend1 {
server 192.168.1.152:8081;
}

server {
listen 80;
server_name luaaccess.yuansredevsecops.top;

location /api {
# 鉴权
access_by_lua '
local token = ngx.var.http_authorization
if token ~= "SECRET-TOKEN" then
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
';

# 路由到 backend1
set $backend "backend1";
proxy_pass http://$backend/;
}
}

在这个例⼦中,我们使⽤ access_by_lua 进⾏鉴权,如果请求头中的 Authorization 值不为 "SECRETTOKEN" ,我们返回 HTTP 401 错误,不继续处理请求。

如果鉴权通过,我们设置 $backend 变量的值为backend1,并将请求转发给http://backend1.example.com

这样,我们就可以使⽤ access_by_luaaccess_by_lua_file 实现访问控制和 API 鉴权的逻辑。

[root@nginx-php-k-1 conf.d]# curl 'http://luaaccess.yuansredevsecops.top/api' --header 'Authorization: SECRET-TOKEN'
<html>
<title> Code1</title>
<body bgcolor="red">
<h1> Code1-8081 </h1>
</body>
</html>

通过postman 验证测试

image-20230609101559499

content_by_lua 和 content_by_lua_file

content_by_lua 和 content_by_lua_file :这两个模块⽤于在 Nginx 处理请求的内容处理阶段(content phase)中执⾏ Lua 代码,⼀般⽤于实现特殊的应⽤逻辑或添加数据处理扩展等。 例如,可以使⽤ Lua 脚本处理请求体中的 JSON 数据,或通过调⽤其他服务的 API 添加⼀些附加的数据处理功能。 处理完毕后,⽤于的 Lua 脚本需要返回数据,以便 Nginx 输出给客户端。

luacontent.conf

下⾯我们来举⼀个使⽤content_by_lua的例⼦,假设我们的业务流程是根据不同请求头的值返回不同的响应内
容。我们可以使⽤ content_by_lua 阶段在 Nignx 中进⾏⾃定义处理。

server {
listen 80;
server_name luacontent.yuansredevsecops.top;

location / {
# 进⾏⾃定义处理
content_by_lua '
local headers = ngx.req.get_headers()
local response = ""

if headers["User-Agent"] == "mobile" then
response = "Hello mobile user!"
else
response = "Hello desktop user!"
end
ngx.say(response)
';
}
}

在这个例⼦中,我们使⽤ content_by_lua 阶段根据请求头中的 User-Agent 做出不同的响应。如果 User-Agent
是 mobile,就返回 "Hello mobile user!";否则返回 "Hello desktop user!"。我们使⽤ ngx.say 输出响应内容。

类似地,我们也可以使⽤ content_by_lua_file 指令来指定⼀个 lua ⽂件进⾏处理。这种⽅式可以更好地分离
业务逻辑和 Nginx 配置⽂件,⽅便代码维护和更新。

image-20230609101959197

12.4 Nginx+Lua实现代码灰度发布 √

使⽤ Nginx 结合lua实现代码灰度发布

灰度发布是⼀种将新版本的软件或功能逐步推⼴给⼀⼩部分⽤户,以进⾏测试和评估它们的反应的⽅法。实
际上,它是⼀种渐进式的部署⽅法,可以逐步将新版本或功能逐步发布给不同的⽤户群体,直到所有⽤户都
可以使⽤这个新版本或功能。

这种⽅法通常⽤于⼤规模应⽤程序和⽹站,以确保新的功能和修复⼯作的质量,并降低和减少出现故障或负
⾯反应的⻛险。在灰度发布期间,团队可以监测应⽤程序或⽹站的性能并调整它们,以便可以全⾯推⼴给所
有⽤户。

按照⼀定的关系区别,分不分的代码进⾏上线,使代码的发布能平滑过渡上线

1.⽤户的信息cookie等信息区别
2.根据⽤户的ip地址, 颗粒度更⼴

实践架构图

image-20230609102116061

执⾏过程:

1.⽤户请求到达前端代理Nginx, 内嵌的lua模块会解析Nginx配置⽂件中Lua脚本
2.Lua脚本会获取客户端IP地址,查看Memcached缓存中是否存在该键值
3.如果存在则执⾏@java_test,否则执⾏@java_prod
4.如果是@java_test, 那么location会将请求转发⾄新版代码的集群组
5.如果是@java_prod, 那么location会将请求转发⾄原始版代码集群组
6.最后整个过程执⾏后结束

实践环境准备:

系统 服务 地址
CentOS7 Nginx+Lua+Memached 192.168.1.170
CentOS7 Tomcat集群8080_Prod 192.168.1.152:8080
CentOS7 Tomcat集群9090_Test 192.168.1.152:9090

1.安装两台服务器 Tomcat ,分别启动 8080 和 9090 端⼝

jdk下载
链接: https://pan.baidu.com/s/1rBd5lAIn0Cn-JrgJDy00IQ?pwd=94he 提取码: 94he

192.168.1.152服务器操作

[root@tomcat-node1-20 ~]# pwd
/app/soft
[root@tomcat-node1-20 ~]# ll
-rw------- 1 root root 194151339 4⽉ 28 21:20 jdk-8u231-linux-x64.tar.gz
[root@tomcat-node1-20 ~]# tar xf jdk-8u231-linux-x64.tar.gz -C /app
[root@tomcat-node1-20 ~]# cd /app/ && mv jdk1.8.0_231 jdk1.8
[root@tomcat-node1-20 ~]#cat /etc/profile.d/jdk.sh
export JAVA_HOME=/app/jdk1.8
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

[root@tomcat-node1-20 ~]# chmod +x /etc/profile.d/jdk.sh
[root@tomcat-node1-20 ~]# source /etc/profile
[root@tomcat-node1-20 ~]# java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

#安装tomcat
[root@tomcat-node1-20 ~]# mkdir /soft/src -p
[root@tomcat-node1-20 ~]# cd /soft/src
[root@nginx ~]# wget https://mirrors.tuna.tsyuanhua.edu.cn/apache/tomcat/tomcat-9/v9.0.74/bin/apache-tomcat-9.0.74.tar.gz --no-check-certificate

[root@tomcat-node1-20 src]# tar xf apache-tomcat-9.0.74.tar.gz -C /soft
[root@tomcat-node1-20 src]# cd ..
[root@tomcat-node1-20 soft]# mv apache-tomcat-9.0.74/ tomcat-8080
[root@tomcat-node1-20 soft]# /soft/tomcat-8080/bin/startup.sh

#启动9090
[root@tomcat-node1-20 soft]# cp -r tomcat-8080 tomcat-9090
[root@tomcat-node1-20 soft]# cd tomcat-9090/conf/
[root@tomcat-node1-20 soft]# vim server.xml
#修改⼀下内容
<Server port="8005" shutdown="SHUTDOWN">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxParameterCount="1000"
/>
#最新的内容
<Server port="8006" shutdown="SHUTDOWN">
<Connector port="9090" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8444"
maxParameterCount="1000"
/>

[root@tomcat-node1-20 conf]# cd ..
[root@tomcat-node1-20 tomcat-9090]# cd bin/
[root@tomcat-node1-20 bin]# sh startup.
sh: startup.: 没有那个⽂件或⽬录
[root@I bin]# sh startup.sh
Usyuan CATALINA_BASE: /soft/tomcat-9090
Usyuan CATALINA_HOME: /soft/tomcat-9090
Usyuan CATALINA_TMPDIR: /soft/tomcat-9090/temp
Usyuan JRE_HOME: /app/jdk1.8
Usyuan CLASSPATH: /soft/tomcat-9090/bin/bootstrap.jar:/soft/tomcat-9090/bin/tomcat-juli.jar
Usyuan CATALINA_OPTS:
Tomcat started.
[root@tomcat-node1-20bin]# netstat -lntup |egrep 9090
tcp6	 0 		0 :::9090 		:::* 		LISTEN
19153/java
//注意tomcat默认监听在8080端⼝, 如果需要启动9090端⼝需要修改server.xml配置⽂件

#修改9090站点⻚⾯
[root@tomcat-node1-20]# cd /soft/tomcat-9090/webapps/ROOT
[root@@tomcat-node1-20 ROOT]# vim index.jsp
<title>9090-tomcat <%=request.getServletContext().getServerInfo() %></title>

访问8080 和 9090

image-20230609102702587

2.配置 Memcached 并让其⽀持 Lua 调⽤

192.168.1.170

//安装memcached服务
[root@Nginx-Lua ~]# yum install memcached -y

//配置memcached⽀持lua
[root@Nginx-Lua ~]# cd /soft/src
[root@Nginx-Lua ~]# wget https://github.com/agentzh/lua-restymemcached/archive/v0.11.tar.gz
# 开源已不存在,本地rz上传工具包
[root@Nginx-Lua ~]# tar xf lua-resty-memcached-0.11.tar.gz
[root@Nginx-Lua ~]# mkdir -p /soft/openresty/nginx/lua/
[root@Nginx-Lua ~]# cp -r lua-resty-memcached-0.11/lib/resty/memcached.lua /soft/openresty/nginx/lua/

//启动memcached
[root@Nginx-Lua ~]# systemctl start memcached
[root@Nginx-Lua ~]# systemctl enable memcached
[root@Nginx-Lua ~]# systemctl status memcached
● memcached.service - Memcached
Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; vendor preset:
disabled)
Active: active (runnyuan) since 六 2023-05-06 14:45:55 CST; 5s ago
Main PID: 26515 (memcached)
CGroup: /system.slice/memcached.service
└─26515 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024

5⽉ 06 14:45:55 180-143 systemd[1]: Started Memcached.

3.配置负载均衡调度

/soft/openresty/nginx/conf/nginx.conf

#必须在http层
lua_package_path "/soft/openresty/nginx/lua/memcached.lua";
#稳定代码 8080
upstream java_prod {
server 192.168.1.152:8080;
} 
#最新代码 灰度测试
upstream java_test {
server 192.168.1.152:9090;
}

server {
listen 80;
server_name www.yuansredevsecops.top;

location /hello {
default_type 'text/plain';
content_by_lua 'ngx.say("hello ,lua scripts")';
}

location /myip {
default_type 'text/plain';
content_by_lua '
clientIP = ngx.req.get_headers()["x_forwarded_for"]
ngx.say("Forwarded_IP:",clientIP)
if clientIP == nli then
clientIP = ngx.var.remote_addr
ngx.say("Remote_IP:",clientIP)
end
';
}
location / {
default_type 'text/plain';
content_by_lua_file /soft/openresty/nginx/lua/dep.lua;
}
location @java_prod {
proxy_pass http://java_prod;
include proxy_params;
}

location @java_test {
proxy_pass http://java_test;
include proxy_params;
}
}


//nginx反向代理tomcat,必须配置头部信息否则返回400错误
[root@nginx-lua conf.d]# cat ../proxy_params
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

proxy_buffer_size 32k;
proxy_buffering on;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;

proxy_max_temp_file_size 256k;

报错处理,将上⾯proxy_params 放在/soft/openresty-1.9.3.2/nginx/conf/

[root@180-143 conf]# /soft/openresty-1.9.3.2/nginx/sbin/nginx -t
nginx: [emerg] open() "/soft/openresty-1.9.3.2/nginx/conf/proxy_params" failed (2: No
such file or directory) in /soft/openresty-1.9.3.2/nginx/conf/nginx.conf:47
nginx: configuration file /soft/openresty-1.9.3.2/nginx/conf/nginx.conf test failed

lua_package_path

Nginx 中设置 Lua 模块搜索路径的指令。具体来说, lua_package_path 指定了 Lua 模块在⽂件系统中的路径,
可以让 Nginx 寻找⽤户⾃定义的 Lua 模块并加载使⽤。

在上述代码中, /soft/openresty/nginx/lua/memcached.lua 指的是⼀个 Lua 模块⽂件的完整路径,该模块
可以⽤来实现 Nginx 对 memcached 数据库的访问和操作。

需要注意的是,使⽤ lua_package_path 指令设置搜索路径时,需要遵循 Lua 模块搜索规则,并使⽤ Lua ⽂件路
径格式。通常,建议将所有 Lua 模块⽂件都放到同⼀个⽬录下,使⽤通配符 * 来指示 Lua 模块⽂件名的匹配规
则,例如:

lua_package_path "/usr/local/nginx/lua/?.lua;/usr/local/nginx/lua/?/init.lua";

该指令表示将 /usr/local/nginx/lua/ ⽬录下所有以 .lua 结尾的⽂件或者所有以 /init.lua 结尾的
⼦⽬录都作为 Lua 模块进⾏加载。

4.编写 Nginx 调⽤灰度发布 Lua 脚本

[root@nginx ~]# cat /soft/openresty/nginx/lua/dep.lua
--获取x-real-ip
clientIP = ngx.req.get_headers()["X-Real-IP"]

--如果IP为空-取x_forwarded_for
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end

--如果IP为空-取remote_addr
if clientIP == nil then
clientIP = ngx.var.remote_addr
end

--定义本地,加载memcached
local memcached = require "resty.memcached"
--实例化对象
local memc, err = memcached:new()
--判断连接是否存在错误
if not memc then
ngx.say("failed to instantiate memc: ", err)
return
end
--建⽴memcache连接
local ok, err = memc:connect("127.0.0.1", 11211)
--⽆法连接往前端抛出错误信息
if not ok then
ngx.say("failed to connect: ", err)
return
end
--获取对象中的ip-存在值赋给res
local res, flags, err = memc:get(clientIP)
--
--ngx.say("value key: ",res,clientIP)
if err then
ngx.say("failed to get clientIP ", err)
return
end
--如果值为1则调⽤local-@java_test
if res == "1" then
ngx.exec("@java_test")
return
end
--否则调⽤local-@java_prod
ngx.exec("@java_prod")
return

5.使⽤ Memcache set IP , 测试灰度发布

# w查看本机windows ip
[root@linuxprobe ~]# w
 10:50:42 up 38 days, 18:54,  3 users,  load average: 0.04, 0.04, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.1.129    10:34    4:34   0.07s  0.00s tailf /soft/openresty/nginx/logs/access.log
root     pts/1    192.168.1.129    10:49    2.00s  0.02s  0.01s w
root     pts/2    192.168.1.129    10:47    2:50   0.02s  0.00s telnet 127.0.0.1 11211

image-20230619105411407

//telnet传⼊值
[root@nginx conf.d]# telnet 127.0.0.1 11211
# set对应IP
set 192.168.1.129 0 0 1
# 输⼊1
1

get 192.168.1.129
VALUE 192.168.1.129 0 1
1
END

image-20230619105300309

使⽤telnet命令连接到了本地运⾏的 Memcached 服务,并进⾏了⼀些操作。

在第⼀条命令set 192.168.1.129 0 0 1中,设置 "192.168.1.129" 为键值,后⾯⼀堆数字分别表示过
期时间、存储的数据⻓度、以及存储的数据内容,最后的 "STORED" 表示设置成功。

在第⼆条命令 get 192.168.1.129 中,查询键值为 "192.168.1.129" 的值,最后的 "VALUE 192.168.1.129 0 1 " 表示查询成功,后⾯的 "1" 是数据⻓度,接着就是存储的数据内容。

该命令序列的作⽤是向 Memcached 存储了以"192.168.1.129"为键值的数据,并从 Memcached 中查询该
键值对应的数据。

5.测试验证

image-20230619105723454

未获取到ip 访问到8080

[root@180-143 ~]# curl http://www.yuansredevsecops.top/ |egrep title
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 11210 0 11210 0 0 1657k 0 --:--:-- --:--:-- --:--:-- 1824k
<title>Apache Tomcat/9.0.74</title>

12.5 Nginx+Lua实现WAF应⽤防⽕墙

  • 1.常⻅的恶意⾏为
    • 爬⾍⾏为和恶意抓取,资源盗取
    • 防护⼿段
      • 1.基础防盗链功能不让恶意⽤户能够轻易的爬取⽹站对外数据
      • 2.access_moudle->对后台,部分⽤户服务的数据提供IP防护

解决⽅法

192.168.1.170

[root@180-143 conf.d]# cat /soft/openresty/nginx/conf/conf.d/luawaf.conf
server {
listen 80;
server_name luawaf.yuansredevsecops.top;

set $ip 0;
if ($http_x_forward_for = "192.168.1.129"){
set $ip 1;
}
if ($remote_addr = "192.168.1.129"){
set $ip 1;
}
if ($ip = 0){
return 403;
}
location /hello {
default_type application/json;
return 200 '{"status":"success"}';
}
}

  • 2.常⻅的攻击⼿段
    • 后台密码撞库,通过猜测密码字典不断对后台系统登陆性尝试,获取后台登陆密码
    • 防护⼿段
      • 1.后台登陆密码复杂度
      • 2.使⽤access_module-对后台提供IP防控
      • 3.预警机制
    • ⽂件上传漏洞,利⽤上传接⼝将恶意代码植⼊到服务器中,再通过url去访问执⾏代码
    • 执⾏⽅式 luawaf.yuansredevsecops.top/1.jpg/1.php

解决办法

location ^~ /upload {
root /soft/code/upload;
if ($request_filename ~* (.*)\.php){
return 403;
}
}

  • 3.常⻅的攻击⼿段
    • 利⽤未过滤/未审核的⽤户输⼊进⾏Sql注⼊的攻击⽅法, 让应⽤运⾏本不应该运⾏的SQL代码
    • 防护⼿段
      • 1.php配置开启安全相关限制
      • 2.开发⼈员对sql提交进⾏审核,屏蔽常⻅的注⼊⼿段
      • 3.Nginx+Lua构建WAF应⽤层防⽕墙, 防⽌Sql注⼊

image-20230609104023506

1.快速安装 lnmp 架构

[root@nginx ~]# yum install mariadb mariadb-server php php-fpm php-mysql -y

2.配置 Nginx + php

[root@nginx conf.d]# cat lnmp.conf
server {
server_name lnmp.yuansredevsecops.top;
root /soft/code/lnmp/;
index index.html index.php;

location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

3.配置 MySQL

[root@nginx ~]# systemctl start mariadb
[root@nginx ~]# mysql -uroot -p'123456'

MariaDB [(none)]> create database info;
MariaDB [(none)]> use info;
MariaDB [info]> create table user(id int(11),username varchar(64), password varchar(64), email varchar(64));
MariaDB [info]> desc user;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| username | varchar(64) | YES | | NULL | |
| password | varchar(64) | YES | | NULL | |
| email | varchar(64) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+

#插⼊数据
MariaDB [info]> insert into user (id,username,password,email) values(1,'yuan',('123'),'yuan@qq.com');
MariaDB [info]> select * from info.user;
+------+----------+----------------------------------+-----------------+
| id | username | password | email |
+------+----------+----------------------------------+-----------------+
| 1 | yuan | 123 | yuan@foxmail.com |
+------+----------+----------------------------------+-----------------+
1 row in set (0.00 sec)

4.配置php代码

[root@nginx conf.d]# cat /soft/code/lnmp/login.html
<html>
<head>
<title> Sql注⼊演示场景 </title>
<meta http-equiv="content-type"content="text/html;charset=utf-8">
</head>
<body>
<form action="sql.php" method="post">
<table>
<tr>
<td> ⽤ 户: </td>
<td><input type="text" name="username"></td>
</tr>

<tr>
<td> 密 码: </td>
<td><input type="text" name="password"></td>
</tr>

<tr>
<td><input type="submit" value="提交"></td>
<td><input type="reset" value="重置"></td>
</tr>

</table>
</form>
</body>
</html>

被html调⽤的sql.php⽂件

[root@nginx conf.d]# cat /soft/code/lnmp/sql.php
<?php
$conn = mysqli_connect("localhost", 'root', '123456', "info") or die("数据库连接失败! ");
$name = $_POST['username'];
$pwd = $_POST['password'];
// # sql注⼊核⼼问题
$sql = "select * from user where username='$name' and password='$pwd'";
echo $sql . "<br />";
$query = mysqli_query($conn, $sql);
$arr = mysqli_fetch_array($query);
if ($arr) {
echo "login success!<br />";
echo $arr[1];
echo $arr[3] . "<br /><br />";
} else {
echo "login failed!";
}
mysqli_close($conn);
?>

sql注⼊操作

image-20230609104553756

5.使⽤lua解决此类安全问题

image-20230609104616848

6.部署Waf相关防护代码

[root@nginx ~]# cd /soft/src/
[root@nginx src]# git clone https://github.com/loveshell/ngx_lua_waf.git

#克隆不下了直接从github上⼿动下载上传解压
[root@nginx src]# rz ngx_lua_waf-master.zip
[root@nginx src]# unzip ngx_lua_waf-master.zip
Archive: ngx_lua_waf-master.zip
314a2f62ec350eba9b5d25b55b5b0a723e20a8d0
creatyuan: ngx_lua_waf-master/
inflatyuan: ngx_lua_waf-master/.gitattributes
inflatyuan: ngx_lua_waf-master/.gitignore
inflatyuan: ngx_lua_waf-master/README.md
inflatyuan: ngx_lua_waf-master/config.lua
inflatyuan: ngx_lua_waf-master/init.lua
inflatyuan: ngx_lua_waf-master/install.sh
inflatyuan: ngx_lua_waf-master/waf.lua
creatyuan: ngx_lua_waf-master/wafconf/
inflatyuan: ngx_lua_waf-master/wafconf/args
inflatyuan: ngx_lua_waf-master/wafconf/cookie
inflatyuan: ngx_lua_waf-master/wafconf/post
inflatyuan: ngx_lua_waf-master/wafconf/url
inflatyuan: ngx_lua_waf-master/wafconf/user-agent
extractyuan: ngx_lua_waf-master/wafconf/whiteurl

# mkdir -p /soft/openresty/nginx/logs/waf/
//把ngx_lua_waf复制到nginx的⽬录下,解压命名为waf
[root@nginx ~]# cp -r ngx_lua_waf-master /soft/openresty/nginx/lua/waf

//在nginx.conf的http段添加(注意路径)
lua_package_path "/soft/openresty/nginx/lua/waf/?.lua";
lua_shared_dict limit 10m;
init_by_lua_file /soft/openresty/nginx/lua/waf/init.lua;
access_by_lua_file /soft/openresty/nginx/lua/waf/waf.lua;

//配置config.lua⾥的waf规则⽬录(⼀般在waf/wafconf/⽬录下)
RulePath = "/soft/openresty/nginx/lua/waf/wafconf/"
logdir = "/soft/openresty/nginx/logs/waf/"
#绝对路径如有变动,需对应修改, 然后重启nginx即可

7.Nginx + lua 防⽌ Sql 注⼊

[root@nginx ~]# vim /soft/openresty/nginx/lua/waf/wafconf/post
\sor\s+

这个正则表达式有两部分:

  1. \s: 表示匹配任意空⽩字符,包括空格、制表符、换⾏符等。
  2. or: 表示匹配这三个字⺟的顺序,即 or。
  3. \s+: 表示匹配⼀个或多个任意空⽩字符,即与\s类似,但⽐\s更加宽松,可以匹配多个连续的空⽩字符。

整个正则表达式的含义是匹配字符串中的⼀个空⽩字符或多个空⽩字符,后跟or,再后跟⼀个或多个空⽩字
符。这个正则表达式通常⽤于匹配字符串中的特定分隔符。

image-20230609105120836

image-20230609105138892

8.防⽌ CC 攻击

[root@nginx ~]# vim /soft/openresty/nginx/lua/waf/config.lua
CCrate="100/60

这个 waf 配置⽂件中, CCrate 参数代表着 IP 的访问频率限制。其中 100 表示限制的请求数量, 60 表示时间窗
⼝(单位为秒),即在 60 秒内,相同的 IP 地址只能发送 100 次请求。

十三、Nginx性能优化

13.1 性能优化概述

在做性能优化前, 我们需要对如下进⾏考虑

  • 1.当前系统结构瓶颈
    • 观察指标
    • 压⼒测试
  • 2.了解业务模式
    • 接⼝业务类型
    • 系统层次化结构
  • 3.性能与安全
    • 性能好安全弱
    • 安全好性能低

13.2 压力测试工具

1.安装压⼒测试⼯具 ab

[root@nginx-lua ~]# yum install httpd-tools -y

2.了解压测⼯具使⽤⽅式

[root@nginx-lua ~]# ab -n 200 -c 2 http://127.0.0.1/
//-n总的请求次数
//-c并发请求数
//-k是否开启⻓连接

3.配置 Nginx 静态⽹站与 tomcat 动态⽹站环境

192.168.1.170

[root@nginx-lua conf.d]# cat jsp.conf
server {
server_name jsp.yuansredevsecops.top;
listen 80;
location / {
root /soft/code/jsp/;
try_files $uri @java_page;
index index.jsp index.html;
}
location @java_page{
proxy_pass http://192.168.1.152:8080;
}
}

//分别给Nginx准备静态⽹站
[root@nginx-lua ~]# cat /soft/code/jsp/yuan.html
<h1> Ab Load </h1>

192.168.1.152

//给Tomcat准备静态⽹站⽂件
[root@tomcat-node1-20 ROOT]# cat /soft/tomcat-8080/webapps/ROOT/yuan.html
<h1> Tomcat Ab Load </h1>

4.使⽤ab⼯具进⾏压⼒测试

//进⾏压⼒测试
[root@Nginx conf.d]# ab -n2000 -c2 http://jsp.yuansredevsecops.top/yuan.html
...
Server Software: nginx/1.24.0
Server Hostname: jsp.yuansredevsecops.top
Server Port: 80

Document Path: /yuan.html
Document Length: 19 bytes

Concurrency Level: 200
# 总花费总时⻓
Time taken for tests: 0.143 seconds
# 总请求数
Complete requests: 2000
# 请求失败数
Failed requests: 0
Write errors: 0
Total transferred: 510000 bytes
HTML transferred: 38000 bytes
# 每秒多少请求/s(总请求出/总共完成的时间)
Requests per second: 9333.23 [#/sec] (mean)
# 客户端访问服务端, 单个请求所需花费的时间
Time per request: 101.315 [ms] (mean)
# 服务端处理请求的时间
Time per request: 0.507 [ms] (mean, across all concurrent requests)
# 判断⽹络传输速率, 观察⽹络是否存在瓶颈
Transfer rate: 491.58 [Kbytes/sec] received

5.将 nginx 下的 yuan.html ⽂件移⾛, 再次压测会由 tomcat进⾏处理

192.168.1.170

[root@lb-node1 jsp]# mv /soft/code/jsp/yuan.html{,.bak}

Concurrency Level: 200
Time taken for tests: 1.028 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 510000 bytes
HTML transferred: 38000 bytes
Requests per second: 1945.09 [#/sec] (mean)
Time per request: 102.823 [ms] (mean)
Time per request: 0.514 [ms] (mean, across all concurrent requests)
Transfer rate: 484.37 [Kbytes/sec] received

13.3 影响性能指标

影响性能⽅便整体关注

  • 1.⽹络
    • ⽹络的流量
    • ⽹络是否丢包
    • 这些会影响http的请求与调⽤
  • 2.系统
    • 硬件有没有磁盘损坏,磁盘IO速率
    • 系统负载、内存、系统稳定性
  • 3.服务
    • 连接优化、请求优化
    • 根据业务形态做对应的服务设置
  • 4.程序
    • 接⼝性能
    • 处理速度
    • 程序执⾏效率
  • 5.数据库

每个架构服务与服务之间都或多或少有⼀些关联, 我们需要将整个架构进⾏分层, 找到对应系统或服务的短板, 然后进⾏优化

13.4 系统性能优化

  • ⽂件句柄, Linux⼀切皆⽂件,⽂件句柄可以理解为就是⼀个索引
    • ⽂件句柄会随着我们进程的调⽤频繁增加
    • 系统默认对⽂件句柄有限制,不能让⼀个进程⽆限的调⽤
    • 需要限制每个进程和每个服务使⽤多⼤的⽂件句柄
    • ⽂件句柄是必须要调整的优化参数
  • 设置⽅式
    • 系统全局性修改
    • ⽤户局部性修改
    • 进程局部性修改
vim /etc/security/limits.conf
//针对root⽤户
root soft nofile 1048576
root hard nofile 1048576s
//所有⽤户, 全局
* soft nofile 1048576
* hard nofile 1048576

//对于Nginx进程
worker_rlimit_nofile 45535;

//root⽤户
//soft提醒
//hard限制
//nofile⽂件数配置项
//65535最⼤⼤⼩

13.5 Nginx性能优化

CPU 亲和, 减少进程之间不断频繁迁移, 减少性能损耗
1.查看当前 CPU 物理状态

[root@nginx ~]# lscpu |grep "CPU(s)"
CPU(s): 24
On-line CPU(s) list: 0-23
NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22
NUMA node1 CPU(s): 1,3,5,7,9,11,13,15,17,19,21,23

//2颗物理cpu,每颗cpu12核⼼, 总共24核⼼

2.将 Nginx worker 进程绑到不同的核⼼上

//启动多少worker进程, 官⽅建议和cpu核⼼⼀致, 第⼀种绑定组合⽅式
#worker_processes 24;
#worker_cpu_affinity 000000000001 000000000010 000000000100 000000001000 000000010000
000000100000 000001000000 000010000000 000100000000 001000000000 010000000000 10000000000;

//第⼆种⽅式
#worker_processes 2;
#worker_cpu_affinity 101010101010 010101010101; 

//最佳⽅式绑定⽅式
worker_processes auto;
worker_cpu_affinity auto;

3.查看 nginx worker 进程绑定⾄对应 cpu

ps -eo pid,args,psr|grep [n]ginx

4.Nginx 通⽤优化配置⽂件

[root@nginx ~]# cat nginx.conf
user nginx;
worker_processes auto;
worker_cpu_affinity auto;

error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

#调整⾄1w以上,负荷较⾼建议2-3w以上
#⽤于限制每个nginx worker进程的打开⽂件数量的最⼤值
worker_rlimit_nofile 65535;

events {
use epoll;
#使用epoll模型,限制每个进程能处理多少个连接请求,10240x16核
worker_connections 10240;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 统⼀使⽤utf-8字符集
charset utf-8;

log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;

# Core module
sendfile on;
# 静态资源服务器建议打开
tcp_nopush on;
# 动态资源服务建议打开,需要打开keepalived
tcp_nodelay on;
keepalive_timeout 65;

# Gzip module
gzip on;
gzip_disable "MSIE [1-6]\.";
gzip_http_version 1.1;

# Virtal Server
include /etc/nginx/conf.d/*.conf;
}

13.6Nginx性能优化总结

安全: 隐藏版本号 加密传输 csof 防盗链 refere 限制上传类型 访问控制acess waf防火墙 等

性能: 硬件 Epool模型 提高连接数 max gzip 压缩,降低带宽 expire sendfile高效文件传输 零拷⻉

十四、Nginx常见问题

14.1 Server优先级

Nginx 多个相同Server_name优先级,根据加载顺序加载。

1.环境准备

[root@nginx ~]# mkdir /soft/code{1..3} -p
[root@nginx ~]# for i in {1..3};do echo "<h1>Code $i</h1>" >
/soft/code"$i"/index.html;done

2.准备多份相同 Nginx 配置⽂件

[root@Nginx conf.d]# ll
总⽤量 12
-rw-r--r-- 1 root root 123 4⽉ 19 19:08 testserver1.conf
-rw-r--r-- 1 root root 123 4⽉ 19 19:09 testserver2.conf
-rw-r--r-- 1 root root 123 4⽉ 19 19:09 testserver3.conf

//内容如下
[root@Nginx conf.d]# cat testserver{1..3}.conf
server {
listen 80;
server_name testserver1 10.1.106.70;

location / {
root /soft/code1;
index index.html;
}
}
server {
listen 80;
server_name testserver2 10.1.106.70;
location / {
root /soft/code2;
index index.html;
}
}
server {
listen 80;
server_name testserver3 10.1.106.70;

location / {
root /soft/code3;
index index.html;
}

}
//检测语法
[root@Nginx conf.d]# nginx -t
nginx: [warn] conflicting server name "10.1.106.70" on 0.0.0.0:80, ignored
nginx: [warn] conflicting server name "10.1.106.70" on 0.0.0.0:80, ignored
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

//重启Nginx
[root@Nginx conf.d]# nginx -t

3.测试访问效果

[root@Nginx conf.d]# curl 10.1.106.70
<h1>Code 1</h1>
[root@Nginx conf.d]# mv testserver1.conf testserver5.conf
[root@Nginx conf.d]# nginx -s reload
[root@Nginx conf.d]# curl 10.1.106.70
<h1>Code 2</h1>

14.2 location优先级

⼀个 server 出现多个 location

完整匹配 优先级⾼
= 进⾏普通字符精确匹配, 完全匹配
^~ 表示普通字符匹配, 使⽤前缀匹配
正则匹配 匹配后会继续查找更精确匹配的location
~ 区分⼤⼩写匹配
~* 不区分⼤⼩写
/ 通⽤匹配(默认匹配)

1.实例准备

[root@Nginx conf.d]# cat testserver.conf
server {
listen 80;
server_name 10.1.106.70;
root /soft;
index index.html;

location = /code1/ {
rewrite ^(.*)$ /code1/index.html break;
}

location ~ /code* {
rewrite ^(.*)$ /code3/index.html break;
}

location ^~ /code {
rewrite ^(.*)$ /code2/index.html break;
}
}

2.测试效果

[root@Nginx conf.d]# curl http://10.1.106.70/code1/
<h1>Code 1</h1>

//注释掉精确匹配=, 重启Nginx
[root@Nginx ~]# curl http://10.1.106.70/code1/
<h1>Code 2</h1>

//注释掉^~, 重启Nginx
[root@Nginx ~]# curl http://10.1.106.70/code1/
<h1>Code 3</h1>

// 测试默认
[root@Nginx]# mkdir -p /soft/default/
[root@Nginx]# echo "default /" > /soft/default/index.html
[root@Nginx]# curl http://10.1.106.70/default/index.html
default /

14.3 try_files的使⽤

nginx try_files 按顺序检查⽂件是否存在

location / {
try_files $uri $uri/ /index.php;
}

#1.检查⽤户请求的uri内容是否存在本地,存在则解析
#2.将请求加/, 类似于重定向处理
#3.最后交给index.php处理

1.演示环境准备

[root@Nginx ~]# echo "Try-Page" > /soft/code/index.html
[root@Tomcat ~]# echo "Tomcat-Page" > /soft/tomcat-8080/webapps/ROOT/index.html

//启动tomcat
[root@Tomcat ~]# sh /soft/app/tomcat-8080/bin/startup.sh
//检查tomcat端⼝
[root@Tomcat ~]# netstat -lntp|grep 8080
tcp6	 0	 	0 :::8080 		:::* 	LISTEN
104952/java

2.配置 Nginx tryfiles

[root@Nginx ~]# cat /etc/nginx/conf.d/try.conf
server {
listen 80;
server_name 10.1.106.70;
root /soft/code;
index index.html;
location / {
try_files $uri @java_page;
}
location @java_page {
proxy_pass http://10.1.106.66:8080;
}
}

//重启Nginx
[root@Nginx ~]# nginx -s reload

3.测试tryfiles

[root@Nginx ~]# curl http://10.1.106.70/index.html
Try-Page

//将/soft/code/index.html⽂件移⾛
[root@Nginx ~]# mv /soft/code/{index.html,index.html_bak}

//发现由Tomcat吐回了请求
[root@Nginx ~]# curl http://10.1.106.70/index.html
Tomcat-Page

14.4 alias与root区别

root 路径配置

[root@Nginx ~]# mkdir /local_path/code/request_path/code/ -p
[root@Nginx ~]# echo "Root" > /local_path/code/request_path/code/index.html

//Nginx的root配置
[root@Nginx ~]# cat /etc/nginx/conf.d/root.conf
server {
listen 80;
index index.html;
location /request_path/code/ {
root /local_path/code/;
}
}

//请求测试
[root@Nginx conf.d]# curl http://10.1.106.70/request_path/code/index.html
Root

//实际请求本地⽂件路径为
/local_path/code/request_path/code/index.html

alias 路径配置

[root@Nginx ~]# mkdir /local_path/code/request_path/code/ -p
[root@Nginx ~]# echo "Alias" > /local_path/code/index.html

//配置⽂件
[root@Nginx ~]# cat /etc/nginx/conf.d/alias.conf
server {
listen 80;
index index.html;
location /request_path/code/ {
alias /local_path/code/;
#root /local_path/code/
}
}

//测试访问
[root@Nginx ~]# curl http://10.1.106.70/request_path/code/index.html
Alias

//实际访问本地路径
/local_path/code/'index.html'

14.5 获取⽤户真实IP

Nginx 传递⽤户的真实IP地址

$remote_addr 只能获取到最近⼀台服务器访问IP
x_forwarded_for 头部信息容易被篡改

14.6 常见HTTP状态码

200 正常请求
301 永久跳转
302 临时跳转
400 请求参数错误
401 账户密码错误(authorization required)
403 权限被拒绝(forbidden)
404 ⽂件没找到(Not Found)
413 ⽤户上传⽂件⼤⼩限制(Request Entity Too Large)
502 后端服务⽆响应(boy gateway)
504 后端服务执⾏超时(Gateway Time-out)

14.7 Nginx优化方案

Nginx优化
#安全
1.隐藏Nginx名称和版本号
2.Nginx加密传输优化
3.配置防盗链,防⽌资源被盗⽤
#访问控制
4.防DDOS、 cc攻击, 限制单IP并发请求连接
5.禁⽌通过IP地址访问,禁⽌恶意域名解析,只允许域名访问
6.限制上传资源⽬录被程序访问,防⽌⽊⻢⼊侵系统
#性能
1.gzip压缩
2.expires静态⽂件缓存
3.调整⽹络IO模型,调整Nginx worker进程的最⼤连接数
4.配置错误⻚⾯,根据错误代码指定⽹⻚反馈⽤户

14.9 Nginx架构总结

基于Nginx中间件的架构

  • 1.了解需求(定义Nginx在服务体系中的⻆⾊)
    • 静态资源服务的功能设计
      • 类型分类(视频、图⽚、 html)
      • 浏览器缓存
      • 防盗链
      • 流量限制
      • 防资源盗⽤
      • 压缩(压缩模式, 压缩⽐例, 压缩类型)
    • 代理服务
      • 协议类型
      • 正向代理
      • 反向代理
      • 负载均衡
      • 代理缓存
      • 头信息处理
      • Proxy_Pass
      • LNMP LNMT 等
      • 动静分离
  • 2.设计评估
    • 硬件 CPU、内存、磁盘 8H16 1G
    • 系统(⽤户权限、⽇志⽬录存放)
    • 代理服务/负载均衡 (CPU、内存)
    • 静态资源服务(硬盘容量、硬盘转速)
    • 动态资源服务(硬盘转速、读写效率)
    • 缓存资源服务(SSD固态)
  • 3.配置注意事项
    • 合理配置
    • 了解原理
      • http协议原理
    • http状态原理
      • 操作系统原理
  • 关注⽇志
    • ⽇志是否有打开
    • 是否有对应请求
    • 请求状态码信息符合
    • 错误⽇志信息吐出来
    • 错误⽇志内容和含义
posted on 2023-07-20 15:49  暗狱碳水  阅读(70)  评论(0编辑  收藏  举报