Nginx 基础配置和语法

全局变量

Nginx 有一些常用的全局变量,可以在配置的任何位置使用他们。列举一些比较常见的:

变量
描述

HTTP 相关的变量

$host

请求行中的 Host,如果有 Host 请求头,则用其值替换掉请求行中的主机名,如果请求中没有 Host 行和 Host 请求头,则等于请求匹配的 server 名称(处理请求 server 的 server_name 指令的值),值为小写,不包含端口

$uri

请求中的当前 URI(不同于 URL ,不包括 ? 后面的请求参数,参数位于 $args),不同于浏览器传递 $request_uri 的值,它可以通过内部重定向,或者使用 index 指令进行修改,不包括协议和主机名,例如 /abc/ef.html

$document_uri

当前请求在 root 指令中指定的值,与 $uri 完全相同,历史问题存在

$request_uri

完整的原始请求 URL(包括 URI 和完整的参数),它无法修改,请查看 $uri 更改或重写 URL

$scheme

请求模式,http 或 https

$request

原始的 url 请求,含有方法与协议版本,例如 GET /?a=1&b=22 HTTP/1.1

$request_method

客户端请求类型,如 GET、POST

$request_length

所有请求内容的大小,包括请求行、头部、包体等

$request_body

请求中的包体,这个变量当且仅当使用反向代理,且设定用内存暂存包体时才有效

$request_body_file

临时存放请求包体的文件,如果包体非常小则不会存文件,可以通过 client_body_in_file_only 强制所有包体存入文件,且可决定是否删除

$remote_user

由 HTTP Basic Authentication 协议传入的用户名

$args

请求中的参数,这个变量可以被修改

$arg_PARAMETER

GET 请求中变量名 PARAMETER 参数的值,/test?name=abc$arg_name 为 abc

$is_args

如果请求有参数则为 "?",否则为空字符串""

$query_string

$args 相同

$content_length

请求头中标识包体长度的 Content-Length 字段

$content_type

请求头中标识包体类型的 Content-Type 字段

$http_HEADER

HTTP 请求头中的内容,HEADER 为 HTTP 请求中的内容转为小写,- 改为 _ (破折号变为下划线),例如 $http_user_agent

$http_user_agent

客户端 agent 信息

$http_cookie

客户端 cookie 信息

$cookie_COOKIE

$arg_PARAMETER 类似,获取某个 cookie 值

TCP 连接相关的变量

$binary_remote_addr

客户端地址的整型格式,对于 IPv4 是 4 字节,对于 IPv6 是 16 字节

$remote_addr

客户端的 IP 地址

$remote_port

客户端的端口

$connection

递增的连接序号

$connection_requests

当前连接上执行过的请求数,对 keepalive 连接有意义

$proxy_protocol_addr

若使用了 proxy_protocol 协议则返回协议中的地址(原始用户的地址),否则返回空

$proxy_protocol_port

若使用了 proxy_protocol 协议则返回协议中的端口(原始用户的端口),否则返回空

$server_addr

服务器端地址

$server_port

服务器端端口

$server_protocol

服务器端协议,例如 HTTP/1.1

$TCP_INFO

tcp 内核层参数,包括 $tcpinfo_rtt$tcpinfo_rttvar$tcpinfo_snd_cwnd$tcpinfo_rcv_space

Nginx 处理请求过程中产生的变量

$request_time

请求处理到现在的耗时,单位为秒,精确到毫秒

$server_name

匹配上请求的 server_name 值

$https

如果开启了 TLS/SSL,则返回 on,否则返回空

$request_completion

若请求处理完则返回 OK,否则返回空

$request_id

以 16 进制输出的请求标识 id,该 id 共含有 16 个字节,是随机生成的

$request_filename

待访问文件的完整路径

$document_root

由 URI 和 root/alias 规则生成的文件夹路径

$realpath_root

将 document_root 中的软链接等换成真实路径

$limit_rate

返回客户端响应时的速度上线,单位为每秒字节数。可以通过 set 指令修改对请求产生效果

发送 HTTP 响应时相关的变量

$sent_http_HEADER

HTTP 响应头中的内容,HEADER 为 HTTP 响应中的内容转为小写,- 改为 _ (破折号变为下划线),例如 $sent_http_cache_controlsent_http_content_type

$status

HTTP 响应状态

$body_bytes_sent

传送页面的字节数,即响应中 body 包体的长度

$bytes_sent

全部 http 响应的长度

$sent_trailer_名字

把响应结尾内容里的值返回

Nginx 系统变量

$time_local

以本地时间标准输出的当前时间

$time_iso8601

使用 ISO 8601 标准输出的当前时间

$nginx_version

当前运行的 Nginx 版本号

$pid

所属 worker 进程的 id

$pipe

使用了管道则返回 p,否则返回 .

$hostname

所在服务器的主机名,与 hostname 命令输出一致

$msec

1970 年 1 月 1 日到现在的时间,单位为秒,小数点后精确到毫秒

Nginx 如何设置变量

Nginx 的配置文件使用的是一门微型的编程语言。既然是编程语言,一般也就少不了 “变量” 这种东西,但是在 Nginx 配置中,变量只能存放一种类型的值,那就是字符串。

可以用 set 配置指令动态指定变量的值,Nginx 变量名前面有一个 $ 符号,并且所有的 Nginx 变量在 Nginx 配置文件中引用时都必须带上 $ 前缀

在引用变量时,需要注意引用的变量名之后紧跟着字符时(比如后跟字母、数以及下划线),就需要使用特别的语法来消除歧义:

另外需要注意的是,如果想输出 $ 符号本身,可以这样做:

上面用到了标准模块 ngx_geo 提供的配置指令 geo 来为变量 ${dollar} 赋予字符串 "$",这样,这里返回的就是 "hello world:$"

Nginx 变量的实现原理

Nginx 的变量对应的模块可以分为:变量的提供模块和变量的使用模块

  • Nginx 启动时,提供变量的模块可以在 preconfiguration 中定义新的变量,包括定义好变量名解析出变量的方法

  • HTTP 头部读取完毕后,使用变量的模块,比如 http 的 access 日志,解析 nginx.conf 时定义变量使用方式,处理请求时,会通过变量名去对应的解析出变量的方法中求得变量值

map 模块通过映射新变量提供更多的可能性

map 模块可以基于已有变量,使用类似switch {case: ... default ...} 的语法创建新变量,为其他基于变量值实现功能的模块提供更多的可能性。ngx_http_map_module 是默认编译进项目的。

map 指令

语法 map string $variable {...},只能在 http 上下文中使用。

  • string 已有变量,可以是字符串、一个或者多个变量、变量和字符串的组合

  • $variable 生成的新的变量

  • case 规则(优先级从高到低)

    • 字符串严格匹配

    • 使用 hostnames 指令,可以对域名使用前缀 * 泛域名匹配

    • 使用 hostnames 指令,可以对域名使用后缀 * 泛域名匹配

    • ~~* 正则表达式匹配,后者忽略大小写

  • default 规则

    • 没有匹配到任何规则时,使用 default

    • 缺失 default 时,返回空字符串给新变量,即新变量为 false

  • 其他情况

    • 使用 include 语法提升可读性

    • 使用 volatile 禁止变量值缓存

例如请求头 Host: map.xu.org.cn 泛域名匹配优先于正则匹配,所以 $name 是 2。

split_client 模块对少量用户指定变量(可以实现 AB 测试)

模块默认编译进 Nginx,基于已有变量(已有变量,可以是字符串、一个或者多个变量、变量和字符串的组合)创建新变量。

过程:

  • 对已有变量的值执行 MurmurHash2 算法得到 32 位整型哈希数字,记为 hash

  • 32 位无符号整型的最大数字 2^32-1,记为 max

  • hash/max 可以得到百分比 percent

  • 配置指令中指示了各个百分比构成的范围,如 0-1%,1%-5%等,及范围对应的值

  • 当 percent 落在哪个范围里,新变量的值就对应着其后的参数。

case 规则

  • xx.xx% 支持小数点后 2 位,所有项的百分比相加不能超过 100%

  • * 由它匹配剩余的百分比(100%减去以上所有项相加的百分比)

geo 模块根据 IP 地址范围生成新变量

语法 geo [$address] $variable {...},根据 IP 地址创建新变量,默认编译进 Nginx。只能在 HTTP 上下文中使用。

  • 如果 geo 指令后不输入 $address,那么默认使用 $remote_addr 变量作为 IP 地址

  • {} 内的指令匹配:优先最长匹配

    • 通过 IP 地址及子网掩码的方式,定义 IP 范围,当 IP 地址在范围内时新变量使用其后的参数值

    • default 指定了当以上范围都未匹配上时,新变量的默认值

    • proxy 指定新地址,此时 remote_addr 的值为 X-Forwarded-For 头部值中最后一个 IP 地址

    • include 优化可读性

    • delete 删除指定网络

Nginx 配置文件的基本结构

拿我们之前编译安装的 Nginx 主配置文件 /usr/local/nginx/conf/nginx.conf 来看,nginx.conf的结构图大体如下:

Nginx 配置文件的语法规则

Nginx 是由一些模块组成,一般在配置文件中使用一些具体的指令来控制。 指令被分为简单指令(简称指令)和块级指令(简称指令块)。

简单指令

简单指令是由名字和参数组成,中间用空格分开,并以分号结尾。

块级指令

块级指令跟简单指令有类似的结构,但是末尾不是分号而是用大括号( {} )包裹的额外指令集。如果一个块级指令的大括号中有其他指令,则它被叫做一个上下文(比如: events、http、server 和 location)。

在配置文件中,没有放在任何上下文中的指令都处在主上下文中。eventshttp 的指令是放在主上下文中,server 放在 http 中,location 放在 server 中。

语法规则

  • 配置文件由指令与指令块构成

  • 每条指令以分号(;)结尾,指令与参数间以空格符号分隔

  • 指令块以大括号({})将多条指令组织在一起

  • include 语句允许组合多个配置文件以提升可维护性

  • 通过 # 符号添加注释,提高可维护性

  • 通过 $ 符号使用变量

  • 部分指令的参数支持正则表达式,例如常用的 location 指令

location 指令规则

location 指令用于仅匹配 uri,忽略参数,可以使用合法的字符串或者正则表达式

语法:

指令后面:

  • =:精确匹配,用于不含正则表达式的 uri 前,如果匹配成功,不再进行后续的查找

  • ^~:前缀匹配,用于不含正则表达式的 uri 前,表示如果该符号后面的字符是最佳匹配。采用该规则,不再进行后续的正则查找。跟 = 的区别是,不需要 uri 一模一样,只需要开头和 uri 匹配即可。

  • ~:正则匹配,表示用该符号后面的正则 uri 去匹配路径,区分大小写

  • ~*:正则匹配,表示用该符号后面的正则 uri 去匹配路径,不区分大小写。

  • :普通匹配(最长字符匹配),匹配以 uri 开头的字符串,只能是普通字符串。例如,location / 是通用匹配,任何请求都会匹配到。另外普通匹配与 location 顺序无关,是按照匹配的长短来确定匹配结果。

优先级

location = > location 完整路径(还会去匹配正则) > location ^~ 路径 > location ~,~* 正则顺序 > location 部分起始路径 > location /

即:精确匹配 > 最长字符串匹配,完全匹配(还会去匹配正则) > 前缀匹配 > 正则匹配 > 普通匹配(最长字符串匹配,部分匹配) > 通用匹配

注意:

  • 在所有匹配成功的 uri 中,选取匹配度最长的 uri 字符地址。正则除外,正则匹配是按照先后顺序确定匹配结果

  • 正则匹配成功之后停止匹配,普通匹配成功后还会接着匹配正则。举个例子:

  • 如果 uri 包含正则表达式,则必须有 ~~* 标志,否则正则代码只能作为普通字符使用,例如 location = /demo$ ,其中的 $ 并不代表正则模式结束,而是一个实实在在的 $ 字符,是 url 的一部分。

  • 针对 ~~* 匹配标识符,可以在前面加上 ! 来取反:!~:表示正则不匹配,区分大小写, !~*:表示正则不匹配,不区分大小写

根据优先级来模拟 Nginx location 的匹配过程

  1. Nginx 首先根据 url 检查最长匹配前缀字符串,即会判断 =^~ 修饰符定义的内容

  • 如果匹配到最长匹配前缀字符串(即最长的 uri)

    • 如果最长匹配前缀字符串被 = 修饰符匹配,则立即响应

    • 如果没有被 = 修饰符匹配,则执行第 2 步判断。

  • 如果没有匹配到最长匹配前缀字符串

  1. Nginx 继续检查最长匹配前缀字符串,即判断 ^~ 修饰符定义的内容

  • 如果最长匹配前缀字符串被 ^~ 修饰符匹配,则立即响应

  • 如果被 修饰符匹配,则将改匹配保存起来(不管是普通匹配的完全匹配还是部分匹配),并执行第 3 步判断。

  1. Nginx 找到 nginx.conf 中定义的所有正则匹配(~~*),并按顺序进行匹配。

  • 如果有任何正则表达式匹配成功,则立即响应

  • 如果没有任何正则匹配成功,则响应第 2 步中存储的 修饰符匹配结果

loaction 其他

  1. @ 开头的是用于内部跳转的命名 location。

  2. merge_slashes 可以合并 url 中的重复斜杠,除了 base64 编码的格式,其他情况都需要打开

典型配置

源码编译安装到 /usr/local/nginx 的 Nginx 典型配置

yum 安装的 Nginx 典型配置

配置中常用指令详细说明

指令介绍

指令是有 Context 的,不同的指令可以应用的 Context 可能也不同。

  • 值指令,主要是存储配置项的值,值指令可以合并,继承规则是向上覆盖,即子配置不存在时,直接使用父配置,子配置存在时,直接覆盖父配置。例如 rootaccess_loggzip 等指令

  • 动作类指令,主要是指定行为,此类指令不可以合并,例如 rewriteproxy_pass 等指令,这些指令生效阶段一般是 server_rewrite 阶段rewrite 阶段content 阶段

main 全局配置

  • worker_processes 1;

定义在配置文件顶级 main 部分,worker 角色的工作进程个数。master 进程是接受并分配请求给 worker 处理。这个数值可以简单设置为 CPU 的核数 grep ^processor /proc/cpuinfo | wc -l,也可以是 auto 值。如果开启了 ssl 和 gzip,更应该设置成与逻辑 CPU 数量一样甚至为 2 倍,可以减少 I/O 操作。如果 Nginx 服务器还有其它服务,可以考虑适当减少。

  • worker_cpu_affinity 0001 0010 0100 1000;

定义在 main 部分。在高并发情况下,通过设置 cpu 粘性来降低由于多 CPU 核切换造成的寄存器等现场重建带来的性能损耗。如 worker_cpu_affinity 0001 0010 0100 1000; (四核)。

  • use epoll; 写在 events 部分。在 Linux 操作系统下,nginx 默认使用 epoll 事件模型,得益于此,nginx 在 Linux 操作系统下效率相当高。同时 Nginx 在 OpenBSD 或 FreeBSD 操作系统上采用类似于 epoll 的高效事件模型 kqueue。在操作系统不支持这些高效模型时才使用 select。

http 配置

  • sendfile on;

    开启高效传输模式,sendfile 指令指定 nginx 是否调用 sendfile 函数来输出文件,减少用户空间到内核空间的上下文切换。对于普通应用设为 on,如果用来进行下载等应用磁盘 IO 重负载应用,可设置为 off,以平衡磁盘与网络 I/O 处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成 off。

  • client_max_body_size 10m;

    允许客户端请求的最大单文件字节数。如果有上传较大文件,请设置它的限制值。

server 虚拟主机

http 服务上支持若干虚拟主机。每个虚拟主机对应一个 server 配置项,配置项里面包含该虚拟主机相关的配置。在提供 mail 服务的代理时,也可以建立若干 server,每个 server 通过监听地址或端口来区分。

  • listen 80;

    监听端口和地址,默认 80,小于 1024 的要以 root 启动,可以只指定端口或者指定地址和端口,例如listen *:80;listen 127.0.0.1:80

  • server_name localhost;

    服务器名,可以设置多个,第一个名字将成为主服务器名称(主域名),服务器名称可以使用 * 代替名称的第一部分或者最后一部分;也可以通过正则匹配(加 ~ 前缀),还可以使用正则表达式进行捕获。

server_name 扩展

1、server_name 第一个名字作为主域名可以配合 server_name_in_redirect,可以让多个子域名有重定向时,重定向到主域名下。

2、 serve_name 可以使用正则表达式的小括号 () 创建变量,并且可以使用尖括号 ?<> 来命名变量。

3、 .example.com 可以匹配到 example.com *.example.com

4、 _ 匹配所有域名

5、 在某个 server 块下的 server_name 使用 "" 匹配没有传递 Host 头部的请求

多个 server 块的匹配顺序

  1. 优先精确匹配,跟 server 块在 nginx.conf 中的顺序无关

  2. 其次优先匹配 * 在前的泛域名

  3. 其次优先匹配 * 在后的泛域名

  4. 其次匹配到正则表达式,匹配顺序是按 nginx.conf 文件中的出现顺序匹配正则表达式域名

  5. 最后会匹配到 default server,default server 又分为两种情况,第一种是匹配第一个 server 块,另一种情况是如果 listen 指令后面有 default 时,所在的 server 块就是 default server。

localtion

访问控制 allow/deny

Nginx 的访问控制模块默认就会安装,而且写法简单,可以分别有多个 allow/deny ,允许或禁止某个 ip 或 ip 段访问,依次满足任何一个规则就停止往下匹配。

我们也常用 httpd-devel 工具的 htpasswd 来为访问的路径设置登录密码:(此处笔者没有验证

这样就生成了默认使用 CRYPT 加密的密码文件。打开上面 nginx-status 的两行注释,重启 Nginx 生效。

列出目录 autoindex

Nginx 默认是不允许列出整个目录的。如果需要此功能,打开 nginx.conf 文件,在 location、server 或 http 部分加入 autoindex on;,另外两个参数最好也加进去:

  • autoindex_exact_size off;

    默认为 on,显示出文件的确切大小,单位是 bytes。改为 off 后,显示出文件的大概大小,单位是 KB、MB 或者 GB。

  • autoindex_localtime on;

    默认为 off,显示的文件时间为 GMT 时间。改为 on 后,显示的文件时间为文件的服务器时间。

Nginx 的 if 判断

rewrite 模块提供的,可以用在 server,location 上下文中,如果条件 condition 为真,则执行大括号内的指令;遵循值指令的继承规则

括号中的表达式语法

普通语法

  • 当表达式只是一个变量时,如果值为空或任何以 0 开头的字符串都会当做 false

  • 直接比较变量和内容时,使用 = 或 !=

正则语法

  • ~!~ 判断是否匹配正则表达式,区分大小写

  • ~*!~* 判断是否匹配正则表达式,不区分大小写

文件及目录

  • -f!-f 判断是否存在文件

  • -d!-d 判断是否存在目录

  • -e!-e 判断是否存在文件、目录、软连接

  • -x!-x 判断文件是否可执行

if 指令出现问题的原因

  • if 指令在 rewrite 阶段执行

  • if {} 块中的配置,会在 if 条件为真时,替换当前请求的配置

    • if {} 同样向上继承父配置

    • 当在 rewrite 阶段顺序执行时,每次 if 为真都会替换当前请求的配置(连续的 if 后面的会覆盖前面的)

  • if {} 中的配置,会影响 rewrite 阶段之后的阶段执行

error_page 配置

error_page 指令的语法是 error_page code... [=[response]] uri;,可以使用的上下文是 http,server,location,if in location

例子:

  1. error_page 404 /404.html;

  2. error_page 500 502 503 504 /50x.html;

  3. error_page 404 =200 /empty.gif 把状态码 404 替换成 200 返回给客户端

  4. error_page 404 = /404.php;

  5. error_page 403 http://example.com/forbidden.html

  6. error_page 404 =301 http://example.com/notfound.html

  7. 根据 @ 符号进行内部跳转

Nginx 中的配置单位

时间单位

  • ms:毫秒(milliseconds)

  • s:秒(seconds)

  • m:分钟(minutes)

  • h:小时(hours)

  • d:天(days)

  • w:周(weeks)

  • M:月(months,30 days)

  • y:年(years,365 days)

空间单位

默认为字节(bytes)

  • k/K:kilobytes

  • m/M:megabytes

  • g/G:gigabytes

推荐文档

Last updated