文章目录
- 一、前言
- 二、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 配置文件你真的懂吗?当你安装完成后就可以访问到如下图测试页面,那它的实现流程又是怎样的呢?
接下来将从 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";
}
}
从技术上讲,NGINX 配置文件中的所有内容都是指令。指令有两种类型:
- 简单指令:一个简单的指令由指令名称和其参数组成(指令名称与其参数以空格分隔),且以分号结束。例如
listen
、return
。 - 块指令:
{ }
块指令类似于简单指令,不同之处在于它们不是以分号结尾,而是以一对包含附加指令的大括号结束。
2.2 上下文
能够在其内部包含其他指令的块指令称为上下文,即events
,http
依此类推。NGINX 中有四个核心上下文:
events { }
:events
上下文用于设置有关 NGINX 将如何在一般级别处理请求的全局配置。一个有效的配置文件中只能有一个events
上下文。http { }
:http
上下文用于定义有关服务器将如何处理 HTTP 和 HTTPS 请求的配置。一个有效的配置文件中只能有一个http
上下文。server { }
:server
上下文嵌套在http
上下文中,用于在单个主机中配置特定的虚拟服务器。server
上下文中可以有多个,每个server
上下文都被视为一个虚拟主机。main
:main
上下文是配置文件本身。在前面提到的三个上下文之外编写的任何内容都在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";
}
}
流程:
- 当客户端向 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
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
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 样式已经改变,比之前美观多了。
在types
上下文中映射文件类型可能适用于小型项目,但对于大型项目而言,它可能很麻烦且容易出错。
NGINX 为这个问题提供了解决方案。在 Nginx 默认安装目录中,你会看到一个名为 mime.types
的文件(默认路径 /etc/nginx/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/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/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
当请求 zhurs.tech:81/hello
时,location
会告诉 Nginx 匹配以 hello
开头的 URL。这种匹配称为前缀匹配。
因为为前缀匹配,所以你只要保证你的 URL 的前缀相同,其返回的内容都是一样的,具体如下:
curl -i zhurs.tech:81/hello-ttttttttttttttt
# 只要保证前缀hello是一致的就可以返回相同值
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
# 但如果URL没精准到hello,则返回404
curl -i zhurs.tech:81/hello-ttttttttttttttt
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
此时访问 curl -i zhurs.tech:81/hello5kkkkkkkk
也是能正常访问的:
但要注意:正则匹配默认是区分 URL 大小写的,如下案例就不能访问成功:
curl -i zhurs.tech:81/Hello5
要想不区分 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
,就可正常访问了。
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
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 # 下图可看到优先匹配到正则表达,说明正则匹配优先级大于前缀匹配
-
优先前缀匹配与正则匹配优先级
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 # 下图可看到优先匹配到正则表达,说明优先前缀匹配优先级大于正则匹配
注意:前缀匹配和优先前缀匹配不能同时使用,如下案例就会导致 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
-
精准匹配与所有匹配的优先级
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
4.2.2 匹配优先级总结
优先级由上至下(高——>低)
匹配 | 修改器 |
---|---|
精准匹配 | = |
优先前缀匹配 | ^~ |
正则匹配 | ~、~*、!~、!~* |
前缀匹配 | / |
内部服务跳转匹配 | @ |
五、NGINX 变量
5.1 说明
1、语法
nginx 变量类似于其他编程语言的变量,使用 set
指令来声明新变量,除了您声明的变量外,NGINX 模块中还有嵌入式变量。
set $<variable_name> <variable_value>;
# 案例
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
host 变量
:该变量用于存放根地址;
uri 变量
:该变量用于存放相对于根的 URL;
args 变量
:该变量用于存放所有查询字符串。
我们还可使用 arg 变量
访问各个值,具体配置如下:
events {
}
http {
include /etc/nginx/mime.types;
server {
listen 80;
server_name zhurs.tech;
set $name $arg_name; # $arg_<query string name>
return 200 "Name - $name\n";
}
}
# 再来请求一下,看看效果
curl http://zhurs.tech:81/user?name=zhurs
六、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.html
、about.html
文件
请求1:curl -I http://zhurs.tech:81/index_page
请求2:curl -I http://zhurs.tech:81/about_page
不难看出,当我们请求 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 时,默认请求根站点:
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 还是保持不变的。
除了处理 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";
}
}
}
上图可看到我根路径下是有这个文件的,因此是能成功请求到的,看下图为请求的结果:
请求 URL:http://xxx.xxx.xxx.xxx:81/
如果我 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";
}
}
}
此时我再次请求,就会得到如下结果:
其流程就是:
- 客户端发起请求: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
请求时,就会返回如下结果:
然而,当客户端发起 http://zhurs.tech:81/
请求时,还会返回 404,这是因为当您访问服务器根目录时,该$uri
变量不对应于任何现有文件,因此 NGINX 为您提供后备的 location
。当然,如果没有 try_files
指令的话就会自动请求根路径的index.html
资源。
那有没有办法解决这个问题呢?答案是有的。看如下配置:就是加了个 $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/
,就会正常返回,如下图:
那其流程又是怎么样的呢?
-
客户端发起请求: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 服务器发送一个请求,看看访问日志。
下图就是客户端的请求日志:
默认情况下,对服务器的任何请求都将记录到此文件中。但在配置文件中,我们可以使用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
在没有指定错误日志输出路径的情况下,默认输出到默认 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
错误日志级别:共 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/";
}
}
}
发起请求后,就会被反向代理。
8.2 反向代理 Node.js
8.2.1 准备应用程序
1、安装 nodejs 工具及 pm2 守护进程管理器
关于 pm2 可看其官方文档:https://pm2.keymetrics.io/docs/usage/quick-start/
2、进入项目目录并启动项目
cd /data/nginx/html/test/node-js-demo
pm2 start app.js
3、请求验证
curl -i 10.150.16.95:3000
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
虽然这适用于像这样的基本服务器,但需要添加更多指令才能使其在实际场景中运行,具体取决于应用程序的要求。例如,如果您的应用程序处理 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 <header name> <header value>
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
3、请求验证
curl -i 10.150.16.95:8000
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:8000
fastcgi_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、验证
请求结果返回 502,那可能就是服务器问题。查看 nginx 错误日志:
似乎 NGINX 进程被拒绝访问 PHP-FPM 进程的权限。出现权限被拒绝错误的主要原因之一是用户不匹配。查看拥有 NGINX 与 PHP 工作进程的用户。
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;
}
}
}
再次请求:
在 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
三个 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
从服务器的响应中可以看出,NGINX 正在自动对服务器进行负载平衡。
<点击跳转至开头>