# nginx常用配置

## nginx

### 基本配置

nginx简单来说可以由三部分组成：全局块、events块和http块，并且nginx中存在作用域，每个大括号代表一个作用域。

```
#全局块
user  www;
worker_processes 1;
pid        logs/nginx.pid;
#events块
events {
    worker_connections 1024;
}
# http块
http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;
    #server块
    server {
        #指定域名和端口号
        listen 80;
        server_name localhost;
        access_log logs/localhost.access.log combined;
        error_log logs/localhost.error.log debug;

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

nginx主要功能在http块中，http块又有server块，server块又有location。

server块是虚拟主机部分，需要指定域名(或ip地址)以及端口号，每个server块中可以有多个location块，location块的作用是根据客户端的请求URL去定位不同的应用。

如上面的配置，当访问`http:localhost`时就会匹配到`location /`，并将`html/index.html`返回。

location的匹配规则

Untitled Database

### 内置变量

nginx变量理解成某种在\*\*请求之间全局共享的东西，\*\*或者说“全局变量”。所有的内置变量都可以通过`$变量名`来引用。

常用的内置变量

* $args //请求中的参数，如www\.123.com/1.php?a=1\&b=2的$args就是a=1\&b=2
* $content\_length //HTTP请求信息里的“Content-Length”
* $conten\_type //HTTP请求信息里的“Content-Type”
* $document\_root //nginx虚拟主机配置文件中的root参数对应的值
* $document\_uri //当前请求中不包含指令的URI，如www\.123.com/1.php?a=1\&b=2的$document\_uri就是1.php,不包含后面的参数
* $host //主机头，也就是域名，请求中的主机头(Host)字段，如果请求中的主机头不可用或者空，则为处理请求的server名称
* $http\_user\_agent //客户端的详细信息，也就是浏览器的标识，用curl -A可以指定
* $http\_cookie //客户端的cookie信息
* $limit\_rate //如果nginx服务器使用limit\_rate配置了显示网络速率，则会显示，如果没有设置， 则显示0
* $remote\_addr //客户端的公网ip
* $remote\_port //客户端的端口
* $remote\_user //如果nginx有配置认证，该变量代表客户端认证的用户名
* $request\_body\_file //做反向代理时发给后端服务器的本地资源的名称
* $request\_method //请求资源的方式，GET/PUT/DELETE等
* *requestilename*//*当前请求的资源文件的路径名称*，*相当于是*document\_root/$document\_uri的组合

  *f*
* *requestri*//*请求的链接*，*包括*document\_uri和$args

  *u*
* $scheme //请求的协议，如ftp,http,https
* $server\_protocol //客户端请求资源使用的协议的版本，如HTTP/1.0，HTTP/1.1，HTTP/2.0等
* $server\_addr //服务器IP地址
* $server\_name //服务器的主机名
* $server\_port //服务器的端口号
* *uri*//*和*document\_uri相同
* $http\_referer //客户端请求时的referer，通俗讲就是该请求是通过哪个链接跳过来的，用curl -e可以指定

### 静态资源

#### 使用静态资源

当指定某个目录作为`location`的`root`时,可以通过`URL`的方式访问到静态资源。

在`\html\static`中存放一张图片`R-C.jpg`，访问`localhost/static/R-C.jpg`

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

#### 缓存

可以设置`expires`来控制资源的缓存时间。

使用置`expires`可以控制HTTP应答中的“Expires”和“Cache-Control”的头标，从而起到控制页面缓存的作用。

可以在time值中使用正数或负数。“Expires”头标的值将通过当前系统时间加上您设定的 time 值来获得。

* `epoch`指定“Expires”的值为 1 January, 1970, 00:00:01 GMT。
* `max`指定“Expires”的值为 31 December 2037 23:59:59 GMT，“Cache-Control”的值为10年。
* `1`指定“Expires”的值为 服务器当前时间 -1s,即永远过期

“Cache-Control”头标的值由您指定的时间来决定：

* 负数：`Cache-Control: no-cache`正数或零：`Cache-Control: max-age = #`, # 为您指定时间的秒数。
* “off” 表示不修改“Expires”和“Cache-Control”的值

甚至可以使用时间单位，比如`30m`，会被自动换算成`1800s`

```
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    expires 30m;
}
```

所有时间单位。

Untitled Database

设置的缓存时间

当然你也可以通过`add_header`来控制缓存时间，效果是一样的，只不过没使用`expires`方便

```
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    # expires 30m;
    add_header cache-control 'max-age=1000';
}
```

### 压缩

nginx支持gzip压缩，通过`gzip on;`来启动gzip压缩。

```
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    gzip on; # 是否开启gzip压缩
    gzip_comp_level 6; # 压缩比，1-9，压缩比越高服务器开销越大，一般设置5-7即可
    gzip_types image/jpeg ; # 匹配MIME类型进行压缩，（无论是否指定）"text/html"类型总是会被压缩的
}
```

gzip开启成功

当nginx开启反向代理时，需要设置`gzip_proxied`，默认值是`off`。

`gzip_proxied`在Nginx作为反向代理的时候启用，开启或者关闭后端服务器返回的结果，匹配的前提是后端服务器必须要返回包含“Via”的 header头。

* off - 关闭所有的代理结果数据的压缩
* expired - 启用压缩，如果header头中包含 “Expires” 头信息
* no-cache - 启用压缩，如果header头中包含 “Cache-Control:no-cache” 头信息
* no-store - 启用压缩，如果header头中包含 “Cache-Control:no-store” 头信息
* private - 启用压缩，如果header头中包含 “Cache-Control:private” 头信息
* no\_last\_modified - 启用压缩,如果header头中不包含 “Last-Modified” 头信息
* no\_etag - 启用压缩 ,如果header头中不包含 “ETag” 头信息
* auth - 启用压缩 , 如果header头中包含 “Authorization” 头信息
* any - 无条件启用压缩

### 日志

nginx分为两种日志：access\_log(访问日志)和error\_log(错误日志)。

#### 访问日志

访问日志主要记录客户端的请求。客户端向Nginx服务器发起的每一次请求都记录在这里。客户端IP，浏览器信息，referer，请求处理时间等信息都可以在访问日志里得到。

错误日志在Nginx中是通过error\_log指令实现的。该指令记录服务器和请求处理过程中的错误信息。

访问日志通过`access_log`来设置，格式如下

```
access_log path [format [buffer=size | off ] 默认值： access_log log/access.log combined
```

指令 access\_log 指派路径、格式和缓存大小。参数 “off” 将清除当前级别的所有 access\_log 指令。如果未指定格式，则使用预置的 “combined” 格式。缓存默认是64k。

我们设置好访问日志，文件路径指向`logs/localhost.access.log`，并使用默认格式。然后`硬刷新`。

```
server {
    listen 80;
    server_name localhost;
    access_log logs/localhost.access.log combined;
}
```

```
# logs/localhost.access.log文件
127.0.0.1 - - [23/Jan/2022:11:56:51 +0800] "GET / HTTP/1.1" 200 851 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"
127.0.0.1 - - [23/Jan/2022:11:56:51 +0800] "GET /static/R-C.jpg HTTP/1.1" 200 9383 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"
127.0.0.1 - - [23/Jan/2022:11:56:52 +0800] "GET /favicon.ico HTTP/1.1" 404 288 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53"
```

#### 错误日志

错误日志通过`error_log`来设置，格式如下

```
error_log path(存放路径) level(日志等级)
日志等级分为[ debug | info | notice | warn | error | crit ],越前面的等级越高
```

示例

```
server {
    listen 80;
    server_name localhost;
    access_log logs/localhost.access.log combined;
    error_log logs/localhost.error.log debug;
}
```

### 配置HTTPS

前面已经了解了如何配置http服务，那么如何配置https呢？

配置https前必须要先准备好SSL证书，在根目录下新建`cert`目录，将两个文件放到此目录中，然后在nginx配置文件中配置

```
    server {
        listen 443 ssl;
        server_name localhost;
        ssl_certificate ../cert/fullchain.pem;
        ssl_certificate_key ../cert/privkey.pem;

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

https默认端口号是443，`listen 443 ssl`表示监听此端口上接受的连接并且应在 SSL 模式下工作。

因为window不能使用443端口，因此我改为了81端口

因为window不能使用443端口，因此我改为了81端口，实际中在服务器上是开启443端口，因为访问https时默认使用的端口号是443

假如用户仍然是通过`http`访问而不是`https`，我们如何让强制用户从`http`协议跳转到`https`协议呢？其实也很简单，通过`rewrite`重写URL即可

```
 server {
        listen 80;
        server_name localhost;
        # 如果端口号不是443则重写URL
        if ($server_port !~ 443){
            rewrite ^(/.*)$ https://$host$1 ;
        }
}
```

### 自定义错误页面

默认情况下，nginx会提供默认的404页面，但是我们通常想要使用自己做的错误界面，因此就需要在nginx进行修改。

首先准备好写好的`404.html`和`50x.html`

```
server {
    listen 80;
    server_name localhost;

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
}
```

当出现404或504等错误时，就会跳转到你设置的界面之中。

### 访问控制

某些时候，我们可能只希望某些特定ip才能访问，例如后台信息系统等场景，这时候就需要使用nginx的`allow`和`deny`，设置白名单和黑名单。

```
location / {
    deny   123.9.51.42;  # 禁止该ip的访问
    allow  45.76.202.231; # 只允许该ip的访问
}
```

可以传入`all`来表示禁止所有的访问

```
#禁止所有ip访问
location / {
    deny   all;
}
#只允许 45.76.202.231 的访问
location / {
    allow 45.76.202.231;
    deny   all;
}
#禁止对敏感文件的访问
location = /user.ini {
    deny   all;
}
```

### 反向代理

nginx通过`proxy_pass`来实现反向代理。

```
location ^~ /api/ {
    proxy_pass http://localhost:3000/;
}
```

此时访问`http://localhost/api/`就相当于访问`http://localhost:3000/`。

反向代理还有些常用的指令：

* proxy\_set\_header :在将客户端请求发送给后端服务器之前，更改来自客户端的请求头信息。
* proxy\_connect\_timeout:配置Nginx与后端代理服务器尝试建立连接的超时时间。
* proxy\_read\_timeout : 配置Nginx向后端服务器组发出read请求后，等待相应的超时时间。
* proxy\_send\_timeout：配置Nginx向后端服务器组发出write请求后，等待相应的超时时间。
* proxy\_redirect :用于修改后端服务器返回的响应头中的Location和Refresh。

### 虚拟主机

虚拟主机是指在一台物理主机服务器上划分出多个磁盘空间，每个磁盘空间都是一个虚拟主机，每台虚拟主机都可以对外提供Web服务，并且互不干扰。虚拟主机可以把多个不同域名的网站部署在同一台服务器上。

#### 基于不同端口号的虚拟主机

通过不同的端口号来配置多个网站。

```
  server {
        listen 80;
        server_name yujin123.cn;
        access_log logs/localhost.access.log combined;
        error_log logs/localhost.error.log debug;
        error_page 404 /404.html;
        location / {
            root html1;
            index index.html index.htm;
        }
    }

    server {
        listen 81;
        server_name yujin123.cn;
        location / {
            root html2;
            index index.html index.htm;
        }
    }
```

#### 基于不同域名的虚拟主机

通过多个域名来配置虚拟主机

```
  server {
        listen 80;
        server_name yujin123.cn;
        access_log logs/localhost.access.log combined;
        error_log logs/localhost.error.log debug;
        error_page 404 /404.html;
        location / {
            root html1;
            index index.html index.htm;
        }
    }

    server {
        listen 80;
        server_name yujin321.cn;
        location / {
            root html2;
            index index.html index.htm;
        }
    }
```

#### 基于不同ip地址的虚拟主机

```
  server {
        listen 80;
        server_name 112.23.108.95;
        access_log logs/localhost.access.log combined;
        error_log logs/localhost.error.log debug;
        error_page 404 /404.html;
        location / {
            root html1;
            index index.html index.htm;
        }
    }

    server {
        listen 80;
        server_name 112.23.108.94;
        location / {
            root html2;
            index index.html index.htm;
        }
    }
```

### 实现跨域

nginx实现跨域有两种方式。

#### 第一种（同源）

第一种方式是利用反向代理，代理后端接口使其与网站同源。

```
server {
        listen 80;
        server_name localhost;
        access_log logs/localhost.access.log combined;
        error_log logs/localhost.error.log debug;

        location ^~ /api/ {
            proxy_pass http://localhost:3000/;
        }

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

因为网站与请求接口同源（协议、域名和端口号都相同），符合浏览器的同源策略，因此不会产生跨域问题。

#### 第二种（CORS）

第二种是利用跨源资源共享（CORS）来实现跨域，在nginx中添加响应头，配置`access-control-allow-origin`、`access-control-allow-headers`和`access-control-allow-methods`，分别表示允许跨域的源、请求头和方法。

```
 server {
    listen 8080;
    server_name localhost;
    location / {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
    }
}
```
