0%

老司机都在用的 Nginx 实用配置

关于 Nginx 系列其他文章的传送门

  1. 《 老司机都在用的 Nginx 实用配置 》     您当前所在位置

  2. 《 干货分享 Nginx 反向代理的参数详解 》

  3. 《 8 分钟轻松学会 Nginx 负载均衡和参数调优 》

  4. 《 实战详解 - 使用 Nginx 负载均衡 Docker 中的 WordPress 和 PhpMyAdmin 》



Nginx_logo

一、前言

2019 年 3 月,Nginx 的市场占有率开始反超 Apache,到今天已经逐步拉开距离,一直霸占着榜首。

ApkN.png

数据来源参考https://news.netcraft.com/

或许你已经在使用 Nginx 承载你的网站文件,又或许用 Nginx 当做代理服务器,这里分享一些实用的 Nginx 配置,帮助你成为熟练驾驶 Nginx 的“老司机”,下面先了解几个重要的知识点(敲黑板)

二、概念

Web 程序的工作模型

Linux 中的程序是都是以 进程子进程 的方式来运行,像 Nginx、Apache 等,大体上有以下几种 Web 工作模型

  • 进程模型:一个子进程只处理一个请求, 比如 Prefork。
    • 机制:使用 select() poll(),限制在最大 1024 个进程,可以调大,但是进程多了 CPU 切换频繁,不建议。
  • 线程模型:一个子进程生成多个线程,每个线程处理一个请求,例如 Worker。
  • 事件驱动模型:一个进程同时处理多个请求。

由于在 linux 中进程是轻量化设计(LWP)的,进程和线程对资源的开销是差不多的。所以 Apache 中无论是 Prefork 还是 Worker,在 Linux 中没有显著区别,无非是运行方式不一样。但是 event 模型,已经开始采用事件驱动的模型,一个进程可以同时处理多个请求,效率极高。

而 Nginx 一开始就是依据 非阻塞 IO 的模型设计并制造的,并且支持 异步 IO

ApkN2.jpg

IO 模型

IO 模型 前先了解两个概念:

阻塞/非阻塞

主要关注调用者在等待结果返回之前的状态。(图上半部分)

  • 阻塞 blocking
    • 指进程提交 IO 请求后,需要等待数据从磁盘复制到内核内存中,在复制完成之前,进行被挂起,进入睡眠状态。
    • 例如:在饭店点了一碗面,厨师没做完之前你必须在柜台前等待。
  • 非阻塞 nobloking
    • 指进程提交 IO 请求后,无需原地等待数据复制的过程,可以先去做别的事,进程不会被挂起。
    • 例如:在饭店点了一碗面,然后找了个座位坐着,边玩手机边等。

同步/异步

关注是消息通信机制。(图下半部分)

  • 同步 asynchronous
    • 进程需要将数据从内核内存中复制到用户内存中,期间不能做别的事,等复制完才能继续执行其他操作。
    • 例如:面做好后,需要自己去柜台把面端回到座位。
  • 异步 asynchronous
    • 进程提交 IO 请求后就去忙别的事了,内核把数据的所有复制过程都完成后,通过状态、通知或者回调机制,主动通知进程。
    • 例如:面做好后,有服务员帮你把面端过来。

五种 IO 模型

io

  1. 同步阻塞型(闲等待)

  2. 同步非阻塞(忙等待)

  3. IO 复用
    进程找一个代理 select,而不直接与内核打交道,系统调用交于 select 进行处理。
    select 可以同时接收多个进程的请求。但是用户进程依旧阻塞于 select 。
    数据到达内核内存后,进程将内核内存中的数据复制到用户内存。

  4. 事件驱动
    进程提交 IO 请求后,去处理其他任务,等数据从磁盘复制到内核空间后,通过 SIGIO 告知进程,这个过程是不阻塞的。但是进程还是需要自己把数据复制到用户内存中。

  5. 异步 IO
    用户进程不受阻塞,所有的请求,数据拷贝过程都由内核完成,进程可以接收更多的用户请求。

IO 调用方式

复用型 IO 调用

  • select():最大 1024
  • poll():

事件驱动 IO 调用

  • epoll(Linux):libevent
  • Kqueue(BSD):
  • /dev/poll(Solaris)

三、Nginx 介绍

介绍

虽然 Apache 支持的模块众多,但是 Nginx 的出生就是为了解决 C10K 的问题而设计的,不仅支持 事件驱动 IO,还支持 异步 IO

c10k.jpg

特性:异步、事件驱动和非阻塞。

  • 并发请求处理:通过 epoll/select
  • 文件 IO:高级 IO sendfile,异步,mmap。

Nginx 功能示意图

map

程序模型为Master/Worker

  • Master 负责
    • 加载配置文件
    • 启动 workers
    • 进行非中断升级
  • Worker 负责
    • 处理并响应用户请求

模块化

Nginx 是高度模块化,但是早期不支持模块的动态装卸载,1.10 后的版本支持部分模块的动态装卸载。

模块分类

  • 核心模块core module
  • 标准模块
    • 静态网站模块HTTP modules
      • Standard HTTP modules
      • Optional HTTP modules
    • 邮件服务器模块Mail modules
    • 传输层代理Stream modules
  • 第三方模块3rd party modules 进程

主要功能

以下功能一般不混用

  • Web Server:静态的 Web 资源服务器。
  • Proxy Server:各种反向代理。
    • http
    • smtp
    • pop3/imap4
  • Stream Server:4 层代理模块,tcp/udp 协议的请求转发。

扩展阅读

四、安装及配置

安装

官网这里可以查看最新版本,版本的第 2 位为偶数的是 Stable

安装方法有三种:

  • 官网下载源码编译安装。
  • epel 仓库,为追求稳定,版本较老,建议生产使用
  • 官方仓库。

官方安装教程

这里是测试环境,所以使用官方仓库最新版,从官网复制 repo 到本地,然后直接 yum install nginx -y 就好了。

配置文件

Nginx 的配置文件按类型分组

  • main block:主配置段,全局配置段,对所有配置段均生效。
  • event {}:事件驱动相关配置。
  • http {}:Web 相关
    • server {}:虚拟主机、反向代理
  • mail {}:邮件相关
  • stream {}:流式的 4 层调度机制

注意

  1. 指令遵循 C 的语法,必须以分号结尾。

  2. 支持使用配置变量。

    • 内建变量:由 Nginx 模块引入,可直接引用。
    • 自定义变量:由用户使用 set 命令定义。
      • 设置变量:set variable_name value;
      • 引用变量:$variable_name

1. main 段配置

正常运行必备类

User
  • 设置运行主控进程 master 的用户身份。
  • user user [group];
PID
  • 指定 Nginx 守护进程的 PID 文件路径。
  • pid /PATH/TO/PID_FILE;
include
  • 指明包含进来的其他配置文件。
  • include file | *.conf;
load_modelu
  • 指定加载的动态模块。
  • load_modelu file;

性能优化相关类

worker_processes
  • worker 进程的数量,通常应该小于等于当前主机 CPU 物理核心数。
  • worker_processes NUMBER | auto;:设置为 auto 的话为当前物理 CPU 核心数。
worker_cpu_affinity
  • 设置 Nginx 进程的 CPU 亲缘性。
  • woker_cpu_affinity MASK;
    • auto:自动绑定
    • 00000001:0 号 CPU
    • 00000010:1 号 CPU
    • 00000100:2 号 CPU
    • 00000011:0 号和 1 号 CPU
worker_priority
  • 设置 worker 的进程优先级。
  • worker_priority [ -20,20 ];
worker_rlimit_nofile
  • workder 进程能够打开的文件数量上限。
  • worker_rlimit_nofile NUMBER;

调试及定位问题类

daemon
  • 是否以守护进程方式运行 Nignx。
  • daemon on | off;
master_process
  • 是否以 master/worker 模型运行 nginx,默认为 on,设置 off 的话则只让 master 处理请求。
  • master_process:on | off;
error_log
  • 设置日志文件及记录级别。
  • error_log file [level];

事件驱动相关类

属于 events 配置段:

1
2
3
events {
...
}
worker_connections
  • 单个 worker 进程所能打开的最大并发连接数量。
  • worker_connections NUMBER;
  • 所以整个 Nginx 的最大并发连接上限等于 worker_processes * worker_connections;
use
  • 指明处理并发连接请求的模型。
  • use epoll | select
    • epoll:事件驱动;
    • select:IO 复用。
accept_mutes
  • 为避免“惊群效应”,设置是否开启互斥锁。
  • accept_mutes on:意味着由各 worker 轮流处理新请求。
  • accept_mutes Off:意味着每个新请求的到达都会通知所有的 worker 进程。

2. http 段配置

http 中定义的配置对所有 server 生效。
而 server 的配置仅 server 范围生效。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http {
......
server {
...
listen
server_name
root
location [operator] /uri/ {
...
}
}

server {
...
}
}

3. server 段配置

一个 server {} 段代表一个虚拟主机。

1
2
3
4
5
server{
listen address[:PORT] | PORT;
server_name SERVER_NAME;
root /PATH/TO/DOCUMENT_ROOT;
}

listen address

  • 设置监听选项。
  • listen address[:port] | PORT [default_server] [ssl];
    • default_server:设置当没有匹配到域名时,默认从上而下选第一个,也可以手动设置默认虚拟主机。
    • ssl:强制仅能使用 ssl 连接。

server_name

  • 指明虚拟主机的主机名称,后可跟多个由空白字符分隔的字符串。
  • server_name NAME...;
    • 支持 * 通配任意长度的任意字符。 server_name *.baidu.com www.monster.*
    • 支持 ~ 起始的字符做正则表达式模式匹配。 server_name ~^www\d+\.baidu\.com$
    • 匹配顺序:
      (1). 首先是字符串精确匹配。
      (2). 左侧 * 通配符。
      (3). 右侧 * 通配符。
      (4). 正则表达式,不建议使用,对性能有影响。

root

  • 设置 Web 资源路径映射,用于指明用户请求的 url 所对应的本地文件系统上的文档所在目录路径,类似 Apache 中的 Document Root
  • root path;
  • 可用配置段:http, server, location
  • 注意location 中使用 root 指令和 alias 指令的意义不同:
    • root:给定的 路径 对应于 location 中的 /uri/ 左侧的 /
    • alias:给定的 路径 对应于 location 中的 /uri/ 右侧的 /

alias

  • 定义本地文件路径的别名,root 的另一种机制。仅能用于 location 上下文!
  • alias PATH;

location

  • 根据请求的 url 设置配置。
  • location [ = | ~ | ~* | ^~ ] uri { ... };
  • 一个 serverlocation 配置段可存在多个,用于实现从 uri 到文件系统的路径映射。
    • =:对 URI 做精确匹配,100% 吻合。
    • ^~:对 URI 最后一个 / 的左半部分做匹配检查,不区分字符大小写。
    • ~:对 URI 做正则表达式模式匹配,区分字符大小写。
    • ~*:对 URI 做正则表达式模式匹配,不区分字符大小写。
    • 不带符号:匹配起始于此 uri 的所有的 url。
  • 匹配优先级:= > ^~ > ~/~* > 不带符号

Apache 和 Nginx 中关于 url 的区别

  • Apache:

    1. 指定网页文件的 本地目录,可以理解为 绝对路径
      • <Directory> "/var/www/html/images/"
    2. 指定网页的 url 路径,以 DocumentRoot "/var/www/html" 为根,可以理解为 相对路径
      • <Location "/images/">
  • Nginx:

    • location /images/ { ... } 就相当于 Apache 中的 <Location "/images/">

index

  • 设定默认主页,可用于 http, server, location
  • index FILE;

error_page

  • 指定状态码和对应的网页文件。
  • error_page CODE URL;
  • 示例:error_page 404 /404.html; 注意/404.html 中前面的 / 的起始路径为能被匹配到的路径。

五、模块

Nginx 是高度模块化的,下面介绍一些常用的模块。

ngx_http_access_module (IP 访问控制)

  • 基于客户端 IP 做访问控制。默认策略为 access。
  • allow address | CIDR | unix: | all;
  • deny address | CIDR | unix: | all;
  • 可用于 http, server, location, limit_except

示例

1
2
3
4
5
6
7
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
deny all;
}

ngx_http_auth_basic_module (用户访问控制)

  • 实现基于用户的访问控制,使用 basic 机制进行用户认证。
  • auth_basic string_NAME | off;
  • auth_basic_user_file FILE;

示例

1
2
3
4
5
location /admin/ {
alias /webapps/app1/data/;
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.ngxpasswd; # 注意:htpasswd 命令由 httpd-tools 所提供
}

ngx_http_stub_status_module (状态页)

用于输出 nginx 的基本状态信息。

示例

  • 配置
1
2
3
location = /basic_status {
stub_status;
}
  • 访问 status 页面。
1
2
3
4
Active connections: 1050
server accepts handled requests
4773055 4772144 2259122
Reading: 0 Writing: 1 Waiting: 1049
  • Active connections:当前活动客户端连接数,包括等待连接。
  • accepts:已经接受的客户端请求的总数。
  • handled::已处理连接的总数。
  • requests:客户端请求的总的数。
  • Reading:nginx 正在读取请求报文首部的当前连接数。
  • Writing:nginx 正在发送响应报文的当前连接数。
  • Waiting:当前等待请求的空闲客户端连接数。

ngx_http_log_module (日志)

以指定的格式记录 access 日志。

示例配置

1
2
3
4
5
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main buffer=32k;
  • 变量含义:Nginx官网可以查看全部变量列表
    • remote_addr:客户端地址。
    • remote_user:经过 Basic 认证的用户名。
    • time_local:本地服务器时间。
    • request:请求报文的请求方法和协议版本。
    • status:响应码。
    • body_bytes_sent:响应报文 body 部分的大小。
    • http_referer:请求报文的引用页。
    • http_user_agent:客户端使用的浏览器。
    • http_x_forwarded_for:在作为被代理的服务器时,显示真正的客户端地址。

open_log_file_cache (缓存)

缓存各日志文件的元数据信息。

  • open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
    • max:缓存的最大文件描述符数量。
    • inactive:设定活动时间范围。
    • min_uses:设置的最小访问次数。结合起来的意思是,在 inactive 指定的时间范围内,最少要访问这个次数,不然被认为是无效缓存。
    • valid:验正缓存中各缓存项是否为活动项的时间间隔。

ngx_http_gzip_module (压缩)

压缩模块。

  • gzip on | off:是否启用压缩。
  • gzip_comp_level LEVEL:压缩比。
  • gzip_disable_regex:指定一个正则表达式,被正则表达式匹配到的 $http-user-agent,将关闭压缩功能。
  • gzip_min_length LENGTH:启用压缩功能的最小阈值。
  • gzip_buffers NUMBER SIZE:支持实现压缩功能时为其配置的缓冲区数量及每个缓存区的大小。
  • gzip_proxied:设置 nginx 作为代理服务器时,接收到从被代理服务器发送的响应报文后,在何种条件下启用压缩功能。
    • gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any;
      • off:对所有代理的请求不启用压缩。
      • no-cache, no-store, private:表示从被代理服务器收到的响应报文首部的 Cache-Control 的值为此三者中任何一个,则启用压缩功能。
      • any:全部压缩
  • gzip_types:压缩过滤器,仅对此处设定的 MIME 类型的内容启用压缩功能。
    • gzip_types mime-type ...;

示例

1
2
3
4
5
gzip on;
gzip_comp_level 6;
gzip_min_length 64;
gzip_proxied any;
gzip_types text/xml text/css application/javascript;

ngx_http_ssl_module (SSL)

加密 SSL 模块。

  • ssl on | off;:是否开启 ssl。
  • ssl_certificate file;:指定当前虚拟主机使用 PEM 格式的证书文件。
  • ssl_certificate_key file;:指定当前虚拟主机上与其证书匹配的私钥文件。
  • ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];:支持 ssl 协议版本,默认为后三个。
  • ssl_session_cache off | none | [builtin[:size]] [shared:name:size];:配置 ssl 缓存。
    • builtin[:size]:使用 OpenSSL 内建的缓存,此缓存为每 worker 进程私有。
    • [shared:name:size]:在各 worker 之间使用一个共享的缓存。
  • ssl_session_timeout time;:客户端一侧的连接可以复用 ssl session cache 中缓存的 ssl 参数的有效时长。

配置示例

1
2
3
4
5
6
7
8
9
server {
listen 443 ssl;
server_name www.monster.com;
root /vhosts/ssl/htdocs;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_cache shared:sslcache:20m;
}

ngx_http_rewrite_module (URL重定向)

使用正则表达式来检查请求的 RUI 地址,然后进行 URL 替换。

  • 语法:rewrite regex replacement [flag];
  • 将用户请求的 URI 基于 regex 所描述的模式进行检查,匹配到时将其替换为 replacement
  • [flag]:如果在同一级配置块中存在多个 rewrite 规则,那么会自上而下逐个检查。被某条件规则替换完成后,会重新一轮的替换检查,因此,使用 [flag] 标志位来控制此循环机制。
  • 如果 replacement 是以 http://https:// 开头,则替换结果会直接以 永久重定向 返回给客户端。

flag 可用参数

last:重写完成后停止对当前 URI 在当前 location 中后续的其它重写操作,而后对新的 URI 启动新一轮重写检查,客户端对此无感知。即:提前重启新一轮循环(continue)

break:重写完成后停止对当前 URI 在当前 location 中后续的其它重写操作,而后直接跳转至重写规则配置块之后的其它配置,客户端对此无感知。即:结束循环(break)

redirect:重写完成后以 临时重定向 方式直接返回重写后生成的新 URI 给客户端,由客户端重新发起请求。

  • 不能以 http://https:// 开头。否则就是 永久重定向 了;
  • 默认状态码 302

permanent:重写完成后以 永久重定向 方式直接返回重写后生成的新 URI 给客户端,由客户端重新发起请求。

  • 默认状态码 301

return:停止处理并将指定的代码或 URL 返回给客户端。

  • return code [text];
  • return code URL;
  • return URL;

其他参数

rewrite_log:是否开启重写日志。

  • rewrite_log on | off;

if:引入一个新的配置上下文。当条件满足时,执行配置块中的配置指令。

  • 可用配置段:server, location
  • if (condition) { ... }
    • condition
      • 比较操作符:
        • ==:等于。
        • !=:不等于。
        • ~:模式匹配,区分字符大小写。
        • ~*:模式匹配,不区分字符大小写。
        • !~:模式不匹配,区分字符大小写。
        • !~*:模式不匹配,不区分字符大小写。
      • 文件及目录存在性判断:
        • -e, !-e:文件存在与否。
        • -f, !-f:是否为空文件。
        • -d, !-d:是否为目录。
        • -x, !-x:是否为可执行文件。
          set:设定用户自定义变量。
    • set $variable value;

ngx_http_referer_module (防盗链)

当报文首部 Referer 字段中具有非法值时,阻止此次请求。(可用于防盗链)

valid_referers none | blocked | server_names | string ...;

定义 referer 首部的合法可用值:

  • none:请求报文首部没有 referer 首部。
  • blocked:请求报文的 referer 首部没有值。
  • server_names:参数,其可以有值作为主机名或主机名模式。
  • arbitrary_string:直接字符串,但可使用 * 作通配符。
  • regular expression:被指定的正则表达式模式匹配到的字符串。
    • 要使用 ~ 打头,例如 ~.*\.monster\.com;

配置示例

1
2
3
4
valid_referers none block server_names *.monster.com *.mageedu.com monster.* mageedu.* ~\.monster\.;
if($invalid_referer) {
return http://www.monster.com/invalid.jpg;
}

wugui