一文搞懂 Nginx
创始人
2024-03-28 16:54:27
0

c69c5c1b883cf9aa467d11e377c4834e


文章目录

    • 一、前言
    • 二、NGINX 指令与上下文
      • 2.1 指令
      • 2.2 上下文
    • 三、NGINX 静态文件处理
      • 3.1 静态文件配置
      • 3.2 静态文件类型处理
    • 四、NGINX 动态路由
      • 4.1 Location 匹配
        • 4.1.1 前缀匹配
        • 4.1.2 精准匹配
        • 4.1.3 正则匹配
        • 4.1.4 优先前缀匹配
      • 4.2 Location 匹配优先级
        • 4.2.1 匹配优先级对比
        • 4.2.2 匹配优先级总结
    • 五、NGINX 变量
      • 5.1 说明
      • 5.2 案例
    • 六、NGINX 重定向与重写
      • 6.1 重定向
      • 6.2 重写
      • 6.3 try_files
    • 七、NGINX 日志
      • 7.1 access_log
      • 7.2 error_log
    • 八、NGINX 反向代理
      • 8.1 简单案例
      • 8.2 反向代理 Node.js
        • 8.2.1 准备应用程序
        • 8.2.2 实现反向代理
      • 8.3 反向代理 PHP
        • 8.3.1 准备应用程序
        • 8.3.2 实现反向代理
    • 九、NGINX 负载均衡
      • 9.1 启动 NodeJS 服务
      • 9.2 实现负载均衡


一、前言

Nginx 配置文件你真的懂吗?当你安装完成后就可以访问到如下图测试页面,那它的实现流程又是怎样的呢?

image-20221207182733173

接下来将从 0-1 来演示一下 Nginx 流程。

二、NGINX 指令与上下文

2.1 指令

去掉 Nginx 默认的其他部分,从最简单的指令语句开始解剖 nginx 配置文件的作用。

如下编写的几行代码,虽然看似简单,但却介绍了 NGINX 配置文件中两个最重要的术语。它们是指令上下文

如下 zhurs.tech 域名是一个虚拟域名,我们做实验时需要在你的 /etc/hosts 文件下做本地解析。

events {
}http {server {listen 80;server_name zhurs.tech;return 200 "hello nginx!\n";}}

image-20221130113106065

从技术上讲,NGINX 配置文件中的所有内容都是指令。指令有两种类型:

  • 简单指令:一个简单的指令由指令名称和其参数组成(指令名称与其参数以空格分隔),且以分号结束。例如listenreturn
  • 块指令:{ }块指令类似于简单指令,不同之处在于它们不是以分号结尾,而是以一对包含附加指令的大括号结束。

2.2 上下文

能够在其内部包含其他指令的块指令称为上下文,即eventshttp依此类推。NGINX 中有四个核心上下文:

  • events { }events上下文用于设置有关 NGINX 将如何在一般级别处理请求的全局配置。一个有效的配置文件中只能有一个events上下文。
  • http { }http上下文用于定义有关服务器将如何处理 HTTP 和 HTTPS 请求的配置。一个有效的配置文件中只能有一个http上下文。
  • server { }server上下文嵌套在http上下文中,用于在单个主机中配置特定的虚拟服务器。server上下文中可以有多个,每个server上下文都被视为一个虚拟主机。
  • mainmain上下文是配置文件本身。在前面提到的三个上下文之外编写的任何内容都在main上下文中。

一个 http { } 上下文可包含多个 server { } 上下文,那当请求到达服务器时,NGINX 如何处理哪一个 server { } 的上下文请求?具体实现如下:

events {
}http {server {listen 80;server_name zhurs.tech;return 200 "nginx port 80!\n";}server {listen 8080;server_name zhurs.tech;return 200 "nginx port 8080!\n";}
}

image-20221130115548443

流程:

  • 当客户端向 http://zhurs.tech:80 发起请求时,那么将会收到来自 nginx port 80! 的响应;
  • 当客户端向 http://zhurs.tech:8080 发起请求时,那么将会收到来自 nginx port 8080! 的响应;

这两个 server {} 上下文就像两个拿着电话听筒的人,在请求到达其中一个号码时等待响应。它们的“号码(即端口)”listen指令指定。除了listen指令,还有server_name指令。

events {
}http {server {listen 80;server_name zhurs.tech;return 200 "nginx zhurs.tech!\n";}server {listen 80;server_name www.zhurs.tech;return 200 "nginx www.zhurs.tech!\n";}
}

流程:

  • 当客户端向 http://zhurs.tech 发起请求时,那么将会收到来自 nginx zhurs.tech! 的响应;
  • 当客户端向 http://zhurs.tech 发起请求时,那么将会收到来自 nginx www.zhurs.tech! 的响应;

其实这是虚拟主机概念的一个基本示例,即在同一台服务器中以不同的服务器名称运行两个单独的应用程序。

其中 return 指令负责向用户返回有效响应。该指令有两个参数:状态代码和要返回的字符串消息。

三、NGINX 静态文件处理

以上的简单配置文件还不能提供有效的静态文件处理,需进一步修改配置文件。

3.1 静态文件配置

1、准备好静态文件

mkdir -p /data/nginx/html/test/static-demo
ll /data/nginx/html/test/static-demo

image-20221130142325661

2、配置 nginx 配置文件

配置与上面案例几乎相同,只是将 return 指令替换为 root 指令。该指令用于声明站点根目录,即该目录就是用于存放静态文件的目录。

events {}http {server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;}
}

3、访问验证

CURL:http://139.xxx.xxx.50:81

注:我是 Docker 起的 Nginx

docker run -itd \
--name=nginx \
--privileged=true \
--restart=always \
-p 81:80 \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /data/nginx/html:/usr/share/nginx/html \
-v /data/nginx/logs:/var/log/nginx nginx:1.20.2

image-20221130141942976

3.2 静态文件类型处理

尽管 NGINX 已正确提供 index.html 文件,但从三个导航链接的外观来看,CSS 代码似乎无法正常工作。对于这个问题,如果在生产环境中出现,我可先与开发人员确定是否文件有问题,若开发人员确定没问题就是我们 nginx 的配置文件配置有问题。

接下来就是要调试 CSS 文件请求:

curl -I zhurs.tech:81/mini.min.css
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Sun, 04 Dec 2022 12:03:27 GMT
Content-Type: text/plain
Content-Length: 46887
Last-Modified: Tue, 16 Nov 2021 06:06:09 GMT
Connection: keep-alive
ETag: "61934a51-b727"
Accept-Ranges: bytes

可看到 Content-Type 类型为 text/plain 而不是 text/css,这意味着 NGINX 将此文件作为纯文本而不是作为样式表。

Nginx 处理请求时,默认找的是 index.html 文件,但在解释文件类型时却不能做到这样的智能。因此我们需要修改配置文件来解决这个问题(配置文件添加文件类型)。

events {}http {types {text/html html;text/css css;}server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;}
}

该配置文件中 typrs{} 指令块可使 Nginx 解析所有以 text/html 结尾的 html 文件,以及所有以 text/css 结尾的 css 文件。

再次请求 CSS 文件:

curl -I zhurs.tech:81/mini.min.css

此时文件已经被解析为 text/css 文件类型了:

HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Sun, 04 Dec 2022 12:24:38 GMT
Content-Type: text/css
Content-Length: 46887
Last-Modified: Tue, 16 Nov 2021 06:06:09 GMT
Connection: keep-alive
ETag: "61934a51-b727"
Accept-Ranges: bytes

本地浏览器请求进行验证:可看到 CSS 样式已经改变,比之前美观多了。

image-20221204203218494

types上下文中映射文件类型可能适用于小型项目,但对于大型项目而言,它可能很麻烦且容易出错。

NGINX 为这个问题提供了解决方案。在 Nginx 默认安装目录中,你会看到一个名为 mime.types 的文件(默认路径 /etc/nginx/mime.types)。

image-20221204203940338

来看看这个文件的内容:

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/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.presentationpptx;application/vnd.openxmlformats-officedocument.spreadsheetml.sheetxlsx;application/vnd.openxmlformats-officedocument.wordprocessingml.documentdocx;application/vnd.wap.wmlc                         wmlc;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;
}

该文件包含一长串文件类型及其扩展名,如果我们一条一条的往配置文件中写,势必降低 Nginx 配置文件可读性,因此我们可以使用 include 指令来实现。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;}
}

重新加载配置文件并再次发送对该文件的请求:

curl -I zhurs.tech:81/mini.min.css
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Sun, 04 Dec 2022 12:50:05 GMT
Content-Type: text/css
Content-Length: 46887
Last-Modified: Tue, 16 Nov 2021 06:06:09 GMT
Connection: keep-alive
ETag: "61934a51-b727"
Accept-Ranges: bytes

四、NGINX 动态路由

4.1 Location 匹配

4.1.1 前缀匹配

以上配置通过 Nginx 根站点发布路径,当有请求时会响应根目录下的文件(如 index.html、about.html、mini.min.css)

我们用新的上下文替换了root指令。location 上下文通常嵌套在 server 块内。一个 server 上下文中可以有多个 location 上下文。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location /hello {return 200 "Hello zhurs.\nWelcome to nginx.\n";}}
}

此时,如果发起 http://zhurs.tech:81/hello 请求,将获得 200 响应代码及响应内容:

curl -i zhurs.tech:81/hello

image-20221204213138471

当请求 zhurs.tech:81/hello 时,location 会告诉 Nginx 匹配以 hello 开头的 URL。这种匹配称为前缀匹配

因为为前缀匹配,所以你只要保证你的 URL 的前缀相同,其返回的内容都是一样的,具体如下:

curl -i zhurs.tech:81/hello-ttttttttttttttt# 只要保证前缀hello是一致的就可以返回相同值

image-20221207113820157

4.1.2 精准匹配

**精准匹配(或叫完全匹配)**只需要修改下 location 配置即可,此时与前缀匹配不同的是,其 URL 必须且也只能匹配到 hello 时才会返回值。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location = /hello {return 200 "Hello zhurs.\nWelcome to nginx.\n";}}
}
curl -i zhurs.tech:81/hello

image-20221207114232725

# 但如果URL没精准到hello,则返回404
curl -i zhurs.tech:81/hello-ttttttttttttttt

image-20221207114356584

4.1.3 正则匹配

NGINX 中的另一种匹配是正则表达式匹配。使用此匹配,您可以根据复杂的正则表达式检查location 的 URL。

想要使用正则表达,只需将精准匹配的 = 号改为 ~ 号即可,具体配置如下。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location ~ /hello[0-9] {return 200 "Hello zhurs.\nWelcome to nginx.\n";}}
}

使用正则后,这意味着只有匹配到 hello,且 hello 后必须有一个数字(0~9任意一个)才会响应,当然你可以把正则匹配看作特殊的前缀匹配,也就是说只要正则匹配的 URL 前缀一致,不管什么都会返回值,否则一律 404。

curl -i zhurs.tech:81/hello5
curl -i zhurs.tech:81/hello

image-20221207115238579

此时访问 curl -i zhurs.tech:81/hello5kkkkkkkk 也是能正常访问的:

image-20221207120741236

但要注意:正则匹配默认是区分 URL 大小写的,如下案例就不能访问成功:

curl -i zhurs.tech:81/Hello5

image-20221207115516449

要想不区分 URL 大小写,必须在 ~ 号后添加一个 * 号。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location ~* /hello[0-9] {return 200 "Hello zhurs.\nWelcome to nginx.\n";}}
}

此时再次请求 curl -i zhurs.tech:81/Hello5,就可正常访问了。

image-20221207120228238

4.1.4 优先前缀匹配

优先前缀匹配只需要在 ~ 号前加 ^ 即可实现,其实与前缀匹配没多大区别,其好处就是在于与正则匹配同时使用且匹配的优先级需要高于正则匹配时使用。注意的是,优先前缀匹配并不是正则匹配,不适用于正则表达式。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location ^~ /hello {return 200 "优先前缀匹配\n";}}
}
curl -i zhurs.tech:81/hello

image-20221207130229881

4.2 Location 匹配优先级

4.2.1 匹配优先级对比

NGINX 为这些 location 匹配分配了优先值,正则匹配比前缀匹配具有更高的优先级,优先前缀匹配又比正则匹配优先级高,精准匹配优先级是最高的。接下来进行一一对比:

  • 前缀匹配与正则匹配优先级

    events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location /hello5 {return 200 "前缀匹配\n";}location ~ /hello[0-9] {return 200 "正则匹配\n";}}
    }
    
    curl -i zhurs.tech:81/hello5# 下图可看到优先匹配到正则表达,说明正则匹配优先级大于前缀匹配
    

    image-20221207131048196

  • 优先前缀匹配与正则匹配优先级

    events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location ~ /hello[0-9] {return 200 "正则匹配\n";}location ^~ /hello6 {return 200 "优先前缀匹配\n";}}
    }
    
    curl -i zhurs.tech:81/hello6# 下图可看到优先匹配到正则表达,说明优先前缀匹配优先级大于正则匹配
    

    image-20221207131353981

    注意:前缀匹配和优先前缀匹配不能同时使用,如下案例就会导致 nginx 启动报错:

    events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location /hello7 {return 200 "前缀匹配\n";}location ^~ /hello7 {return 200 "优先前缀匹配\n";}}
    }
    
    docker logs -g nginx
    

    image-20221207132104698

  • 精准匹配与所有匹配的优先级

    events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location ~ /hello[0-9] {return 200 "正则匹配\n";}location = /hello7 {return 200 "精准匹配\n";}location ^~ /hello7 {return 200 "优先前缀匹配\n";}}
    }
    
    curl -i zhurs.tech:81/hello7
    

    image-20221207132251185

4.2.2 匹配优先级总结

优先级由上至下(高——>低)

匹配修改器
精准匹配=
优先前缀匹配^~
正则匹配~、~*、!~、!~*
前缀匹配/
内部服务跳转匹配@

五、NGINX 变量

5.1 说明

1、语法

nginx 变量类似于其他编程语言的变量,使用 set 指令来声明新变量,除了您声明的变量外,NGINX 模块中还有嵌入式变量。

set $ ;
# 案例
set name "zhurs"
set age 26

2、类型

  • 字符串;

  • 整型;

  • 布尔型。

5.2 案例

要查看一些正在运行的变量,请按如下方式更新配置:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;return 200 "Host - $host\nURI - $uri\nArgs - $args\n";}
}
curl http://zhurs.tech:81/user?name=zhurs

image-20221207145501156

host 变量:该变量用于存放根地址;

uri 变量:该变量用于存放相对于根的 URL;

args 变量:该变量用于存放所有查询字符串。

我们还可使用 arg 变量访问各个值,具体配置如下:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;set $name $arg_name;   # $arg_return 200 "Name - $name\n";}
}
# 再来请求一下,看看效果
curl http://zhurs.tech:81/user?name=zhurs

image-20221207150759542

六、NGINX 重定向与重写

6.1 重定向

重定向,其实很容易理解,比如当我访问 zhurs.tech 的时候会自动跳转到 www.qq.com,即 URL 发生了改变。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;location = /index_page {return 307 http://xxx.xxx.xxx.xxx:81/index.html;}location = /about_page {return 307 http://xxx.xxx.xxx.xxx:81/about.html;}}
}

准备 index.htmlabout.html 文件

image-20221207152134449

请求1:curl -I http://zhurs.tech:81/index_page

image-20221207154825738

image-20221207154528921

请求2:curl -I http://zhurs.tech:81/about_page

image-20221207154738045

image-20221207154640797

不难看出,当我们请求 curl -I http://zhurs.tech:81/index_page 时,跳转到 http://xxx.xxx.xxx.xxx:81/index.html;当我们请求 curl -I http://zhurs.tech:81/about_page 时,跳转到 http://xxx.xxx.xxx.xxx:81/about.html

根据 Nginx 配置文件可知,当没有匹配任何 URL 时,默认请求根站点:

image-20221207155311239

6.2 重写

重写与重定向不同之处是,重写是在 Nginx 内部更改 URL,且用户无感知,而重定向是明显看到 URL 再变化的。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;rewrite /index_page /index.html;  # 因为是内部自动实现转换,不经过浏览器,所以可以不用写Host的IP+端口rewrite /about_page /about.html;}
}

可看到下图,当请求 http://xxx.xxx.xxx.xxx:81/about_page 时,虽然发生了重写,但是我的 URL 还是保持不变的。

image-20221207160918661

除了处理 URI 更改的方式不同之外,重定向和重写之间还有另一个区别。当发生重写时,NGINX 会重新评估 server 上下文。因此,重写的代价比重定向更高。

6.3 try_files

与重定向与重写类似,用来判断多个文件实现内部跳转。

该配置文件作用为:当我请求 http://zhurs.tech 时,nginx 会在根目录中(/usr/share/nginx/html/test/static-demo)中查找名为 the-nginx-handbook.jpg 的文件。存在则返回,如果不存在,则跳转到/not_found 的 location 指令块。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;try_files /the-nginx-handbook.jpg /not_found;location /not_found {return 404 "The requested resource does not exist!\n";}}
}

image-20221207161823344

上图可看到我根路径下是有这个文件的,因此是能成功请求到的,看下图为请求的结果:

请求 URL:http://xxx.xxx.xxx.xxx:81/

image-20221207162423526

如果我 Nginx 配置文件故意配置一个不存在的文件,看看返回效果。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;try_files /not_found.jpg /not_found;location /not_found {return 404 "The requested resource does not exist!\n";}}
}

此时我再次请求,就会得到如下结果:

image-20221207162939933

其流程就是:

  • 客户端发起请求:http://xxx.xxx.xxx.xxx:81/;
  • Nginx 收到请求后,根据配置文件的 try_files 指令去查找其后的第一个文件(/not_found.jpg),看根路径下是否存在该资源;
  • 如果该资源在根路径下存在则返回给客户端;
  • 如果该资源在根路径下不存在,则继续查找下一个文件(/not_found),而 /not_found 有对应的 location,就会跳转到该部分进行请求处理与响应。

一般地,try_files 常会与 Nginx 内置变量配合使用,否则你每次都需要修改配置文件,而且限死了客户端的请求 URL。因此,我们只需要简单修改try_files即可:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;try_files $uri /not_found;location /not_found {return 404 "The requested resource does not exist!\n";}}
}

此时,客户端发起 http://zhurs.tech:81/index.html 请求时,就会返回如下结果:

image-20221207164503148

然而,当客户端发起 http://zhurs.tech:81/ 请求时,还会返回 404,这是因为当您访问服务器根目录时,该$uri变量不对应于任何现有文件,因此 NGINX 为您提供后备的 location。当然,如果没有 try_files 指令的话就会自动请求根路径的index.html资源。

image-20221207164906638

那有没有办法解决这个问题呢?答案是有的。看如下配置:就是加了个 $uri/

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;try_files $uri $uri/ /not_found;location /not_found {return 404 "The requested resource does not exist!\n";}}
}

再次请求 http://zhurs.tech:81/ ,就会正常返回,如下图:

image-20221207165631940

那其流程又是怎么样的呢?

  • 客户端发起请求:http://xxx.xxx.xxx.xxx:81/;

  • Nginx 收到请求后,根据配置文件的 try_files 指令去获取并查找其后的第一个内置变量的值,,看根路径下是否存在该资源;

  • 如果该资源在根路径下存在则返回给客户端;

  • 如果该资源在根路径下不存在或 Nginx 获取不到请求的 $uri 值,则把请求的 uri 作为二级路径进行查询,如果存在则返回资源;

    举个例子:发起 http://zhurs.tech:81/ 请求,第一个$uri是获取不到值的,因为你的请求地址就没有 uri 部分(仅有域名+端口),此时来到 $uri/,此时就会正常请求根路径下的 index.html 文件,如果没有 index.html 文件,则进入 /not_found 部分,最终跳转到 location 部分请求。

  • 如果该资源在根路径下依旧不存在,则继续查找下一个文件(/not_found),而 /not_found 有对应的 location,最终会跳转到该部分进行请求处理与响应。

七、NGINX 日志

默认情况下,NGINX 的日志文件位于/var/log/nginx

为了实验验证,先清空 Nginx 日志:

# 删除旧的日志文件
rm -rf /data/nginx/logs/access.log /data/nginx/logs/error.log# 创建新日志文件
touch /data/nginx/logs//access.log /data/nginx/logs/error.log# 向Nginx发送reopen信号
nginx -s reopen

为什么要向 Nginx 发送 reopen 信号?如果不向 NGINX 发送 reopen 信号,它将继续将日志写入先前打开的流,而你新创建的日志文件依然是空的。

7.1 access_log

Nginx 配置文件:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;try_files $uri $uri/ /not_found;location /not_found {return 404 "The requested resource does not exist!\n";}}
}

此时,向 Nginx web 服务器发送一个请求,看看访问日志。

image-20221207172733465

下图就是客户端的请求日志:

image-20221207172600404

默认情况下,对服务器的任何请求都将记录到此文件中。但在配置文件中,我们可以使用access_log指令来指定特定的日志记录文件。

该配置文件的作用:当你请求的是:curl -i http://zhurs.tech:81/admin,则打入 admin.log 默认日志下;当你请求的是:curl -i http://zhurs.tech:81/no_logging,不记录任何访问日志;如果你请求的是:curl -i http://zhurs.tech:81/,则打入 access.log 默认日志下。

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;location / {return 200 "this will be logged to the default file.\n";}location = /admin {access_log /var/logs/nginx/admin.log;  return 200 "this will be logged in a separate file.\n";}location = /no_logging {access_log off;            return 200 "this will not be logged.\n";}}
}
curl -i http://zhurs.tech:81/admin
cat /data/nginx/logs/admin.log

image-20221207174630659

在没有指定错误日志输出路径的情况下,默认输出到默认 error 路径。

7.2 error_log

错误日志同理,如果想输出至指定路径,使用 error_log 指令指定路径即可。进行简单的错误日志输出演示:

故意写一个错误的配置文件(return 选项只能有两个,我故意弄成三个,重启时就一定会报错)

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/static-demo;return 200 "..." "...";}
}
docker restart nginx
tail -5 /data/nginx/logs/error.log

image-20221207180507961

错误日志级别:共 8 个错误级别

错误日志级别说明
debug调试级别,用于定位问题所在。
info一般信息,需要进行了解的日志信息。
notice一些值得注意的正常日志信息。
warn一些警告信息,但不会对当前服务造成影响。
error一些错误信息,有些需进行解决,否则些服务不可用。
crit比 error 稍严重的日志信息,需进行解决。
alert严重级别,需快速解决的问题。
emerg系统不可用,需立即解决的问题。

默认情况下,NGINX 记录所有级别的消息。如果要将消息的最低级别设置为warn,可进行如下配置:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;error_log /var/log/error.log warn;return 200 "..." "...";}
}

对于大多数项目,将错误配置保留原样就是没问题的。一般建议是将最小错误级别设置为warn,这样您就不必查看错误日志中不必要的条目。更多错误日志配置请看官方文档。

八、NGINX 反向代理

关于反向代理、正向代理,我前面文章有提到过——《Nginx实现反向代理》,大家可以去看看。

8.1 简单案例

来看一个简单的反向代理示例:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location / {proxy_pass "https://www.baidu.com/";}}
}

发起请求后,就会被反向代理。

image-20221208094802917

8.2 反向代理 Node.js

8.2.1 准备应用程序

1、安装 nodejs 工具及 pm2 守护进程管理器

关于 pm2 可看其官方文档:https://pm2.keymetrics.io/docs/usage/quick-start/

image-20221208101229747

2、进入项目目录并启动项目

cd /data/nginx/html/test/node-js-demo
pm2 start app.js

image-20221208101413837

3、请求验证

curl -i 10.150.16.95:3000

image-20221208102256607

8.2.2 实现反向代理

1、配置反向代理

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location / {proxy_pass http://10.150.16.95:3000;}}
}

2、验证

发起请求:curl -i pm2 zhurs.tech:81

image-20221208102654278

虽然这适用于像这样的基本服务器,但需要添加更多指令才能使其在实际场景中运行,具体取决于应用程序的要求。例如,如果您的应用程序处理 Web 套接字连接,那么 Nginx 配置应如下:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;location / {proxy_pass http://10.150.16.95:3000;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection 'upgrade';}}
}

proxy_http_version指令设置服务器的 HTTP 版本。默认情况下它是 1.0,但是 web socket 要求它至少是 1.1。该proxy_set_header指令用于在后端服务器上设置标头。该指令的通用语法如下:

proxy_set_header 

8.3 反向代理 PHP

8.3.1 准备应用程序

1、安装 PHP 环境

略...

2、进入项目目录并启动项目

cd /data/nginx/html/test/php-demo
php -S 10.150.16.95:8000# 也可以指定文件启动
php -S 10.150.16.95:8000 /data/nginx/html/test/php-demo/index.php

image-20221208111759563

3、请求验证

curl -i 10.150.16.95:8000

image-20221208111919713

8.3.2 实现反向代理

1、配置反向代理

PHP-FPM 中的 FPM 部分代表 FastCGI Process Module。FastCGI 是一种类似于 HTTP 的协议,用于交换二进制数据。此协议比 HTTP 稍快,并提供更好的安全性。

要使用 FastCGI 而不是 HTTP,需修改 Nginx 配置:

events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /usr/share/nginx/html/test/php-demo;index index.php;location / {try_files $uri $uri/ =404;}location ~ \.php$ {fastcgi_pass unix:/var/run/php-fpm/www.sock;  # 你是容器运行的nginx的话,改为10.150.16.95:8000fastcgi_param REQUEST_METHOD $request_method;fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;}}
}

配置文件说明:

  • index指令

    • NGINX 默认情况下会查找要提供的 index.html 文件。但在演示项目中,它被称为 index.php。因此,通过编写index index.php,指示 NGINX 使用 index.php 文件作为根。

    • 该指令可以接受多个参数。如果你写类似的东西index index.php index.html,NGINX 会首先寻找 index.php。如果找不到该文件,它将查找 index.html 文件。

  • try_files指令

    该指令已经讲过,最后=404的 表示如果找不到任何文件则抛出的错误。

  • 第二个location

    • 我们已将proxy_pass指令替换为新的fastcgi_pass。顾名思义,它用于将请求传递给 FastCGI 服务。

    • PHP-FPM 服务默认运行在主机的 9000 端口。因此,我们可以直接将请求传递给 http://localhost:9000,而不是像在这里所做的那样使用 Unix 套接字。但是使用 Unix 套接字更安全。

2、验证

image-20221208114659515

请求结果返回 502,那可能就是服务器问题。查看 nginx 错误日志:

image-20221208115234707

似乎 NGINX 进程被拒绝访问 PHP-FPM 进程的权限。出现权限被拒绝错误的主要原因之一是用户不匹配。查看拥有 NGINX 与 PHP 工作进程的用户。

image-20221208115417807

nginx 的运行用户为 101,php-fpm 的启动用户为apache。这就是 NGINX 被拒绝访问此进程的原因。

要解决此问题,可修改 Nginx 启动用户为 apache 即可,如下更新 nginx 配置文件。

但是我 Docker 部署的 Nginx 不行,请求 502,这里换为 Host 部署的 Nginx。

user  apache;events {}http {include /etc/nginx/mime.types;server {listen 80;server_name zhurs.tech;root /data/nginx/html/test/php-demo;index index.php;location / {try_files $uri $uri/ =404;}location ~ \.php$ {fastcgi_pass unix:/var/run/php-fpm/www.sock;  fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;include /etc/nginx/fastcgi_params;}}
}

再次请求:

image-20221209095412874

在 nginx 配置文件中,有个 include 指令包含了一个名为fastcgi_params,此文件包含了最常见的 FastCGI 参数列表。

九、NGINX 负载均衡

9.1 启动 NodeJS 服务

实际应用中,分布在多个服务器上的大型项目可能需要负载平衡,这里来做三个非常简单的 Node 应用负载。

pm2 start /data/nginx/html/test/load-balancer-demo/server-1.js
pm2 start /data/nginx/html/test/load-balancer-demo/server-2.js
pm2 start /data/nginx/html/test/load-balancer-demo/server-3.js

image-20221209100627081

三个 Node.js 服务应该分别在 localhost:3001、localhost:3002、localhost:3003 上运行。

9.2 实现负载均衡

NGINX 中的upstream(上游)是可以视为单个后端的服务器集合,所以可以将 PM2 的三个服务放在一个单一的上游中,就可以让 NGINX 平衡它们之间的负载。

events {}http {upstream backend_servers {server localhost:3001;server localhost:3002;server localhost:3003;}server {listen 80;server_name zhurs.tech;location / {proxy_pass http://backend_servers;}}
}

测试验证:可通过一个 while 循环来验证。

while sleep 0.5; do curl http://zhurs.tech; done

image-20221209102653869

从服务器的响应中可以看出,NGINX 正在自动对服务器进行负载平衡。

<点击跳转至开头>

上一篇:Virtual Private Network

下一篇:多谐振荡器

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...