Nginx 入门

703 阅读15分钟

image.png

一、简介

Nginx是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。

安装、启动及常用命令行指令

以windows系统为例,在官网下载对应的版本后,并解压到磁盘中:

  • 可以直接点击nginx.exe启动
  • 也可以在cmd切换到nginx目录下,执行start nginx

其他常用命令:

  • nginx -s reload 服务重启,一般用于配置文件修改后,重新启动nginx服务
  • nginx -s stop 直接停止服务
  • nginx -s quit 平滑停止服务

二、配置文件nginx.conf

nginx.conf是nginx的主配置文件,采用类JSON的语法。

#全局块
worker_processes  1;
#event块
events {
  worker_connections  1024;
}
#http块
http {
  #http全局块
  include       mime.types;
  keepalive_timeout  65;
  #server块
  server {
    #server全局块
    listen       8000;
    server_name  localhost;
    #location块
    location / {
      root   html;
      index  index.html index.htm;
    }
  }
}

主要包含三大部分:

  • 全局块
  • http块
  • server块(包含在http块中),每个server可以分配一个端口号,http块中可以有多个server

全局块

全局块设置影响Nginx服务器整体运行的配置指令。主要包括:配置运行Nginx服务器的用户(组)、允许生成的worker process数、Nginx进程PID存放路径、日志的存放路径和类型以及配置文件引入等。

# 指定可以运行nginx服务的用户和用户组,只能在全局块配置
# user [user] [group]
# 将user指令注释掉,或者配置成nobody的话所有用户都可以运行
# user nobody nobody;
# user指令在Windows上不生效,如果你制定具体用户和用户组会报小面警告
# nginx: [warn] "user" is not supported, ignored in D:\software\nginx-1.18.0/conf/nginx.conf:2

# 指定工作线程数,可以制定具体的进程数,也可使用自动模式,这个指令只能在全局块配置
worker_processes number | auto;
# 列子:指定4个工作线程,这种情况下会生成一个master进程和4个worker进程
worker_processes 4;

# 指定pid文件存放的路径,这个指令只能在全局块配置
pid logs/nginx.pid;

# 指定错误日志的路径和日志级别,此指令可以在全局块、http块、server块以及location块中配置。(在全局会配置nginx全局的错误信息,在不同的server块下会单独记录该server的错误信息)
# 其中debug级别的日志需要编译时使用--with-debug开启debug开关
error_log [path] [debug | info | notice | warn | error | crit | alert | emerg] 
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

events 块

events块涉及的指令主要影响Nginx服务器与用户的网络连接。

# 当某一时刻只有一个网络连接到来时,多个睡眠进程会被同时叫醒,但只有一个进程可获得连接。如果每次唤醒的进程数目太多,会影响一部分系统性能。在Nginx服务器的多进程下,就有可能出现这样的问题。
# 开启的时候,将会对多个Nginx进程接收连接进行序列化,防止多个进程对连接的争抢
# 默认是开启状态,只能在events块中进行配置
# accept_mutex on | off;

# 如果multi_accept被禁止了,nginx一个工作进程只能同时接受一个新的连接。否则,一个工作进程可以同时接受所有的新连接。 
# 如果nginx使用kqueue连接方法,那么这条指令会被忽略,因为这个方法会报告在等待被接受的新连接的数量。
# 默认是off状态,只能在event块配置
# multi_accept on | off;

# 指定使用哪种网络IO模型,method可选择的内容有:select、poll、kqueue、epoll、rtsig、/dev/poll以及eventport,一般操作系统不是支持上面所有模型的。
# 只能在events块中进行配置
# use method
# use epoll

# 设置允许每一个worker process同时开启的最大连接数,当每个工作进程接受的连接数超过这个值时将不再接收连接
# 当所有的工作进程都接收满时,连接进入logback,logback满后连接被拒绝
# 只能在events块中进行配置
# 注意:这个值不能超过超过系统支持打开的最大文件数,也不能超过单个进程支持打开的最大文件数,具体可以参考这篇文章:https://cloud.tencent.com/developer/article/1114773
# worker_connections  1024;

http块

http块是Nginx服务器配置中的重要部分,http块中可以包含自己的全局块,也可以包含server块,server块中又可以进一步包含location块,

  • http块
    • server 1
      • location1
      • location 2
    • server 2 ...

常用的http块全局配置包括:

include  mime.types; # 使用include引入其他的文件, 配置http Response 的  Content-Type
default_type  application/octet-stream; # 配置默认类型,http Response 的  Content-Type
access_log path [format [buffer=size]] # 访问日志文件
sendfile  on | off;  # 传输时是否拷贝(直接把文件传输给客户端还是先在nginx应用程序内存中处理为2进制文件再传输)
keepalive_timeout  120s 120s; # 配置nginx支持长链接,它允许在单个TCP连接上发送多个HTTP请求和响应,而不需要为每个请求都建立和关闭一个独立的连接。

server 块

server块和“虚拟主机”的概念有密切联系。虚拟主机技术可以将一台服务器的某项或者全部服务内容逻辑划分为多个服务单位,对外表现为多个服务器。
每一个http块都可以包含多个server块,而每个server块就相当于一台虚拟主机。
主要的配置项包括listenserver_name

  • listen: 监听的端口号
  • server_name: 指定域名或主机名,以便 Nginx 能够根据请求的域名来路由流量到正确的服务器块(server block)

刚开始不理解这个server_name的作用,其实它可以解决这样的问题:比如有两个地址 a.com_和_b.com,都指向同一个ip地址同一个端口,通过配置不同的server_name,可以将这个两个地址的请求交给不同的server块去处理。

域名是一个整体的网络标识,主机名是域名的一部分,通常是用来区分同一域名下的不同服务器或服务。 比如:域名:www.example.com 在这个域名中:

  • "com" 是顶级域名(TLD)。
  • "example" 是二级域名。
  • "www" 是主机名。

location

location 指令是 nginx 中最关键的指令之一,location 指令的功能是用来匹配不同的 URI 请求,进而对请求做不同的处理和响应。

基本语法

标准的location匹配类似这样:/abc,这样请求地址前缀为http://域名/abc的请求会被这个location块处理。
同时location还支持其他的语法来匹配来实现更复杂的需求:

location [ = | ~ | ~* | ^~ ] /URI { … }
location @/name/ { … }
参数解释示例
表示前缀匹配,代表跟请求中的 URI 从头开始匹配。location /abc
//可以匹配
http://192.168.200.133/abc
http://192.168.200.133/abc?p1=TOM
http://192.168.200.133/abc/
http://192.168.200.133/abcdef
=用于标准 URI 前,要求请求字符串与其精准匹配,成功则立即处理,nginx停止搜索其他匹配。location =/abc
可以匹配到
http://192.168.200.133/abc
http://192.168.200.133/abc?p1=TOM
匹配不到
http://192.168.200.133/abc/
http://192.168.200.133/abcdef
^~用于标准 URI 前,并要求一旦匹配到就会立即处理,不再去匹配其他的那些个正则 URI,一般用来匹配目录
~用于正则 URI 前,表示 URI 包含正则表达式, 区分大小写
~*用于正则 URI 前, 表示 URI 包含正则表达式, 不区分大小写
@@ 定义一个命名的 location,@ 定义的locaiton名字一般用在内部定向,例如error_page, try_files命令中。它的功能类似于编程中的goto。

匹配的顺序

优先级从高到低依次为(序号越小优先级越高):

  1. location =    # 精准匹配
  2. location ^~   # 带参前缀匹配
  3. location ~    # 正则匹配(区分大小写)
  4. location ~*   # 正则匹配(不区分大小写)
  5. location /a   # 普通前缀匹配,优先级低于带参数前缀匹配。
  6. location /    # 任何没有匹配成功的,都会匹配这里处理

三、一些重要的配置指令

root、alias、

root :设置请求资源的根目录,此指令可以在http块、server块或者location块中配置。但通常在location块中进行设置。

对于root指定的目录,Nginx会将客户端请求的URI附加到该目录的路径上
语法:root path
示例1:

location /i/ {
    root /data/w3;
}

请求 /i/top.gif 是找到文件 data/w3/i/top.gif。

alias:alias指令也可用于设置一个目录,但它会完全替换URI中的部分路径,然后使用剩余部分路径来定位文件。 示例:

location /images/ {
        alias /var/www/image_files/;
}

对于请求/images/pic.jpg,Nginx会将它映射到 /var/www/image_files/pic.jpg

对于同一个location块,rootalias 不能同时设置,

index、try_files

index与try_files都涉及到文件查找和请求处理。他们的具体用法如下:

index:

index指令用于定义当URI指向一个目录时,NGINX 应该默认返回的文件。
index语法:index file ...;
可以指定一个或多个文件名,用空格分隔。NGINX 会按照指定的顺序逐个尝试这些文件,直到找到第一个存在的文件为止。

try_files:

**try_files**指令用于指定在请求文件时如何进行文件查找和处理。通常用于处理 URL 重写、文件查找和错误处理的情况。
语法:try_files file ... uri;其中,

示例用法:

server {
    listen 80;
    server_name example.com;
    index index.html;

    location /static/ {
        alias /var/www/static_files/;
        try_files $uri $uri/ =404;
    }
}

当访问 http://example.com/static/image.jpg 时,查找过程如下:

  1. 请求 URI 为 /static/image.jpg
  2. alias/static/ 映射到 /var/www/static_files/,得到文件路径 /var/www/static_files/image.jpg
  3. try_files 首先会尝试查找/var/www/static_files/image.jpg文件。
  4. 如果找不到,则尝试查找 /var/www/static_files/image.jpg/ 目录(因为有 $uri/ 部分),并根据index配置,查找目录下index.html。
  5. 最后,如果仍然找不到匹配的文件,返回 404 错误。

四、反向代理与负载均衡

反向代理

image.png
nginx一个常见的用途就是作为反向代理服务器,比如代理tomcat实例。
反向代理通常使用proxy_pass指令配置:
比如如下的配置示例,会将localhost:80的访问代理为localhost:8080

server {
 listen       80;

 location / {
  proxy_pass  http://127.0.0.1:8080
 }
}

负载均衡

反向代理的一个常见情形是结合负载均衡使用。
一个最简的配置如下,这份配置会将请求
其中upstream块定义一组后端服务器,通过location下的proxy_pass将请求分发到这组后端服务器,实现负载均衡。

http{
  upstream backend {
    server localhost:8087 ;
    server localhost:8088 ;
    server localhost:8089;
	}
  server{
    location / {
      proxy_pass http://backend;
      proxy_set_header Host $host; #设置原始主机头部
      proxy_set_header X-Real-IP $remote_addr; # 设置客户端真实 IP 地址:
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 设置客户端原始 X-Forwarded-For 头部:
    }
  }
}

负载均衡策略

nginx支持多种负载均衡策略。

  1. **轮询:**默认的负载均衡策略,每个请求按照服务器列表的顺序轮流分发。适用于后端服务器性能相近的情况。
upstream backend {
    server backend-server1;
    server backend-server2;
    server backend-server3;
}
  1. **权重轮询: **为每个后端服务器分配不同的权重,根据权重比例分发请求。适用于后端服务器性能差异较大的情况。
upstream backend {
    server backend-server1 weight=3;
    server backend-server2 weight=2;
    server backend-server3 weight=1;
}
  1. **IP 哈希: **根据客户端IP地址进行散列,将同一个IP地址的请求始终分发到同一个后端服务器。适用于需要保持会话一致性的情况。
upstream backend {
    ip_hash;
    server backend-server1;
    server backend-server2;
    server backend-server3;
}
  1. **最少连接: **将请求分发到当前连接数最少的后端服务器,以平衡连接负载。适用于处理连接数不均匀的场景。
upstream backend {
    least_conn;
    server backend-server1;
    server backend-server2;
    server backend-server3;
}
  1. 随机:随机选择一个后端服务器分发请求。适用于负载较轻的情况。
upstream backend {
    random;
    server backend-server1;
    server backend-server2;
    server backend-server3;
}
  1. 最快响应时间(Least Time):根据后端服务器的响应时间分发请求,将请求分发到响应时间最短的服务器。适用于需要优化响应时间的情况。
upstream backend {
    least_time;
    server backend-server1;
    server backend-server2;
    server backend-server3;
}

keep-alive

keep-alive,持久连接机制。可以在单个TCP连接上发送多个请求和响应,减少了为每个HTTP请求/响应对重复建立和终止连接的开销。
以下是保持活动连接机制的工作方式:

  1. 连接建立:当客户端(如Web浏览器)向服务器发送HTTP请求时,在请求中包含一个特殊的头部"Connection: keep-alive"。这告知服务器客户端支持持久连接。
  2. 响应传输:服务器处理请求并发送响应。在发送响应后,服务器不会立即关闭连接。相反,它会保持连接打开一段时间,允许在同一连接上发送附加请求。
  3. 后续请求:如果客户端想要发送更多请求,它可以通过现有的开放连接发送请求,而无需建立新连接。这减少了延迟并提高了性能,特别是当网页包含多个资源(如图像、样式表、脚本)需要单独的HTTP请求时。
  4. 连接超时:在一段不活动时间之后或者如果已达到最大请求数(根据配置),服务器可能会关闭连接。

Nginx 默认已经开启了keep-alive,同时也有一些配置设置保持活动连接的配置。
比如下面这份配置,

http {
    server {
        listen 80;
        server_name example.com;

        keepalive_timeout 60s;  # 最长保持连接的时间(在此示例中为60秒)
        keepalive_requests 100; # 单个连接上的最大请求数(在此示例中为100个请求)

        location / {
            # 处理请求的其他配置指令
        }
    }
}

五、日志

Nginx可以记录访问日志和错误日志。

访问日志

访问日志记录了来自客户端的请求信息,包括请求的URL、响应状态、用户代理等。要设置访问日志,可以在 http 或 server 块中使用 access_log 指令。

语法: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
默认值: access_log logs/access.log combined;
例子: access_log /path/to/log.gz combined gzip flush=5m;

其中:

  • path:指定访问日志文件的路径。可以是一个绝对路径,也可以是相对于 Nginx 配置文件的路径。例如:/var/log/nginx/access.log
  • format(可选):指定日志格式。Nginx 预定义了一些格式,如 combinedmainjson 等,也可以使用自定义的日志格式。自定义格式使用 log_format 指令定义,并在此处引用。
  • buffer=size(可选):设置缓冲区的大小,用于将日志数据暂存到缓冲区中。默认情况下,不使用缓冲区。
  • flush=time(可选):设置在多长时间内刷新一次缓冲区。默认情况下,每隔 1 秒刷新一次。
  • if=condition(可选):指定一个条件,只有满足条件的请求才会被记录到日志中。条件可以是一个变量,例如 status>=400,或者是一个nonempty字符串,例如if=status >= 400**,或者是一个 **non-empty** 字符串,例如 **if=loggable
http {
    # ...
    server {
        # ...
        access_log /var/log/nginx/access.log;
        # ...
    }
}

错误日志

错误日志记录了服务器的错误和警告信息,设置错误日志,可以在 http 块中使用 error_log 指令。
error_log指令语法:error_log file [level]
**其中:**level(可选)指定日志记录的级别,包括:infodebugnoticewarnerror......
为了节约服务器资源,生产环境下通常选择**error****warn**

自定义格式

访问日志可以通过log_format指令指定日志文件中的内容格式。

错误日志无法设置自定义格式

基本的示例如下,

http {
  log_format custom '$remote_addr - $remote_user [$time_local] '
    '"$request" $status $body_bytes_sent '
    '"$http_referer" "$http_user_agent"';

  server {
  }
}

在这个示例中,我们定义了一个名为 custom 的日志格式,记录了客户端IP、用户名、访问时间、请求、状态码、响应字节数、引用来源(Referer)和用户代理(User Agent)。

JSON格式

还可以将日志记录为JSON格式,便于后续的日志分析。

http {
  log_format json '{ '
    '"remote_addr": "$remote_addr", '
    '"remote_user": "$remote_user", '
    '"time_local": "$time_local", '
    '"request": "$request", '
    '"status": $status, '
    '"body_bytes_sent": $body_bytes_sent, '
    '"http_referer": "$http_referer", '
    '"http_user_agent": "$http_user_agent" '
    '}';

  server {
  }
}

日志分割

nginx默认是不支持日志文件自动分割。我们可以通过**logorate**工具来实现**。**

logrotate 是一个在类Unix系统中常用的工具,用于管理和维护日志文件。在 Windows 系统下,可以安装logrotatewin

使用方式:

  1. 在centos中是默认带有**logorate**工具的**,**在 Ubuntu 系统上,可以运行以下命令来安装 logrotate:
sudo apt-get install logrotate
  1. 创建 logrotate 配置文件: 在 /etc/logrotate.d/ 目录下创建一个新的文件,例如 nginx,用于配置 Nginx 日志的切割规则。
sudo nano /etc/logrotate.d/nginx
  1. 配置 logrotate: 在配置文件中,您可以指定日志文件、切割频率、保留的备份数量等。以下是一个示例配置,用于按天切割 Nginx 的访问日志文件:
/var/log/nginx/access.log {
    daily
    missingok
    rotate 7
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        /usr/sbin/service nginx reload > /dev/null
    endscript
}

  1. 保存并退出配置文件。
  2. 测试 logrotate 配置: 您可以手动运行 logrotate 来测试配置是否正确。
sudo logrotate -f /etc/logrotate.d/nginx
  1. 设置自动执行: logrotate 默认通过 cron 任务定期运行。可以编辑 /etc/cron.daily/logrotate 文件,确保 logrotate 在每天执行。不过,大多数系统已经默认配置了 cron 任务来运行 logrotate。

六、一些最佳实践

模块化配置

将不同的功能和配置信息分离到不同的文件中,然后通过include指令将它们引入主配置文件。这样可以使配置更易于维护和理解。

安全设置

  • 关闭不必要的模块,减少攻击面。
  • 使用 server_tokens off; 来隐藏服务器版本信息。
  • 使用 HTTPS 配置来加密通信。
  • 配置适当的访问控制,限制谁可以访问NGINX服务器。

性能优化

  • 配置适当的缓存策略,如 proxy_cache 或 fastcgi_cache。
  • 启用 Gzip 压缩以减小传输数据的大小。
  • 配置合理的连接和缓冲区大小,以匹配系统资源。

日志和错误处理

  • 配置适当的错误页,以提供用户友好的错误信息。
  • 设置日志级别,确保及时记录关键事件和故障排查信息。

参考:

Nginx配置文件详解 - 程序员自由之路 - 博客园
131-error日志与日志分割_哔哩哔哩_bilibili