# 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 配置文件中引用时都必须带上 $ 前缀

set $limit_rate 1K; #限制对客户端的响应传输速率。

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

server {
  listen 80;
  server_name test.com;

  set $temp hello;

  location / {
    default_type text/html;
    return 200 "$temp world";
  }

  location /close {
    default_type text/html;
    return 200 "${hello}world"; # 紧跟字符时的用法
  }
}

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

geo $dollar {
  default "$";
}

server {
  listen 80;
  server_name test.com;

  location {
    set $temp "hello ";
    default_type text/html;
    return 200 "${temp}world:$dollar";
  }
}

上面用到了标准模块 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 禁止变量值缓存
map $http_host $name {
  hostnames;

  default 0;

  ~map\.x\w+\.org.cn 1;
  *.xu.org.cn 2;
  map.xu.tech 3;
  map.xu.* 4;
}

例如请求头 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%减去以上所有项相加的百分比)
split_clients "${http_testcli}" $variant {
  0.51% .one;
  20.0% .tow;
  * "";
}

# 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 删除指定网络
geo $country {
  default ZZ;

  #include conf/geo.conf;
  proxy 116.62.160.193;

  127.0.0.0/24 US;
  127.0.0.1/32 RU;
  10.1.0.0/16 RU;
  192.168.1.0 UK;
}

# Nginx 配置文件的基本结构

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

main        # Nginx 的全局配置,对全局生效
├── events  # 配置影响 nginx 服务器或与用户的网络连接
├── http    # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置,可以嵌套多个 server
│   ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│   ├── server   # 配置虚拟主机的相关参数,如域名、IP、端口等,一个 http 块中可以有多个 server 块
│   ├── server
│   │   ├── location  # 配置请求的路由,以及各种页面的处理情况
│   │   ├── location  # server 块可以包含多个 location 块,location 指令用于匹配 uri
│   │   └── ...
│   └── ...
└── ...

# Nginx 配置文件的语法规则

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

# 简单指令

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

#简单指令
root /data/www;

# 块级指令

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

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

#块级指令
http {
  server {
    listen 80;
    server_name doc.chenfangxu.com;
    access_log logs/doc.chenfangxu.access.log;
    root html;

    location ~ \.php$ {
      fastcgi_pass 127.0.0.1:1025;
    }
  }
}

# 语法规则

  • 配置文件由指令与指令块构成
  • 每条指令以分号(;)结尾,指令与参数间以空格符号分隔
  • 指令块以大括号({})将多条指令组织在一起
  • include 语句允许组合多个配置文件以提升可维护性
  • 通过 # 符号添加注释,提高可维护性
  • 通过 $ 符号使用变量
  • 部分指令的参数支持正则表达式,例如常用的 location 指令

# location 指令规则

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

语法:

location [ = | ~ | ~* | ^~ | 空] uri {
  ……
}

指令后面:

  • =:精确匹配,用于不含正则表达式的 uri 前,如果匹配成功,不再进行后续的查找
  • ^~:前缀匹配,用于不含正则表达式的 uri 前,表示如果该符号后面的字符是最佳匹配。采用该规则,不再进行后续的正则查找。跟 = 的区别是,不需要 uri 一模一样,只需要开头和 uri 匹配即可。
  • ~:正则匹配,表示用该符号后面的正则 uri 去匹配路径,区分大小写
  • ~*:正则匹配,表示用该符号后面的正则 uri 去匹配路径,不区分大小写。
  • :普通匹配(最长字符匹配),匹配以 uri 开头的字符串,只能是普通字符串。例如,location / 是通用匹配,任何请求都会匹配到。另外普通匹配与 location 顺序无关,是按照匹配的长短来确定匹配结果。

# 优先级

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

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

# 注意:

  • 在所有匹配成功的 uri 中,选取匹配度最长的 uri 字符地址。正则除外,正则匹配是按照先后顺序确定匹配结果
  • 正则匹配成功之后停止匹配,普通匹配成功后还会接着匹配正则。举个例子:
# `location 完整路径` 虽然比 `location ^~ 路径` 优先级高,但还是会去匹配正则
# 如果正则匹配成功,采用正则匹配结果。如果没有匹配到 `location 完整路径`,`location ^~ 路径` 就比 `location ~,~* 正则顺序` 优先级高了
location ~ /ab {
  rewrite ^ http://baidu.com/s?word=A;
}
location /abc {
  rewrite ^ http://baidu.com/s?word=B;
}
location ^~ /ab {
  rewrite ^ http://baidu.com/s?word=C;
}

#访问 http://docs.chenfangxu.com/ab 会跳到百度搜索关键词 C
#访问 http://docs.chenfangxu.com/abc 会跳到百度搜索关键词 A
  • 如果 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 典型配置

#user  nobody;  # 定义 Nginx 运行的用户和用户组,默认由 nobody 账号运行,可以不进行设置
worker_processes  1;  # Nginx 进程数,一般设置为同 CPU 核数一样

# Nginx 的错误日志存放目录,后面可以跟日志类型
# 全局错误日志定义类型包括:[ debug | info | notice | warn | error | crit ]
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid; # Nginx 服务启动的 pid 存储位置


events {
    # 参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];
    # epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
    #use epoll;
    worker_connections  1024; # 每个进程允许最大并发数
}


http {  # 配置使用最频繁的部分,代理,缓存,日志定义等绝大多数功能和第三方模块的配置都在这里设置
    # include 是个主模块指令,可以将配置文件拆分并引用,减少主配置文件的复杂度
    include       mime.types; # 文件扩展名与类型映射表
    default_type  application/octet-stream; # 默认文件类型

    # 设置日志格式
    #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  logs/access.log  main; # Nginx 访问日志存放位置

    sendfile        on; # 开启高效传输模式
    #tcp_nopush     on; # 减少网络报文段的数量,防止网络阻塞
    #autoindex on;  # 开启目录列表访问,适合下载服务器

    #keepalive_timeout  0;
    keepalive_timeout  65;  # 保持连接的时间,也叫超时时间,单位秒,默认为0

    #gzip  on;

    include	/usr/local/nginx/conf/conf.d/*.conf; # 加载子配置项

    server {  # 配置虚拟主机的相关参数,如域名、IP、端口等
        listen       80;  # 配置监听的端口
        server_name  localhost; # 配置的域名,可以有多个,用空格隔开

        #charset koi8-r;  # 默认编码

        #access_log  logs/host.access.log  main;  # 定义本虚拟机的访问日志

        location / {
            root   html;  # 网站根目录
            index  index.html index.htm;  # 默认首页文件
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;  # 默认50x对应的访问页面
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

# yum 安装的 Nginx 典型配置

user  nginx;                        # 运行用户
worker_processes  1;                # Nginx 进程数,一般设置为同 CPU 核数一样
error_log  /var/log/nginx/error.log warn;   # Nginx 的错误日志存放目录
pid        /var/run/nginx.pid;      # Nginx 服务启动时的 pid 存放位置

events {
    use epoll;     # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
    worker_connections 1024;   # 每个进程允许最大并发数
}

http {   # 配置使用最频繁的部分,代理、缓存、日志定义等绝大多数功能和第三方模块的配置都在这里设置
    # 设置日志模式
    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;   # Nginx访问日志存放位置

    sendfile            on;   # 开启高效传输模式
    tcp_nopush          on;   # 减少网络报文段的数量
    tcp_nodelay         on;
    keepalive_timeout   65;   # 保持连接的时间,也叫超时时间,单位秒
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;      # 文件扩展名与类型映射表
    default_type        application/octet-stream;   # 默认文件类型

    include /etc/nginx/conf.d/*.conf;   # 加载子配置项

    server {
    	listen       80;       # 配置监听的端口
    	server_name  localhost;    # 配置的域名

    	location / {
    		root   /usr/share/nginx/html;  # 网站根目录
    		index  index.html index.htm;   # 默认首页文件
    		deny 172.168.22.11;   # 禁止访问的ip地址,可以为all
    		allow 172.168.33.44; # 允许访问的ip地址,可以为all
    	}

    	error_page 500 502 503 504 /50x.html;  # 默认50x对应的访问页面
    	error_page 400 404 error.html;   # 同上
    }
}

# 配置中常用指令详细说明

# 指令介绍

指令是有 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 {
      server_name example.com *.example.com www.example.*;
    }
    

# server_name 扩展

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

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

# 使用正则,并且创建变量
server {
  server_name ~^(www\.)?(.+)$;

  location / {
      root /sites/$2;
  }
}

# 创建命名变量
server {
  server_name ~^(www\.)?(?<domain>.+)$;

  location / {
      root /sites/$domain;
  }
}

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 段访问,依次满足任何一个规则就停止往下匹配。

location /nginx-status {

  allow 192.168.10.100;
  allow 172.29.73.0/24;
  deny all;
}

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

htpasswd -c htpasswd admin
New passwd:
Re-type new password:
Adding password for user admin

htpasswd htpasswd admin    //修改admin密码
htpasswd htpasswd sean    //多添加一个认证用户
location /nginx-status {
  #  auth_basic   "NginxStatus";
  #  auth_basic_user_file   /usr/local/nginx-1.6/htpasswd;

  allow 192.168.10.100;
  allow 172.29.73.0/24;
  deny all;
}

这样就生成了默认使用 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 后,显示的文件时间为文件的服务器时间。

location /images {
  root   /var/www/nginx-default/images;
  autoindex on;
  autoindex_exact_size off;
  autoindex_localtime on;
}

# Nginx 的 if 判断

if (condition) {
  ……
}

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

# 括号中的表达式语法

# 普通语法

  • 当表达式只是一个变量时,如果值为空或任何以 0 开头的字符串都会当做 false
  • 直接比较变量和内容时,使用 = 或 !=
if ($request_method != POST) {
  return 405;
}

# 正则语法

  • ~!~ 判断是否匹配正则表达式,区分大小写
  • ~*!~* 判断是否匹配正则表达式,不区分大小写
# 如果参数中有 id=1 则 301 到指定域名
if ($args ~ id=1) {
  rewrite ^ http://example.com permanent;
}
location = /test.html {
  set $name aaa;
  # 如果参数中有 name=xxx 则使用该值
  if($args ~* name=(\w+?)(&|$)) {
    set $name $1;
  }

  # 301 跳转
  rewrite ^ /$name.html permanent;
  # /test.html => /aaa.html
  # /test.html?name=bbb => /bbb.html
}

# 文件及目录

  • -f!-f 判断是否存在文件
  • -d!-d 判断是否存在目录
  • -e!-e 判断是否存在文件、目录、软连接
  • -x!-x 判断文件是否可执行
if (!-f $request_filename) {
  return 400;
}

# 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. 根据 @ 符号进行内部跳转
location / {
  error_page 404 = @fallback;
}
location @fallback {
  proxy_pass http://backend;
}

# Nginx 中的配置单位

# 时间单位

  • ms:毫秒(milliseconds)
  • s:秒(seconds)
  • m:分钟(minutes)
  • h:小时(hours)
  • d:天(days)
  • w:周(weeks)
  • M:月(months,30 days)
  • y:年(years,365 days)
expires 3m;

# 空间单位

默认为字节(bytes)

  • k/K:kilobytes
  • m/M:megabytes
  • g/G:gigabytes
client_max_body_size 10m;

# 推荐文档