参考Nginx学习 | 何叨叨的个人博客 (heyingjiee.github.io)和尚硅谷Nginx教程-bilibili,感谢作者和尚硅谷。
Nginx介绍
虚拟机安装就略过了。
-
Nginx开源版 http://nginx.org/en/
官方原始的Nginx版本
-
Nginx plus商业版
开箱即用,集成了大量功能
-
Open Resty https://openresty.org/cn/
OpenResty是一个基于Nginx与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。更适用于需要大量二次开发的场景,有极强的扩展性
-
Tengine https://tengine.taobao.org/
由淘宝网发起的Web服务器项目。它在Nginx 的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网 ,天猫商城 等得到了很好的检验。相比于Open Resty,扩展性不够强,但是能够满足绝多数使用场景
Nginx安装
下载Nginx官方安装包http://nginx.org/en/download.html
1.解压安装包
上传到虚拟机目录里,我将安装包解压到了/usr/software/
下,使用命令tar -zxvf
进行解压,得到/usr/software/nginx-1.23.3
。
2.安装依赖库
#安装C编译器 yum install -y gcc #安装pcre库 yum install -y pcre pcre-devel #安装zlib yum install -y zlib zlib-devel
3.安装
./configure --prefix=/usr/local/nginx #使用prefix选项指定安装的目录 make make install
4.启动
cd /usr/local/nginx/sbin ls # 里面是一个nginx的可执行文件 ./nginx # 启动这个可执行
5.关闭防火墙
systemctl stop firewalld
6.补充Nginx命令
./nginx -s stop #快速停止 ./nginx -s quit #完成已接受的请求后,停止 ./nginx -s reload #重新加载配置 ./nginx -t #检查nginx配置是否正确
7.查看nginx状态
ps -ef | grep nginx
启动时:
可以看到master进程和worker进程都存在。如果nginx处在停止状态,则只会有最下面一个的进程,master
和worker
进程都不会存在。
8.注册系统服务,通过系统服务的方式启动nginx
(1)创建服务脚本:vim /usr/lib/systemd/system/nginx.service
(2)其中的内容为:
如果安装的目录不是在/usr/local/nginx下的话,需要修改目录地址。
[Unit] Description=nginx After=network.target remote-fs.target nss-lookup.target [Service] Type=forking 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 ExecQuit=/usr/local/nginx/sbin/nginx -s quit PrivateTmp=true [Install] WantedBy=multi-user.target # 多用户
(3)重新加载系统服务:systemctl daemon-reload
之后启动nginx服务就可以使用systemctl start nginx
,我们可以用systemctl status nginx
查看nginx状态。
设置成开机启动,使用命令systemctl enable nginx.service
Nginx目录
Nginx一般安装在/usr/local/nginx
目录下(安装时--prefix可指定安装目录),目录结构如下。
conf #配置文件 |-nginx.conf # 主配置文件 |-其他配置文件 # 可通过那个include关键字,引入到了nginx.conf生效 html #静态页面 logs |-access.log #访问日志(每次访问都会记录) |-error.log #错误日志 |-nginx.pid #进程号,会标记出当前nginx进程的进程号 sbin |-nginx #主进程文件 *_temp #运行时,生成临时文件
Nginx运行流程
1.首先启动/sbin/nginx进程,开启master进程。
2.master进程会读取并校验配置文件,检查配置文件是否正确。
3.启动worker子进程,此时worker已经获取到了配置文件(conf文件)
4.请求过来之后,worker会根据请求的路径以及配置文件去找对应的响应信息。
worker是进程,会有多个,master进程只有一个用于协调各个worker之间的工作。
Nginx配置文件
后面学习Nginx配置,每次修改配置文件,一定要重载才能生效。systemctl reload nginx
。
将配置文件的注释部分去掉之后,配置文件如下所示:
worker_processes 1; # 启动的worker进程数 events { worker_connections 1024; #每个worker进程的连接数 } http { include mime.types; #include是引入关键字,这里引入了mime.types这个配置文件(同在conf目录下,mime.types是用来定义,请求返回的content-type) default_type application/octet-stream; #mime.types未定义的,使用默认格式application/octet-stream sendfile on; #详情,见下文 keepalive_timeout 65; #长链接超时时间 #一个nginx可以启用多个server(虚拟服务器 vhost),每个server就是一个主机 server { listen 80;#监听端口80 server_name localhost; #接收的域名 或者 主机名 location / { root html; #根目录指向html目录 index index.html index.htm; #域名/index 指向 index.html index.htm文件 } error_page 500 502 503 504 /50x.html; # 服务器错误码为500 502 503 504,转到"域名/50x.html" location = /50x.html {# 指定到html文件夹下找/50x.htm root html; } } }
核心配置
1.worker_processes:启动的worker子进程的数量,基本是对应到CPU物理的内核数量。
2.events
3.http
(1)include表示引入文件,这里引入了同目录下的mime.types配置文件,其内容为:
types { text/html html htm shtml; text/css css; text/xml xml; image/gif gif; image/jpeg jpeg jpg; application/javascript js; application/atom+xml atom; application/rss+xml rss; text/mathml mml; text/plain txt; text/vnd.sun.j2me.app-descriptor jad; text/vnd.wap.wml wml; text/x-component htc; image/avif avif; image/png png; image/svg+xml svg svgz; image/tiff tif tiff; image/vnd.wap.wbmp wbmp; image/webp webp; image/x-icon ico; image/x-jng jng; image/x-ms-bmp bmp; font/woff woff; font/woff2 woff2; application/java-archive jar war ear; application/json json; application/mac-binhex40 hqx; application/msword doc; application/pdf pdf; application/postscript ps eps ai; application/rtf rtf; application/vnd.apple.mpegurl m3u8; application/vnd.google-earth.kml+xml kml; application/vnd.google-earth.kmz kmz; application/vnd.ms-excel xls; application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; application/vnd.oasis.opendocument.graphics odg; application/vnd.oasis.opendocument.presentation odp; application/vnd.oasis.opendocument.spreadsheet ods; application/vnd.oasis.opendocument.text odt; application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; application/vnd.wap.wmlc wmlc; application/wasm wasm; application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; application/x-java-jnlp-file jnlp; application/x-makeself run; application/x-perl pl pm; application/x-pilot prc pdb; application/x-rar-compressed rar; application/x-redhat-package-manager rpm; application/x-sea sea; application/x-shockwave-flash swf; application/x-stuffit sit; application/x-tcl tcl tk; application/x-x509-ca-cert der pem crt; application/x-xpinstall xpi; application/xhtml+xml xhtml; application/xspf+xml xspf; application/zip zip; application/octet-stream bin exe dll; application/octet-stream deb; application/octet-stream dmg; application/octet-stream iso img; application/octet-stream msi msp msm; audio/midi mid midi kar; audio/mpeg mp3; audio/ogg ogg; audio/x-m4a m4a; audio/x-realaudio ra; video/3gpp 3gpp 3gp; video/mp2t ts; video/mp4 mp4; video/mpeg mpeg mpg; video/quicktime mov; video/webm webm; video/x-flv flv; video/x-m4v m4v; video/x-mng mng; video/x-ms-asf asx asf; video/x-ms-wmv wmv; video/x-msvideo avi; }
对应的分别是类型以及文件后缀名。default_type application/octet-stream; mime.types未定义的,使用默认格式application/octet-stream,即以数据流的方式进行下载,比如exe文件,浏览器是无法加载exe文件的,这个时候就会显示下载。
(2)snedfile表示数据零拷贝,打开sendfile,用户请求的数据不用再加载到nginx的内存中,而是直接发送
若没有开启零拷贝,则是会先拷贝到nginx应用程序的内存中:
nginx将文件读到自己的应用程序内存后,再从自己的应用程序内存里读取文件到网络接口缓存,再由OS调度读取网络接口缓存从而返回给用户。
若开启了零拷贝,则流程为:
nginx直接发送一个带有套接字或者文件地址的信号sendfile()给系统内核,系统内核直接读取文件到网络接口缓存中后返回给用户。
虚拟主机
一台主机可以绑定多个域名,这样可以节省服务器资源,nginx可以根据域名来区分访问的内容,从而到对应的文件夹中寻找响应文件。
为了模拟域名的效果,我们可以先修改本机host,写一些域名绑定到虚拟机上:
为了模拟出多站点的情况,我们可以先创建对应的文件夹,比如在根目录下创建/www
文件夹,其下再创建vod和www文件夹来模拟多站点的情况,每个单独的文件夹下都有一个index.html:
接下来编辑nginx的配置文件(nginx自己有一个nginx.conf.default
文件,如果有写错了的情况,可以用默认的配置文件代替):
worker_processes 1; # 启动的worker进程数 events { worker_connections 1024; #每个worker进程的连接数 } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #一个nginx可以启用多个server(虚拟服务器 vhost),每个server就是一个主机 server { listen 80;#监听端口80 server_name localhost; location / { root /www/www; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html {# 指定到html文件夹下找/50x.htm root html; } } server { listen 88;#监听端口88 server_name localhost; location / { root /www/vod; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html {# 指定到html文件夹下找/50x.htm root html; } } }
比如80端口监听主站点的,88端口监听的是vod站点的。
修改配置文件后需要reload一下:systemctl reload nginx
那假如说我想都用80端口,根据域名来区分返回的内容,只需要把server_name
改成对应的域名即可,总之只要保证每个server的listen(端口号)+server_name(域名)保持唯一性即可。
多个域名配置到同一个文件夹
可以在server_name后面加上多个域名,每个域名、主机名之间用空格区分开来。比如server_name vod1.test.com vod2.test.com;
,比如这个配置就是将两个域名都配置到一个文件夹下了。
server { listen 80;#监听端口80 server_name vod1.test.com vod2.test.com; location / { root /www/www; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html {# 指定到html文件夹下找/50x.htm root html; } }
除了配置固定的主机名外,还可以使用通配符的方式进行配置,比如*.test.com
,www.test.*
,这个可以查看专门的文档
反向代理
反向代理的概念非常简单,用户访问反向代理服务器(nginx)后,把请求转发给对应的业务服务器,随后业务服务器返回结果给nginx,nginx将结果再返回给用户,这是一种典型的隧道式代理,隧道式服务器中,用户与业务服务器不能直接产生连接。
因为隧道式代理非常考验nginx的能力,所以又提出了一种LVS的代理模式,与隧道式的区别在于,nginx转发请求给业务服务器后,业务服务器直接返回结果给用户,即返回结果的时候不再经过nginx。LVS代理模式中,业务服务器只接受从nginx进入的流量,但是发出数据时不受限制,可以发给任意的一个用户。
反向代理的实现方式使用proxy_pass
实现,使用了proxy_pass
后,root
和index
就不需要再配置了。
server { listen 80;#监听端口80 server_name localhost; location / { proxy_pass http://www.atguigu.com; #root /www/www; #index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html {# 指定到html文件夹下找/50x.htm root html; } }
将本机反向代理至http://www.atguigu.com
,这个时候访问本机地址192.168.247.128时,就会转到尚硅谷的主页并且地址栏不会变化。
不过反向代理是不支持反向代理至https的,不过服务端一般都会对http请求进行重定向至https,所以这个问题不大。
负载均衡
刚刚我们提到nginx作为反向代理服务器时转发请求给对应的业务服务器,这个过程中,nginx可以做负载均衡的功能。负载均衡:把请求,按照一定算法规则,分配给多台业务服务器(即使其中一个坏了/维护升级,还有其他服务器可以继续提供服务)
轮询
负载均衡的配置要与proxy_pass
配置项搭配的使用,我们可以定义一个地址别名,随后使用upstream来配置这个别名的负载均衡。
http{ upstream httpds{ server 192.168.174.133:80; #如果是80端口,可以省略不写 server 192.168.174.134:80; } server { listen 80; server_name localhost; location / { proxy_pass http://httpds; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
使用upstream定义一组地址【在server字段下】,访问localhost,访问都会代理到192.168.174.133:80
和192.168.174.134:80
这两个地址之一,每次访问这两个地址轮着切换(后面讲到,因为默认权重相等)。
设置权重
访问使用哪个地址的权重
upstream httpds{ server 192.168.174.133:80 weight=10; server 192.168.174.134:80 weight=80; }
设置down后,可以让这台机器不参与负载均衡,也就是休息。(使用不多)
upstream httpds{ server 192.168.174.133:80 weight=10 down; server 192.168.174.134:80 weight=80; }
备用服务器,如果192.168.174.133:80
出现故障,无法提供服务,就用使用backup的这个机器。(使用不多)
upstream httpds{ server 192.168.174.133:80 weight=10; server 192.168.174.134:80 weight=80 backup; }
动静分离
当用户请求时,动态请求分配到Tomcat业务服务器,静态资源请求放在Nginx服务器中。可用于中小型的应用。
例子:
- 如果请求的资源地址是
location/
,/
的优先级比较低,如果下面的location没匹配到,就会走http://xxx这个地址的机器 - 如果请求的资源地址是
location/css/*
,就会被匹配到nginx的html目录下的css文件夹中(我们把css静态资源放在这个位置)
server { listen 80; server_name localhost; location / { # /的优先级比较低,如果下面的location没匹配到,就会走http://xxx这个地址的机器 proxy_pass http://xxx; } location /css { # root指的是html,location/css指的是root下的css,所以地址就是html/css root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
还可以使用正则表达式来进行匹配,这样把/js
,/css
以及/img
的请求都进行了反向代理。~表示开始正则,*表示任意字符。
location ~*/(js|css|img){ root html; index index.html index.htm; }
不过现在项目基本上都是前后端分离了,前端部署到nginx上,后端再另外启动一个服务。
URLRewrite
这个配置在前后端分离中可能是会用到的。rewrite是URL重写的关键指令,根据regex(正则表达式)部分内容,重定向到replacement,结尾是flag标记。
rewrite <regex> <replacement> [flag]; 关键字 正则 替代内容 flagt标记
正则:使用正则表达式语句进行规则匹配 替代内容:将正则匹配的内容替换成replacement flag标记说明: last #本条规则匹配完成后,继续向下匹配新的1ocation URI规则 break #本条规则匹配完成即终止,不再匹配后面的任何规则 redirect #返回302临重定向,游览器地址会显示跳转后的URL地址 permanent #返回301永久重定向,测览器地址栏会显示跳转后的URL地址
浏览器地址栏访问 xxx/123.html
实际上是访问xxx/index.jsp?pageNum=123
server { listen 80; server_name localhost; location / { rewrite ^/([0-9]+).html$ /index.jsp?pageNum=$1 break; proxy_pass http://xxx; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
网关服务器配置
上图中,应用服务器,不能直接被外网访问到,只能通过Nginx服务器进行访问(使用proxy_pass),这时候这台Nginx服务器就成为了网关服务器(承担入口的功能)
所以,我们启动应用服务器的防火墙,设置其只能接受这台Nginx服务器的请求
添加rich规则
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.174.135" port protocol="tcp" port="8080" accept" #这里的192.168.174.135是网关 服务器地址
移除rich规则
firewall-cmd --permanent --remove-rich-rule="rule family="ipv4" source address="192.168.174.135" port port="8080" protocol="tcp" accept"
移除和添加规则后都要重启才能生效:firewall-cmd --reload
;可以使用该命令查看所有规则:firewall-cmd --list-all
。
防盗链
当我们请求到一个页面后,这个页面一般会再去请求其中的静态资源,这时候请求头中,会有一个refer字段,表示当前这个请求的来源,我们可以限制指定来源的请求才返回,否则就不返回,这样可以节省资源。
我们可以通过valid_referers none|server_name
,设置有效的refer值。
- none:检测地址没有refer,则有效;比如直接请求图片的时候(即不是在另一个页面里请求图片的情况),配置示例:
valid_referes none 192.168.44.101
,这种情况下资源只允许来自192.168.44.101的页面引用或者直接请求该页面。 - server_name:检测主机地址,refer显示是从这个地址来的,则有效(server_name必须是完整的
http://xxxx
)
注意:if ($invalid_referer)
中if后有个空格,不写就会报错,报错信息如下:
nginx: [emerg] unknown directive "if($invalid_referer)" in /usr/local/nginx/conf/nginx.conf:27
例子:这里设置nginx服务器中的img目录下的图片必须refer为http:192.168.174/133才能访问。
server { listen 80; server_name localhost; location / { proxy_pass http://xxx; } location /img{ valid_referers http:192.168.174/133; if ($invalid_referer){#无效的 return 403;#返回状态码403 } root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
如果引用这张图片的页面且refer并没有被设置,图片无法加载出来。如果直接访问图片地址,因为没有refer字段指向来源,会直接显示Nginx的页面:
设置盗链图片
将提示图片放在html/img/x.png,访问设置防盗链图片时,就返回这x.png张图,if
和(
之间必须有一个空格。
location /img{ valid_referers http:192.168.174/133; if ($invalid_referer){#无效的 rewrite ^/ /img/x.png break; } root html; index index.html index.htm; }
高可用(High Availablity)
我们之前用到的nginx的负载均衡,考虑到的场景是后端服务器如果挂掉的话,把请求转发到正常运作的服务器上,但是设想一个场景:如果nginx挂掉了,那么就没办法把请求转发给后端服务器了,自然也没法儿进行负载均衡了。
那我们拓展一下,在nginx前面再放一层nginx,第一层nginx对第二层nginx做负载均衡,但是这样就会陷入到逻辑怪圈中,万一第一层nginx挂了,那第二层的nginx也访问不到了,自然也访问不到后面的应用服务器了。这个时候我们就提出了高可用的概念。
用户访问时,访问的是一个虚拟IP,keepalived会选定一个主服务器使用这个虚拟IP。
每台机器上的keepalived会相互通信,根据其他机器上的keepalived进程是否存在,判断服务器状态,如果默认的Master停止了,就会在剩下的Backup机器中,竞选出一台Nginx服务器作为Master
安装keepalived
通过yum命令安装:
yum install -y keepalived
yum安装后的配置文件在/etc/keepalived/keepalived.conf
;vrrp_instance
、authentication
、virtual_router_id
、virtual_ipaddress
这几个一样的机器,才算是同一个组里。这个组才会选出一个作为Master机器。
这里我们设置两台机器,分别下载好keepalived,然后进行配置
机器一:
! Configuration File for keepalived global_defs { router_id lb1 # 名字与其他配置了keepalive的机器不重复就行 } vrrp_instance heyingjie {#vrrp实例名可以随意取 state MASTER #只能有一个默认的Master,其他写BACKUP interface ens33 # ip addr查看下网卡名,默认时ens33 virtual_router_id 51 priority 100 # 多台安装了keepalived的机器竞争成为Master的优先级 advert_int 1 #通信时间 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.200.16 #虚拟IP } }
机器二:
! Configuration File for keepalived global_defs { router_id lb2 } vrrp_instance heyingjie { state BACKUP #只能有一个默认的Master,其他写BACKUP interface ens33 virtual_router_id 51 priority 50 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.200.16 #虚拟IP } }
通过命令ip addr
查看机器一的ip信息,可以看到虚拟IP
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库