Nginx是一个很牛的高性能WEB和反向代理服务器,它具有很多非常优越的特性:
(1)在高连接并发情况下,nginx是apache服务器不错的替代品,能够支持高达5万个并发连接数的相应
(2)使用epoll and kqueue,作为开发模型
(3)Nginx作为负载均衡服务器: nginx既可以在内部直接支持和PHP程序对外进行服务,也可以支持作为HTTP代理服务器对外进行服务
(4)Nginx采用c进行编写,不论系统资源开销还是CPU使用效率都比Perlbal要好很多。
(1)高并发连接:官方测试能够支撑5万并发连接,在实际生产环境中跑到2-3万并发连接数
(2) 内存消耗少:在3万并发连接下,开启的10 个nginx进程才消耗150M内存(15M*10=150M)
(3)配置文件非常简单:风格跟程序一样通俗易懂
(4)成本低廉: nginx为开源软件,可以免费使用。而购买F5 BIG-IP、NetScaler等硬件负载均衡交换机则需要十多万至几十万人民币
(5)支持 Rewrite重写规则:能够根据域名、URL的不同,将HTTP请求分到不同的后端服务器群组
(6) 内置的健康检查功能:如果Nginx Proxy后端的某台Web服务器宕机了,不会影响前端访问
(7)节省带宽:支持GZIP压缩,可以添加浏览器本地缓存的Header头
(8)稳定性高:用于反向代理,宕机的概率微乎其微
(9)模块化设计:模块可以动态编译
(10)外围支持好:文档全,二次开发和模块较多(11)支持热部署:可以不停机重载配置文件
(12)支持事件驱动、AlO (Asynclo,异步l0)、mmap ( Memory Map,内存映射)等性能优化
(1)静态资源的web服务器,能缓存打开的文件描述符
(2 ) http、smtp、pop3协议的反向代理服务器
(3)缓存加速、负载均衡
(4)支持FastcGl(fpm,LNMP) ,uwSGl(Python)等
(5)模块化(非 DSo机制),过滤器zip、SSI及图像的大小调整
(6)支持SSL
(1)基于名称和IP的虚拟主机
(2)支持 keepalive
(3)支持平滑升级
(4)定制访问日志、支持使用日志缓冲区提高日志存储性能
(5)支持URL重写
(6)支持路径别名
(7)支持基于I及用户的访问控制
(8)支持速率限制,支持并发数限制
(1)使用nginx结合FastcGl运行PHP、JSP、Perl等程序
(2)使用nginx_作反向代理、负载均衡、规则过滤
(3)使用nginx运行静态HTML网页、图片
(4) nginx与其他新技术的结合应用
nginx的模块从结构上分为核心模块、基础模块和第三方模块
(1)HTTP模块、EVENT模块和MAIL模块等属于核心模块
(2)HTTP Access模块、HTTP FastCGl,模块、HTTP Proxy模块和HTTP Rewrite模块属于基本模块
(3)HTTP Upstream模块、Request Hash模块、Notice模块和HTTP Access Key模块属于第三方模块
nginx模块从功能上分为三类,分别是:
(1)Handlers(处理器模块)。此类模块直接处理请求,并进行输出内容和修改headers信息等操作。handlers 处理器模块一般只能有一个
(2)Filters(过滤器模块)。此类模块主要对其他处理器模块输出的内容进行修改操作,最后由nginx输出
(3)Proxies(代理器模块)。就是nginx的 HTTP Upstream之类的模块,这些模块主要与后端一些服务比如 fastcgi等操作交互,实现服务代理和负载均衡等功能
nginx模块分为:核心模块、事件模块、标准Http模块、可选 Http模块、邮件模块、第三方模块和补丁等
nginx,基本模块:所谓基本模块,指的是nginx默认的功能模块,它们提供的指令允许你使用定义nginx,基本功能的变量,在编译时不能被禁用,包括:
(1)核心模块:基本功能和指令,如进程管理和安全。常见的核心模块指令大部分是放置在配置文件的顶部
(2)事件模块:在 Nginx.内配置网络使用的能力。常见的events(事件)模块指令,=大部分是放置在配置文件的顶部
(3)配置模块:提供包含机制
1、Nginx进程模型
Nginx 默认采用多进程工作方式,Nginx启动后,会运行一个master进程和多个worker进程。其中master充当整个进程组与用户的交互接口,同时对进程进行监护,管理 worker进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。worker用来处理基本的网络事件,worker之间是平等的,他们共同竞争来处理来自客户端的请求。
在创建master进程时,先建立需要监听的socket(listenfd),然后从master进程中 fork()出多个worker进程,如此一来每个worker进程多可以监听用户请求的socket。一般来说,当一个连接进来后,所有在Worker都会收到通知,但是只有一个进程可以接受这个连接请求,其它的都失败,这是所谓的惊群现象。nginx,提供了一个accept_mutex (互斥锁),有了这把锁之后,同一时刻,就只会有一个进程在accpet,连接,这样就不会有惊群问题了。
先打开accept_mutex,选项,只有获得了accept_mutex的进程才会去添加accept事件。nginx.使用一个叫 ngx_accept_disabled 的变量来控制是否去竞争accept_mutex锁。ngx_accept_disabled = ngin…单进程的所有连接总数/ 8-空闲连接数量,当ngx_accept_disabled大于0时,不会去尝试获取accept_mutex锁,ngx_accept_disable越大,于是让出的机会就越多,这样其它进程获取锁的机会也就越大。不去 accept,每个worker进程的连接数就控制下来了,其它进程的连接池就会得到利用,这样,nginx,就控制了多进程间连接的平衡。
每个worker进程都有一个独立的连接池,连接池的大小是worker_connections。这里的连接池里面保存的其实不是真实的连接,它只是一个worker_connections大小的一个ngx_connection_t结构的数组。并且,nginx,会通过一个链表free_connections来保存所有的空闲ngx_connection_t,每次获取一个连接时,就从空闲连接链表中获取一个,用完后,再放回空闲连接链表里面。一个nginx…能建立的最大连接数,应该是worker_connections * worker_processes。当然,这里说的是最大连接数,对于HTTP请求本地资源来说,能够支持的最大并发数量是worker_connections * worker_processes,而如果是HTTP作为反向代理来说,最大并发数量应该是worker_connections * worker_processes/2。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服务的连接,会占用两个连接。
环境准备
配置好镜像源和关闭防火墙
[root@localhost ~]# ls /etc/yum.repos.d/
CentOS-Base.repo epel.repo epel-testing.repo
epel-modular.repo epel-testing-modular.repo
创建系统用户
[root@localhost ~]# useradd -rMs /sbin/nologin nginx
[root@localhost ~]# id nginx
uid=995(nginx) gid=992(nginx) groups=992(nginx)
安装开发工具包
[root@localhost ~]# yum -y groups mark install 'Development Tools'
创建日志存放路径
[root@localhost ~]# mkdir /var/log/nginx
[root@localhost ~]# chown -R nginx.nginx /var/log/nginx/
[root@localhost ~]# ll -d /var/log/nginx/
drwxr-xr-x. 2 nginx nginx 6 Oct 10 16:56 /var/log/nginx/
安装nginx
[root@localhost ~]# wget http://nginx.org/download/nginx-1.20.2.tar.gz
--2022-10-10 17:04:05-- http://nginx.org/download/nginx-1.20.2.tar.gz
Resolving nginx.org (nginx.org)... 3.125.197.172, 52.58.199.22, 2a05:d014:edb:5702::6, ...
Connecting to nginx.org (nginx.org)|3.125.197.172|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1062124 (1.0M) [application/octet-stream]
Saving to: ‘nginx-1.20.2.tar.gz’
nginx-1.20.2.tar.gz 100%[=================>] 1.01M 229KB/s in 6.9s
2022-10-10 17:04:13 (150 KB/s) - ‘nginx-1.20.2.tar.gz’ saved [1062124/1062124]
[root@localhost ~]# ls
anaconda-ks.cfg nginx-1.20.2.tar.gz
[root@localhost ~]# tar -zxf nginx-1.20.2.tar.gz -C /usr/src/
预编译
[root@localhost nginx-1.20.2]# cd /usr/local/nginx-1.20.2/
./configure \
--prefix=/usr/local/nginx \
--user=nginx
--group=nginx \
--with-debug \
--with-http_ssl_module \
--with-http _realip_module \
--with-http_image_filter_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log
[root@localhost nginx-1.20.2]# make
[root@localhost nginx-1.20.2]# make install
配置环境变量以便启动nginx
[root@localhost nginx-1.20.2]# echo 'export PATH=/usr/local/nginx/sbin:$PATH' > /etc/profile.d/nginx.sh
[root@localhost nginx-1.20.2]# . /etc/profile.d/nginx.sh
[root@localhost nginx-1.20.2]# nginx
[root@localhost nginx-1.20.2]# ss -antl
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
//启动nginx,并查看端口情况服务控制方式,使用nginx命令
-t 检查配置文件语法
-v 输出nginx的版本
-c 指定配置文件路径
-s 发送服务控制信号,可选值有stop、auit、reopen、reload
主配置文件:/usr/local/nginx/nginx.conf
默认启动nginx时,使用的配置文件是:安装路径/conf/nginx.conf
可以在启动nginx时通过-c选项来指定要读取的配置文件
//nginx常见的配置文件及其作用
nginx.conf nginx的基本配置文件
mime.types MIME类型关联的扩展文件
fastcgi.conf 与fastcgi相关的配置
proxy.conf 与proxy相关的配置
sites.conf 配置nginx,提供的网站,包括虚拟主机
以下PHP-MySQL都是源码安装,可以参考之前我写的
MySQL安装
[root@my ~]# ss -antl | grep 3306
LISTEN 0 80 *:3306 *:*
PHP配置
部署成功后在配置以下内容
[root@node1 php-fpm.d]# pwd
/usr/local/php7/etc/php-fpm.d
listen = 0.0.0.0:9000
listen.allowed_clients = 192.168.47.137
[root@node1 php-fpm.d]# ss -antl | grep 9000
LISTEN 0 128 0.0.0.0:9000 0.0.0.0:*
网页测试目录
[root@node1 php-fpm.d]# mkdir /var/www/html -p
[root@node1 php-fpm.d]# cd /var/www/html/
[root@node1 html]# ls
[root@node1 html]# vim index.php
[root@node1 html]# useradd -Mrs /sbin/nologin nginx
[root@node1 html]# id nginx
uid=975(nginx) gid=974(nginx) groups=974(nginx)
[root@node1 html]# chown -R nginx.nginx /var/www/html/
[root@node1 html]# ll
total 4
-rw-r--r-- 1 nginx nginx 21 Oct 11 19:02 index.php
[root@localhost conf]# cd /usr/local/nginx/conf
[root@localhost conf]# vim nginx.conf
location / {
root html;
index index.php index.html index.htm;
}
location ~ \.php$ {
root /var/www/html;
fastcgi_pass 192.168.47.50:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
include fastcgi_params;
}
拿nginxip访问
[root@localhost conf]# ss -antl | grep 80
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
//平滑升级的步骤
1、获取之前的编译参数
2、下载新模块
3、重新编译软件,加上–add-module=新模块的解压路径
4、停止服务并备份原程序
5、把源程序用新程序覆盖
6、启动新程序
1、基于之前部署的nginx
确保网页可以访问,使用自己的手机热点和其他设备即可
[https://github.com/openresty/echo-nginx-module]
下载到本地
[root@localhost ~]# wget https://github.com/openresty/echo-nginx-module
解压
[root@localhost ~]# unzip echo-nginx-module-master.zip
2、获取之前安装nginx的编译参数
这里nginx软件包推荐使用nginx-1.20.0版本
查看自己原来二进制安装的nginx模块,复制一下
[root@localhost ~]# nginx -V
nginx version: nginx/1.20.0
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC)
built with OpenSSL 1.1.1k FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log
重新压缩一份nginx
[root@localhost ~]# tar -zxf nginx-1.20.0.tar.gz
重新预编译软件
[root@localhost nginx-1.20.0]# ./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-debug \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_image_filter_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--add-module=../echo-nginx-module-master
//添加成功
[root@localhost nginx-1.20.0]# make
sed -e "s|%%PREFIX%%|/usr/local/nginx|" \
-e "s|%%PID_PATH%%|/usr/local/nginx/logs/nginx.pid|" \
-e "s|%%CONF_PATH%%|/usr/local/nginx/conf/nginx.conf|" \
-e "s|%%ERROR_LOG_PATH%%|/var/log/nginx/error.log|" \
< man/nginx.8 > objs/nginx.8
make[1]: Leaving directory '/root/nginx-1.20.0'
objs目录以有nginx这个可执行程序
[root@localhost nginx-1.20.0]# cd objs/
[root@localhost objs]# ls
addon Makefile nginx.8 ngx_auto_headers.h ngx_modules.o
autoconf.err nginx ngx_auto_config.h ngx_modules.c src
3、备份源程序并停止、覆盖、启动服务
//先查看升级前和升级后的版本区别,主要看编译参数
//升级前
[root@localhost nginx-1.20.0]# objs/nginx -V
nginx version: nginx/1.20.0
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC)
built with OpenSSL 1.1.1k FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --add-module=../echo-nginx-module-master
重新停止启动下nginx,以便程序识别
[root@localhost nginx-1.20.0]# nginx -s stop
将其原有的程序备份到/opt下
[root@localhost nginx-1.20.0]# cp /usr/local/nginx/sbin/nginx /opt/
在用新的版本覆盖掉旧的版本
[root@localhost nginx-1.20.0]# cp objs/nginx /usr/local/nginx/sbin/
cp: overwrite '/usr/local/nginx/sbin/nginx'?
[root@localhost nginx-1.20.0]# /usr/local/nginx
nginx/ nginx-1.20.2/
[root@localhost nginx-1.20.0]# /usr/local/nginx/sbin/nginx
[root@localhost nginx-1.20.0]# ss -antl
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
[root@localhost nginx-1.20.0]# nginx -V
nginx version: nginx/1.20.0
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC)
built with OpenSSL 1.1.1k FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --add-module=/root/echo-nginx-module-master
4、测试–引用echo模块
#access_log logs/host.access.log main;
location / {
echo "good time";
}
可以使用windos系统中的cmd进行
C:\Users\goodtime>curl 192.168.47.137
good time
location区段,通过指定模式来与客户端请求的URI相匹配
功能:
允许根据用户请求的URI来匹配定义的各个location,匹配时,此请求将被相应的location配置块中的配置所处理,例如做访问控制等功能
语法:
location [修饰符] pattern {…}
修饰符
= 精确匹配
~ 正则表达式模式匹配,区分大小写
~* 正则表达式模式匹配,不区分大小写
^~ 前缀匹配,类似于无修饰符的行为,也是以指定模块开始,不同的是,如果模式匹配,那么就停止搜索其他模式了,不支持正则表达式
@ 定义命名location区段,这些区段客户端不能访问,只可以由内部产生的请求来访问,如try_files或者error_page等
1、定义一个测试字段
[root@localhost sbin]# vim /usr/local/nginx/conf/nginx.conf
location /hhh {
echo "good time";
}
[root@localhost sbin]# ./nginx -s reload
//可见不按添加的字段访问的话显示不了输出值
C:\Users\goodtime>curl 192.168.47.137
Welcome to nginx!
C:\Users\goodtime>curl 192.168.47.137/hhh
good time
2、= 精确匹配
//如果输出别的就报错
C:\Users\goodtime>curl 192.168.47.137 /hhh
Welcome to nginx!
3、 ~ 区分大小写,且以绝对路径为搜索(只要在里面即可)
C:\Users\goodtime>curl 192.168.47.137/hhH
404 Not Found
//后面可以加任意的数值
C:\Users\goodtime>curl 192.168.47.137/hhhdadadawqeqw
good time
4、 ~* 不区分大小写
C:\Users\goodtime>curl 192.168.47.137/hHh
good time
5、^~ 以数值开头的部分匹配
C:\Users\goodtime>curl 192.168.47.137/hhh
good time
优先级顺序,这里如果一切添加到里面的话按优先级顺序来匹配规则
查找顺序和优先级:由高到低
1、带有“=”的精确匹配优先
2、正则表达式按照他们在配置文件中定义的顺序
3、带有“^~”修饰符的,开头匹配
4、带有或者*修饰符的,如果正则表达式与URI匹配
5、没有修饰符的精确匹配
location = 路径
location ^~ 路径
location ~ 正则(例如/hhh的后面需要添加$,以这个为结尾)
location ~* 正则
location 路径
1 =
2 ^~
3 ~*
4 ~
5 无数
//用于location段
Allow:设定允许哪台或哪些主机访问,多个参数间用空格隔开
Deny:设定禁止那台或哪些主机访问,多个参数间用空格隔开
比如:
allow 192.168.47.137 192.168.47.136;等
deny all;
//本地cmd系统中查看ip
C:\Users\goodtime>ipconfig
以太网适配器 VMware Network Adapter VMnet8:
连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::70bb:164a:9969:5e53%21
IPv4 地址 . . . . . . . . . . . . : 192.168.47.1
子网掩码 . . . . . . . . . . . . : 255.255.255.0
模拟拒绝本机访问nginx状态页面
location /status {
echo "chenyu";
deny 192.168.47.1; //本机ip
C:\Users\goodtime>curl 192.168.47.137/status
404 Not Found
404 Not Found
nginx/1.20.2
//开启stub_status模块
stub_status模块主要作用于查看nginx的一些状态信息
location /status {
stub_status on;
}
状态
C:\Users\goodtime>curl 192.168.47.137/status
Active connections: 1
server accepts handled requests
8 8 6
Reading: 0 Writing: 1 Waiting: 0
解析:
Active connections:当前nginx正在处理的活动连接数
Server accepts handled requests:nginx总共处理了63个连接,成功创建63次握手,总共处理了62个请求
Reading:nginx读取到客户端的Header信息数
Writing:nginx返回给客户端的Header信息数
Waiting:开启keep-alive的情况下,这个值等于active-(reading+writing),意思就是nginx已经处理完成,正在等候下一次请求指令的驻留连接。所以,在访问效率高、请求很快就被处理完毕的情况下,waiting数比较多是正常的。如果reading+writing数较多,则>说明并发访问量非常大,正在处理过程中。
//当allow all存在时,允许其他ip访问
location /status {
stub_status on;
allow 192.168.47.1;
allow all;
}
测试,本机成功
C:\Users\goodtime>curl 192.168.47.137/status
Active connections: 1
server accepts handled requests
8 8 8
Reading: 0 Writing: 1 Waiting: 0
模拟在另一台虚拟机网页中访问主机ip
[root@my ~]# ip a | grep ens32
2: ens32: mtu 1500 qdisc _codel state UP group default qlen 1000
inet 192.168.47.136/24 brd 192.168.47.255 scope global noprefixroute ens32
可以ping通nginx主机
[root@my ~]# ping 192.168.47.137
PING 192.168.47.137 (192.168.47.137) 56(84) bytes of data.
64 bytes from 192.168.47.137: icmp_seq=1 ttl=64 time=0.408 ms
[root@my ~]# curl 192.168.47.137/status
Active connections: 1
server accepts handled requests
13 13 13
Reading: 0 Writing: 1 Waiting: 0
当添加deny后
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
location /status {
stub_status on;
allow 192.168.47.1;
deny all;
}
[root@localhost ~]# nginx -s reload
失败
[root@my ~]# curl 192.168.47.137/status
403 Forbidden
在测试添加136访问
allow 192.168.47.136;
[root@localhost ~]# nginx -s reload
//成功
[root@my ~]# curl 192.168.47.137/status
Active connections: 1
server accepts handled requests
16 16 16
Reading: 0 Writing: 1 Waiting: 0
为虚拟机用户添加一组加密信息,这样在登录虚拟机界面时候会让其输入加密密码,保证其安全性
//授权用户
安装httpd-tools软件包
[root@localhost ~]# yum -y install httpd-tools
//创建用户密钥文件
[root@localhost ~]# cd /usr/local/nginx/conf/
//这里的密码为加密后的密码串,建议用htpasswd来创建文件,这里创建的jr用户是不存在系统中的
[root@localhost conf]# htpasswd -c -m .user_auth_file jr
New password:
Re-type new password:
Adding password for user jr
//密码信息
[root@localhost conf]# cat .user_auth_file
jr:$apr1$ma8B3sAP$r24RhqreiU0O2pqBLnUNq/
//配置nginx(注意auth_basic_user_file必须用绝对路径)
[root@localhost conf]# vim nginx.conf
[root@localhost conf]# nginx -s reload
location /status {
stub_status on;
auth_basic "欢迎光临";
auth_basic_user_file "/usr/local/nginx/conf/.user_auth_file";
}
Nginx:192.168.47.137
CA:192.168.47.136
//在CA服务器中生成一对密钥
[root@CA ~]# mkdir -p /etc/pki/CA/private
[root@CA ~]# cd /etc/pki/CA/
//生成私钥
[root@CA CA]# (umask 077;openssl genrsa -out private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus (2 primes)
.....+++++
...........+++++
e is 65537 (0x010001)
//生成公钥
[root@CA CA]# openssl rsa -in private/cakey.pem -pubout
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuQfU9CLxicvy7XggXSSB
KJp/6VrVd6iHqG8Rfv89kx0X/AOXPKFHrTDiDj1fxwTNDOhPNSTXXVybxgjAdfXT
03DmbgFYoXp6C+SqeetdiDD3NbIBRJjyFb5bgXXt0Se11vN0oDPzp6PowRH+VhFI
gfsvdjpMvaDmuEoYwnefA5SjP4gO4i0CNdu8PSy/JFgXz7NGinp4Eiqxt5Ljtthj
IljqH6yIbuYoao2oW0GrPfFe5hhkKu8cXredNhFD5uz9HJU/ziwPecVqo88FC2af
8GtQCfBGRTewqkoTcLLoIsPum58aVvomnF0t5IU0hcpGl7jlqndk6dnBlqGNTrOp
OwIDAQAB
-----END PUBLIC KEY-----
生成自属签名颁发证书,并导入到cacert.pem中
[root@CA CA]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 1024
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HB
Locality Name (eg, city) [Default City]:WH
Organization Name (eg, company) [Default Company Ltd]:HH^H
Organizational Unit Name (eg, section) []:linux
Common Name (eg, your name or your server's hostname) []:LL
Email Address []:[email protected]
//在nginix中生成证书签署请求,发送给CA
[root@localhost ~]# cd /usr/local/nginx/conf/
//生成私钥
[root@localhost conf]# (umask 077;openssl genrsa -out httpd.key 2048)
Generating RSA private key, 2048 bit long modulus (2 primes)
......+++++
...................................+++++
e is 65537 (0x010001)
//在生成一个请求,保持一个合同同步允许确认证书通过
[root@localhost conf]# openssl req -new -key httpd.key -days 1024 -out httpd.csr
Ignoring -days; not generating a certificate
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HB
Locality Name (eg, city) [Default City]:WH
Organization Name (eg, company) [Default Company Ltd]:HH^H
Organizational Unit Name (eg, section) []:linux
Common Name (eg, your name or your server's hostname) []:LL
Email Address []:[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@localhost conf]# ls
httpd.csr httpd.key
//发送证书
[root@localhost conf]# scp httpd.csr [email protected]:/root/
[email protected]'s password:
httpd.csr 100% 1017 723.0KB/s 00:00
//在CA主机中查看
[root@CA ~]# ls
anaconda-ks.cfg httpd.csr
//CA签署证书并发送给NGINX
[root@CA ~]# mkdir /etc/pki/CA/newcerts //将来颁发证书的存放路径
[root@CA ~]# touch /etc/pki/CA/index.txt //网页数据显示
[root@CA ~]# echo "01" > /etc/pki/CA/serial //设置序列号
//重新对证书进行签名,并生成httpd.crt
[root@CA ~]# openssl ca -in httpd.csr -out httpd.crt -days 1024
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Oct 13 09:50:22 2022 GMT
Not After : Aug 2 09:50:22 2025 GMT
Subject:
countryName = CN
stateOrProvinceName = HB
organizationName = HH\08
organizationalUnitName = linux
commonName = LL
emailAddress = [email protected]
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
B9:E3:DC:E2:75:93:5A:8C:82:FD:80:30:75:99:CC:C5:5A:95:3B:56
X509v3 Authority Key Identifier:
keyid:2C:A2:DB:98:54:06:EB:2D:24:A8:84:E4:8E:71:36:D0:70:88:BC:2D
Certificate is to be certified until Aug 2 09:50:22 2025 GMT (1024 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
[root@CA ~]# ls
anaconda-ks.cfg httpd.crt httpd.csr
//将CA签署的证书httpd.crt和服务器的证书cacert.pem(密钥信息)发送给nginx
[root@CA ~]# scp httpd.crt [email protected]:/usr/local/nginx/conf/
The authenticity of host '192.168.47.137 (192.168.47.137)' can't be established.
ECDSA key fingerprint is SHA256:cdmo9f87/nd53T0zrSlRNvEDKskgEb2tSwNZINSW84U.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.47.137' (ECDSA) to the list of known hosts.
[email protected]'s password:
httpd.crt 100% 4517 2.8MB/s 00:00
[root@CA ~]# scp /etc/pki/CA/[email protected]:/usr/local/nginx/conf/
[email protected]'s password:
cacert.pem 100% 1367 1.4MB/s 00:00
//nginx配置https
[root@localhost conf]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 443 ssl; //监听443加密
server_name localhost;
ssl_certificate httpd.crt; //证书位置
ssl_certificate_key httpd.key; //私钥信息
ssl_session_cache shared:SSL:1m; //链接缓存
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
[root@localhost conf]# nginx -s reload
[root@localhost html]# echo "jrhh" > index.html
[root@localhost html]# nginx -s reload
和apache等web服务软件一样,rewrite的主要功能是实现URL地址的重定向。Nginx的rewrite功能需要PCRE软件的支持,即通过perl兼容正则表达式语句进行规则匹配的。默认参数编译nginx就会支持rewrite的模块,但是也必须要PCRE的支持
Rewirte功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标记位实现URL重写以及重定向。
Rewrite只能放在server{},location{},if{}中,并且默认只能对域名后边的除去传递参数外的字符串起作用。例如http://www.cy.com/abc/aa/index.php?a=1&b=2 只对/abc/aa/index.php重写
URL:就是具体路径/位置
URI:指的是一个拥有相同类型/特性的对象集合
URL地址俗称网页地址,简称网址,是用于完整地描述Internet上网页和其他资源地址的字符串
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0uDhliX2-1666173614317)(./1665804328382.png)]
Nginx:通过ngx_http_rewrite_module模块支持URL重写,支持if条件判断,但不支持else。
跳转:从一个location跳转到另一个location,循环最多可以执行10次,超过后nginx将返回500错误。
PCRE支持:perl兼容正则表达式的语法规则匹配
重写模块set指令:创建新的变量并设其值
//语法格式:
rewrite [flag];
regex:表示正则匹配规则
replacement:表示跳转后的内容
flag:表示rewrite支持的flag标记
//flag标记说明:
last:本条规则匹配完成后,继续向下匹配新的location URL规则,一般用在server和if中。
break:本条规则匹配完成即终止,不在匹配后面的任何规则,一般使用在location中。
redirect:返回302临时重定向代表临时跳转,当用户访问一个页面时,服务器会返回一个302状态码,告诉浏览器该页面已被重定向。就必须手动地将浏览器重定向到新的URL上,浏览器地址会显示跳转后的URL地址
permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址。
匹配正则的标识符和意义
^ 必须以^后的实体开头
$ 必须以$前的实体结尾
. 匹配任意单个字符
[] 匹配指定字符集的任意字符
[^] 匹配任何不包括在指定字符集内的任意字符串
| 匹配|之前或之后的实体
() 分组,组成一组用于匹配的实体,通常会有|来协助
\ 转义
(pattern) 匹配括号内pattern并可以在后面获取对应的匹配,常用$0-9 属性获取小括号中匹配的内容。 如 ( h e l l o ∣ c h e n y u ) 9属性获取小括号中匹配的内容。如^(hello | chenyu)9属性获取小括号中匹配的内容。如(hell**o∣cheny**u) //字符串为“hello chenyu”,可以捕获的结果为:
$1=hello$2=chenyu 这些被捕获的数据,在后面就可以当作变量一样进行使用了
nginx的rewrite功能在企业里应用非常广泛
1、可以调整用户浏览的URL,看起来更规范,合乎开发及产品人员的需求
2、为了让搜索引擎搜录网站内容及用户体验更好,企业会将动态的URL地址伪装成静态地址提供服务
3、网址更新域名后,让旧的访问跳转到新的域名上,例如访问京东的360buy.com会跳转到jd.com
4、根据特殊变量、目录、客户端的信息进行URL调整等。
//nginx访问小李子自定义网页
[root@localhost ~]# cd /usr/local/nginx/html/
[root@localhost html]# ls
50x.html index.html
[root@localhost html]# mkdir imgs
[root@localhost html]# cd imgs/
[root@localhost images]# ls
xlz.jpg
[root@localhost imgs]# vim /usr/local/nginx/conf/nginx.conf
location = /imgs {
}
[root@localhost imgs]# nginx -s reload
确实帅!
break:本条规则匹配完成即终止,不在匹配后面的任何规则,一般使用在location中。
//需要写rewrite
//网页的绝对路径是/images/,但做一个变量就不同了
[root@localhost html]# vim /usr/local/nginx/conf/nginx.conf
location = /imgs {
rewrite ^/imgs/(.*\.jpg)$ /images/$1 break; //$定义正则表达式访问网页
}
[root@localhost images]# nginx -s reload
访问的依旧是imgs
//还可以使用break,让我们访问得站点跳转到百度得首页
location /imgs {
rewrite ^/imgs/(.*.jpg)$ http://www.baidu.com break;
}
last:本条规则匹配完成后,继续向下匹配新的location URL规则,一般用在server和if中。
//匹配多个数值,跳转到免费听歌网站中(分享)
[root@localhost html]# vim /usr/local/nginx/conf/nginx.conf
location /imgs {
rewrite ^/imgs/(.*\.jpg)$ /images/$1 last;
}
location /images {
rewrite ^/images/(.*\.jpg)$ https://music.y444.cn/#/ last;
}
[root@localhost html]# nginx -s reload
//可以用来一边学习一边听jay的歌
redirect:返回302临时重定向代表临时跳转,当用户访问一个页面时,服务器会返回一个302状态码,告诉浏览器该页面已被重定向。就必须手动地将浏览器重定向到新的URL上,浏览器地址会显示跳转后的URL地址
location /imgs {
rewrite ^/imgs/(.*\.jpg)$ /images/$1 redirect;
}
//按F12进行状态监测
F5刷新网页
返回301永久重定向,浏览器地址栏会显示跳转后的URL地址。
[root@localhost html]# vim /usr/local/nginx/conf/nginx.conf
location /imgs {
rewrite ^/imgs/(.*\.jpg)$ /images/$1 permanent;
}
[root@localhost html]# nginx -s reload
可以使用在server段和location段
语法:
if (condition) {…}
常见的condition:
(1)变量名
(2)以变量名为操作数构成的比较表达式(可使用=,!=类似的比较符进行测试)
(3)正则表达式的模式匹配操作
假如现在公司旧的域名www.lty.com有业务需求,需要使用新的域名www.liutianyang.com代替,但是旧域名不能废除,需要跳转到新的域名上,而且后面的参数保持不变
//修改nginx服务器主机名为www.lty.com
[root@localhost html]# hostnamectl set-hostname www.lty.com
[root@localhost html]# bash
[root@www html]#
//将本机两个域名映射关系写入到/etc/hosts中,并传给客户端
[root@localhost html]# vim /etc/hosts
192.168.47.137 www.lty.com
192.168.47.137 www.liutianyang.comm
[root@localhost html]# scp /etc/hosts [email protected]:/etc/hosts
[email protected]'s password:
hosts 100% 220 42.1KB/s 00:00
//修改配置文件,写入rewrite和if结合使用
[root@www html]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name www.lty.com;
location / {
if ($host = 'www.lty.com') {
rewrite ^/(.*)$ http://www.liutianuang.com/$1 permanent;
}
root html;
index index.html index.htm;
[root@www html]# echo "This is a test" > /usr/local/nginx/html/index.html
[root@www html]# nginx -s reload
//客户端使用浏览器访问–http://www.lty.com—我们会发现自动跳转到新的域名www.liutianuang.com中
假如今天公司业务新版本上线,要求所有ip访问任何内容都显示一个固定维护页面,只有公司ip:192.168.47.50访问正常
[root@www html]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name www.lty.com;
set $rewrite true; //开启重写规则
if ($remote_addr = "192.168.47.50") { //如果判断等于对应的ip则成立
set $rewrite false; //关闭重写
}
if ($rewrite = true) { //当变量判断是其他ip成立时
rewrite (.+) /weihu.html; //.+代表配合任何ip并以/网页状态显示
}
[root@www html]# nginx -s reload
//新建/var/www/html目录,并往该目录下写入文件weihu.html,内容为weihu
[root@www html]# mkdir /var/www/html -p
[root@www html]# echo "in weihuing" > /var/www/html/weihu.html
验证:
50客户端访问
137端访问
[root@www html]# curl http://www.lty.com
in weihuing
//在/usr/local/nginx/html目录中创建如下目录和文件
[root@www html]# mkdir firefox chrome
[root@www html]# echo "firefox test" > firefox/index.html
[root@www html]# echo "chrome test" > chrome/index.html
//修改配置文件
[root@www html]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name localhost;
location / {
if ($http_user_agent ~ Firefox) {
rewrite ^(.*)$ /firefox/$1 break;
}
if ($http_user_agent ~ Chrome) {
rewrite ^(.*)$ /chrome/$1 break;
}
root html;
index index.html index.htm;
}
#charset koi8-r;
#access_log logs/host.access.log main;
location /firefox {
root html;
index index.html;
}
location /chrome {
root html;
index index.html;
}
[root@www html]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@www html]# nginx -s reload
验证
1、chrome谷歌浏览器访问
2、Firefox浏览器访问
了解防盗链的原理之前,我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候,一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。
后台服务器可以根据获取到的这个Referer信息来判断是否为自己信任的网站地址,如果是则放行继续访问,如果不是则可以返回403(服务端拒绝访问)的状态信息。
语法:
valid_referers none blocked server_names string
[root@www html]# mkdir abc
[root@www html]# cd abc/
[root@www abc]# ls
悟蓝.png
[root@www abc]# vim /usr/local/nginx/conf/nginx.conf
location ~* \.(jpg|png) {
root html/abc;
}
[root@www abc]# nginx -s reload
//使用命令查看referer信息,此时还未配置防盗链](https://img-blog.csdnimg.cn/a37ddec96be740919d774758e2c9ebaf.png)
[root@www abc]# curl --referer http://baidu.com -I http://192.168.47.137/悟 蓝.png
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Sat, 15 Oct 2022 02:57:12 GMT
Content-Type: image/png
Content-Length: 540902
Last-Modified: Sat, 15 Oct 2022 02:50:36 GMT
Connection: keep-alive
ETag: "634a1ffc-840e6"
Accept-Ranges: bytes
这里的状态也是没有标头的
![(img-qMmq8inY-1666173614326)(./1665802902479.png)]](https://img-blog.csdnimg.cn/37419da8250649189bf993c83695dd1c.png)
[root@www html]# vim /usr/local/nginx/conf/nginx.conf
location ~* \.(jpg|png) { //以~开始正则匹配(jpg|png)为结尾的后缀
root html/abc;
valid_referers blocked www.cy.com; //如果返回的头部referer为www.lty.com那么就不会执行valid_referer下面内容
if ($invalid_referer) { //反之则会生成防盗链
return 403;
break;
}
}
[root@www html]# nginx -s reload
这里不用加none参数,这种形式的访问是直接请求服务器中默认html中的1.jpg文件,是没有头部的(只有二次以上请求才会有referer头部),并且我们在配置文件中添加了[none]这个参数,它的含义就是当我们在没有头部referer时,依然能访问到文件,所以我们配置的防盗链在这个时候是不起作用的。
验证:
[root@www html]# curl --referer http://baidu.com -I http://192.168.47.137/悟蓝.png
HTTP/1.1 403 Forbidden
Server: nginx/1.20.2
Date: Sat, 15 Oct 2022 03:19:57 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive
说到代理,首先我们要明确一个概念,所谓代理就是一个代表、一个渠道;
此时就设计到两个角色,一个是被代理角色,一个是目标角色,被代理角色通过这个代理访问目标角色完成一些任务的过程称为代理操作过程;如同生活中的专卖店~客人到某达斯专卖店买了一双鞋,这个专卖店就是代理,被代理角色就是某达斯厂家,目标角色就是用户
这样的代理模式称为正向代理,正向代理最大的特点是客户端非常明确要访问的服务器地址;服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;正向代理模式屏蔽或者隐藏了真实客户端信息。
多个客户端给服务器发送的请求,nginx服务器接收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理了。此时~请求的来源也就是客户端是明确的,但是请求具体由哪台服务器处理的并不明确了,nginx扮演的就是一个反向代理角色
反向代理,主要用于服务器集群分布式部署的情况下,反向代理隐藏了服务器的信息!
//在实际生产项目中,大部分的就是正向代理和反向代理结合起来使用
我们在实际项目操作时,正向代理和反向代理很有可能会存在在一个应用场景中,正向代理代理客户端的请求去访问目标服务器,目标服务器是一个反向代理服务器,反向代理了多台真实的业务处理服务器
主机 | Ip | 安装 | 系统 |
---|---|---|---|
Nginx | 192.168.47.137 | Nginx | RHEL8 |
Rs1 | 192.168.47.136 | Httpd | RHEL8 |
Rs2 | 192.168.47.50 | Httpd | RHEL8 |
//三台主机都关闭防火墙和selinux,还需要配置好yum仓库
//nginx主机部署nginx服务,之前已经部署好了,我这里就不演示了
//rs1主机上,安装httpd,然后添加一个测试网页
[root@rs1 ~]# yum -y install httpd
[root@rs1 ~]# systemctl restart httpd
[root@rs1 ~]# systemctl enable --now httpd
[root@rs1 ~]# echo "This is a server1" > /var/www/html/index.html
[root@rs1 ~]# cat /var/www/html/index.html
This is a server1
[root@rs1 ~]# systemctl restart httpd
//rs2主机上,安装httpd,然后添加一个测试网页
[root@rs2 ~]# yum -y install httpd
[root@rs2 ~]# systemctl restart httpd.service
[root@rs2 ~]# systemctl enable --now httpd.service
[root@rs2 ~]# echo "This is a server2" > /var/www/html/index.html
[root@rs2 ~]# systemctl restart httpd.service
//在nginx主机上,修改配置文件,设置负载均衡
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream webserver { //定义负载模块为webserver
server 192.168.47.136;
server 192.168.47.50;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://webserver;
}
[root@www ~]# nginx -t //检查配置文件是否正确
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@www ~]# nginx -s reload
//用nginx ip访问
server2
负载均衡设置成功
如果想其中一台后端真实服务器数据量足够,多承担一些访问量,可以去用weight设置请求访问的权重
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream webserver {
server 192.168.47.136 weight=2; ///添加此行
server 192.168.47.50;
}
[root@www ~]# nginx -s reload
重载nginx并测试访问,此时会发现47.136 主机(rs1)访问时访问2次后,才轮询到rs2中
//此时,我们发现三台主机都是使用80端口,所以在nginx配置文件中使用的upstream中,对应的真实后端服务器。假若我们并没有设置端口,如果其中某台后端服务器使用8080端口呢?我们如何进行设置,rs1为8080端口,rs2为80端口
//首先修改rs1的httpd服务,侦听8080端口,并重启httpd服务
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream webserver {
server 192.168.47.136:8080 weight=2;
server 192.168.47.50:80;
}
[root@www ~]# nginx -s reload
//第一台服务端修改端口
[root@rs1 ~]# vim /etc/httpd/conf/httpd.conf
Listen 8080
[root@rs1 ~]# systemctl restart httpd
[root@rs1 ~]# ss -antl | grep 8080
LISTEN 0 128 *:8080 *:*
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream webserver {
ip_hash
server 192.168.47.136:8080 weight=2;
server 192.168.47.50:80;
}
[root@www ~]# nginx -s reload
ip_hash这种负载均衡模式根据个人理解就是:例如多个用户通过nginx访问到了后端的httpd集群中,这个时候因为有不同用户,所以ip也不同,ip+hash算法计算的hash值都传到了httpd,nginx就记录了这个ip和hash值,那么下次同一个ip过来还是会分配到这个httpd的。
还是基于上面的环境额外添加一台tomcat
Tomcat:192.168.47.50
//想要部署tomcat可以看我之前jenkins服务部署中的tomcat,此时我就省略掉了,部署好了后,我们来测试访问以下基于tomcat的动态测试网页
nginx端部署
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream static {
server 192.168.47.136;
server 192.168.47.148 weight=2;
}
upstream tomcat { //动态测试
server 192.168.47.50:8080;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://static;
}
location /jenkins {
proxy_pass http://tomcat;
}
[root@www ~]# nginx -s reload
静态页面访问成功
动态访问