# 配置

# 配置文件

  • Nginx 默认采用 /etc/nginx/nginx.conf 作为主配置文件,还会导入 /etc/nginx/conf.d/ 目录下的其它配置文件。
  • 配置文件的扩展名为 .conf ,采用 Nginx 自定的语法,用 # 声明单行注释。
    • 配置文件分为多个层级,最外层称为 main ,其下可以包含 events、http 等区块。
    • 每个层级的缩进距离建议为 4 个空格,但也可以不缩进,不影响语法。
    • 每条指令大多独占一行,以 ; 结尾。
  • 配置文件中,有的指令只能使用一次,有的指令可以重复使用。
    • 如果在局部作用域、外部作用域同时使用了某一条指令,则局部作用域里那条指令的优先级更高。

# nginx.conf

/etc/nginx/nginx.conf 的默认内容如下:

user  nginx;                    # 启动 Nginx 主进程的用户名
worker_processes  auto;         # 启动的 worker 进程数,默认为 1 ,设置成 auto 则会等于 CPU 核数
# worker_shutdown_timeout 60s;  # 限制 worker 进程优雅终止的超时时间。默认没有超时时间,可能一直于 shutting down 状态
# daemon off;                   # 是否以 daemon 方式运行 Nginx 进程,默认为 on
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;  # 将 Nginx 主进程的 PID 记录到该文件中

events {
    worker_connections  512;    # 每个 worker 进程的最大并发连接数,包括与客户端的连接、与 upsteam 的连接。默认为 512 。该值应该不能超过 ulimit -n 限制
    # use epoll;                # 处理请求事件的方法,默认会自动选择。在 Linux 上优先采用 epoll ,其次是 poll、select 等
}

http {
    include       /etc/nginx/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  /var/log/nginx/access.log  main;
    sendfile        on;
    # tcp_nopush     on;
    keepalive_timeout  65;
    # gzip  on;
    include /etc/nginx/conf.d/*.conf;
}
  • 用 include 指令可导入指定文件的内容到当前配置。
  • Nginx 默认会在 HTTP 响应头中记录服务器信息,例如 server: nginx/1.23 ,建议设置 server_tokens off; ,隐藏版本号,提高安全性。

# default.conf

/etc/nginx/conf.d/ 目录下默认存在一个 default.conf ,配置了 Nginx 的初始 Web 页面,如下:

server {
    listen       80;            # 该 server 监听的地址(必填)
    server_name  localhost;     # 监听的域名(可选)

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
  • http{} 区块中至少要定义一个 server{} ,才能监听 TCP 端口,接收 HTTP 请求。
  • server{} 区块中至少要定义一个 location{} ,才能对 HTTP 请求进行路由处理。

# 变量

  • Nginx 提供了一些内置变量,用户也可以自定义变量。
  • 变量可以通过 $var 的格式取值。
    • 变量名不区分大小写。
    • 如果变量不存在,则报错:unknown variable
    • 内置变量的默认值为 - 。
  • 例:
    location / {
        return  200 '$request_uri\n';
    }
    

# set

:为一个变量赋值。如果该变量不存在则自动创建它。

  • 可用范围:server
  • 语法:
    set $variable value;
    
  • 例:
    server {
        listen  80;
        set     $port_type 8x;
    }
    
  • 注意被赋值的变量名之前要加前缀 $ 。
  • 不能给 Nginx 的内置变量赋值,否则会报错:duplicate variable
  • 变量的值可以是数字或字符串类型。

# map

:用于将源变量输入字典取值,并赋值给目标变量。

  • 可用范围:http
  • 例:
    map $server_port $port_type{
        # default   '';   # 如果字典中没有匹配的 key ,则取默认值
        80        8x;     # 将源变量与 key 进行字符串匹配
      ~ 9\d       9x;     # 正则匹配
      ~*9\d       9x;     # 不区分大小写的正则匹配
    }
    

# 内置变量

  • 关于服务器:

    server_addr       # 服务器的 IP ,由请求指向的 IP 决定,比如 127.0.0.1
    server_name       # 服务器的名称,取决于 Nginx 中 server{} 模块配置的 server_name
    server_port       # 服务器监听的端口号
    
    hostname          # 服务器的主机名,由服务器所在主机决定
    pid               # Nginx 当前 worker process 的 PID
    nginx_version     # Nginx 的版本号
    
    upstream_addr
    upstream_response_time
    
    msec              # Unix 时间戳格式的服务器时间,比如 1603792024.820
    time_iso8601      # ISO 格式的服务器时间,比如 2020-10-28T10:27:14+08:00
    time_local        # 日志格式的服务器时间,比如 28/Oct/2020:10:27:14 +0800
    
  • 关于客户端:

    remote_addr       # 客户端的地址
    remote_port       # 客户端的端口
    remote_user       # 客户端的用户名(用于 HTTP Basic Auth)
    http_referer
    http_user_agent
    
  • 关于 HTTP 请求:

    request           # 请求报文的第一行,比如 GET /static/1.html HTTP/1.1
    request_method    # 请求的方法名,采用大写,比如 GET
    request_uri       # 请求的原始 URI ,不包括 query string
    uri               # 请求的当前 URI ,取值会因为 rewrite、alias 而改变
    args              # 请求 URL 中的 Query String
    is_args           # 如果存在 Query String 则取值为 ? (即使格式不正确),否则取值为空
    args_XXX          # Query String 中指定参数的值,不区分大小写
    
    host              # 请求指向的服务器地址,不包括端口号。按优先级取值:请求行中的主机名、请求头中的 Host 字段、处理该请求的 server_name
    request_filename  # 请求 URI 指向的服务器文件,比如 /www/static/1.html
    document_root     # request_filename 文件在服务器上所处的根目录,通常由 root 指令决定
    
    request_length    # 请求报文的长度
    server_protocol   # 请求采用的协议及版本,通常取值为 HTTP/1.0、HTTP/1.1 或 HTTP/2.0
    scheme            # 请求采用的协议,取值为 http 或 https
    https             # 如果请求采用了 HTTPS 协议则取值为 on ,否则取值为空
    
    http_XXX          # headers 中指定参数的值,不区分大小写,要将 - 写作 _
    cookie_XXX        # cookie 中指定参数的值,不区分大小写
    
    request_time      # 请求的处理时长,指从开始接收请求到发完响应报文的耗时。单位 s ,小数点后保留 3 位,即精确到 ms
    request_body      # 请求 body 。只有当 Nginx 执行了 proxy_pass、fastcgi_pass、uwsgi_pass 或 scgi_pass 时才会将请求 body 载入内存,否则该变量取值为空
    
  • 关于 HTTP 响应:

    status            # 响应报文的状态码
    bytes_sent        # 响应报文的大小,单位为 bytes
    body_bytes_sent   # 响应报文 body 的大小
    

# 日志指令

# access_log

:配置 Nginx 的访问日志,它会记录 Nginx 处理的所有 HTTP 请求。

  • 可用范围:http、server、location、limit_except
  • 语法:
    access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
    
    • 日志文件所在目录必须存在。
    • Nginx 每次写入日志时会打开文件描述符,写完之后就会关闭。
    • buffer 的默认大小为 64k 。
    • 启用 buffer 时,Nginx 不会立即将日志写入文件,而是先放入 buffer 缓存,直到满足以下任一条件:
      • buffer 满了。
      • buffer 中保留的日志超过 flush 秒。
      • Nginx worker 正在关闭或重新打开日志文件。
    • gzip 的默认压缩级别为 1 。取值为 9 时压缩率最高,速度最慢。
  • 例:
    access_log off;       # 取消当前作用域的访问日志
    
    access_log logs/access.log combined gzip=1 flush=5m if=$need_log;
    

# error_log

:配置 Nginx 的错误日志,它会记录 Nginx 的内部运行信息。

  • 可用范围:main ,http ,mail ,stream ,server ,location
  • 语法:
    error_log path [level];
    
    • 日志级别从复杂到简单依次为:debug, info, notice, warn, error, crit, alert, emerg

# log_format

:定义日志格式。该格式只能被 access_log 命令调用。

  • 可用范围:http
  • 默认值:
    log_format combined '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';
    
  • log_format 指令只能定义 access_log 的格式,不能改变 error_log 的格式。

# 流程控制指令

# if

:如果条件为真,则执行括号内的指令。

  • 可用范围:server、location
  • 例:
    if ($uri ~ /www/(\d+)/(.+)) {
        set $param1 $1;
        set $param2 $2;
        return  200 '$param1, $param2\n';
    }
    
    • Nginx 不支持 else 子句。
    • if 指令虽然比较灵活,但是很多指令不支持在 if 语句块内使用,需要谨慎。
  • 条件表达式有多种类型:
    • 取值为空字符串 ''0 则为假,否则为真。
    • =!= 进行比较运算。
    • ~!~ 进行正则匹配,用 ~*!~* 进行不区分大小写的正则匹配。
    • -f!-f 判断文件是否存在。
    • !-d!-d 判断目录是否存在。

# break

:跳过执行 ngx_http_rewrite_module 模块的指令。

  • 可用范围:server、location
  • 例:
    if ($slow) {
        limit_rate 10k;
        break;
    }
    
  • ngx_http_rewrite_module 模块的指令包括 if、break、return、rewrite、set 等

# return

:直接生成一个 HTTP 响应报文,返回给客户端。(不会执行后续指令)

  • 可用范围:server、location
  • 例:
    server{
        listen  80;
        return  404;                                # 只返回状态码
        return  200 OK\n;                           # 返回状态码和一个字符串(字符串可以不加定界符)
        return  200 '{"name":"test","id":"001"}';   # 返回状态码和 JSON 格式的字符串
        return  302 /index.html;                    # 返回 302 状态码,并指定重定向的目标
    }