林秀栋的技术博客

nginx配置

文章来源

Nginx 是一个开源且高性能、可靠的 http 中间件,代理服务。Nginx(发音同 engine x)是一个 Web 服务器,也可以用作反向代理,负载平衡器和 HTTP 缓存。

nginx.conf:

# 全局配置
user  nginx;         # 配置用户或者组
worker_processes  1; # 允许生成的进程数

error_log  /var/log/nginx/error.log warn; # 错误日志路径warn 代表日志级别级别越高记录越少
pid        /var/run/nginx.pid;            # Nginx 进程运行文件存放地址

events {
  accept_mutex on;          # 设置网路连接序列化防止惊群现象发生
  multi_accept on;          # 设置一个进程是否同时接受多个网络连接
  worker_connections  1024; # 每个进程的最大连接数因此理论上每台 Nginx 服务器的最大连接数 = worker_processes * worker_connections
}

# HTTP 配置
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; # 允许 sendfile 方式传输文件

  keepalive_timeout  65; # 连接超时时间

  server {
    listen       80;         # 监听端口
    server_name  localhost;  # 监听地址

    location / {                    # 请求的url过滤正则匹配
      root   /usr/share/nginx/html; # 根目录
      index  index.html index.htm;  # 默认页
    }
  }
}

Nginx 的 HTTP 配置

HTTP 配置是 Nginx 配置最关键,同时也是 Nginx 实用技巧中最常涉及的部分。Nginx 的 HTTP 配置主要分为三个层级的上下文:http — server — location。

http

http 主要存放协议级别的配置,包括常用的诸如文件类型、连接时限、日志存储以及数据格式等网络连接配置,这些配置对于所有的服务都是有效的。

server

server 是虚拟主机配置,主要存放服务级别的配置,包括服务地址和端口、编码格式以及服务默认的根目录和主页等。部分特殊的配置各级上下文都可以拥有,比如 charest (编码格式) access_log (访问日志)等,因此你可以单独指定该服务的访问日志,如果没有则默认向上继承。

location

location 是请求级别的配置,它通过 url 正则匹配来指定对某个请求的处理方式,主要包括代理配置、缓存配置等。location 配置的语法规则主要为:

# location [修饰符] 匹配模式 { ... }
location [=|~|~*|^~] pattern { ... }

1)没有任何修饰符时表示路径前缀匹配,下边这个例子,匹配 http://www.jd.com/test 和 http://www.jd.com/test/may。

server {
  server_name www.jd.com;
  location /test { }
}

2)= 表示路径精确匹配,下边这个例子,只匹配 http://www.jd.com/test。

server {
  server_name www.jd.com;
  location = /test { }
}

3)~ 表示正则匹配时要区分大小写,下边这个例子,匹配 http://www.jd.com/test,但不匹配 http://www.jd.com/TEST。

server {
  server_name www.jd.com;
  location ~ ^/test$ { }
}

4)~* 表示正则匹配时不需要区分大小写,下边这个例子,既匹配 http://www.jd.com/test,也匹配 http://www.jd.com/TEST。

server {
  server_name www.jd.com;
  location ~* ^/test$ { }
}

5)^~ 表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找。

Nginx location 有自己的一套匹配优先级:

下边这个例子,http://www.jd.com/test/may 虽然命中了两个 location 规则,但是由于 ^~ 匹配优先级高于 ~* 匹配,所以将优先使用第二个 location。

server {
  server_name www.jd.com;
  location ~* ^/test/may$ { }
  location ^~ /test { }
}

Nginx 实用技巧

正向代理

客户端通过访问一个代理服务,由它将请求转发到目标服务,再接受目标服务的请求响应并最终返回给客户端,这就是一个代理的过程。“科学上网” 就是一种典型的正向代理,在这个过程中,Nginx 就充当了代理中介的角色。(不同客户端的请求代理到一个服务器)

修改 Nginx 的 location 配置,利用 proxy_pass 属性让主路径访问请求转发到目标服务 web1:

// ...
location / {
  proxy_redirect off;
  proxy_pass http://web1; ## 转发到web1
}
// ...

负载均衡

代理还包括反向代理,我们业务中最常提到的负载均衡,就是一种典型的反向代理。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,就需要用多台服务器构建集群服务了,此时多台服务器将以合理的方式分担负载,避免出现某台服务器负载高宕机而某台服务器闲置的情况。

nginx.conf 中,我们创建了一个 upstream 配置 web-app,web-app 配置了三个目标服务,因此我们的请求将经由 web-app 代理到目标服务。Nginx 自带的负载均衡策略有多种,包括默认的轮询方式、权重方式、依据 IP 分配的 ip_hash 方式以及最少连接的 least_conn 方式等,采取哪种策略需要根据不同的业务和并发场景而定,这里我们使用 least_conn 策略来处理请求的分发。


// ...
upstream web-app {
  least_conn;   # 最少连接选取活跃连接数与权重weight的比值最小者为下一个处理请求的server
  server web1 weight=10 max_fails=3 fail_timeout=30s;
  server web2 weight=10 max_fails=3 fail_timeout=30s;
  server web3 weight=10 max_fails=3 fail_timeout=30s;
}

server {
  listen       80;         # 监听端口
  server_name  localhost;  # 监听地址

  location / {
    proxy_redirect off;
    proxy_pass http://web-app; ## 转发到web-app
  }
}
// ...

Server-side Include

Server-side Include(简称 SSI)是一种简单的解释型服务端脚本语言,是指在页面被获取时,服务器端能够进行 SSI 指令解析,对现有 HTML 页面增加动态生成的内容。SSI 是早期 Web 实现模块化的一个重要手段,适用于多种运行环境,且解析效率比 JSP 高,目前仍然在一些大型网站中广泛应用。

在 HTML 中使用 SSI 的格式就像这样:

<!--#include virtual="/global/foot.html"-->

一行注释,通过服务端的 SSI 解析,会被置换成 /global/foot.html 的内容,virtual 可以是绝对路径,也可以是相对路径。

在 nginx.conf 中简单配置以下两个属性,开启 Nginx 的 SSI 支持,其中 ssi_silent_errors 表示处理 SSI 文件出错时需要输出错误提示:

location / {
  ssi on;
  ssi_silent_errors on; # 处理 SSI 文件出错时输出错误提示默认 off
  
  proxy_redirect off;
  proxy_pass http://web1; ## 转发到web1
}

GZIP 压缩

location / {
  # ...
  gzip on;
  gzip_min_length 1k; # 大于1K的文件才会压缩
  
  # ...
}

压缩后的请求响应头中多了 Content-Encoding: gzip。

防盗链

某些情况下我们不希望自己的资源文件被外部网站使用,比如有时候我会把 JD 图片服务上的图片链接直接复制到 GitHub 上使用,这个时候假如 JD 要禁用来自 GitHub 的图片访问,可以怎么做呢?很简单:

location ~* \.(gif|jpg|png|webp)$ {
   valid_referers none blocked server_names jd.com *.jd.com;
   if ($invalid_referer) {
    return 403;
   }
   return 200 "get image success\n";
}

我们利用 Nginx 自带的 valid_referers 指令,对所有图片请求做了一个 referer 校验,只有 jd.com 及其子域下的图片请求才能成功,其他的都走 403 禁止,变量 $invalid_referer 的值正是校验结果。

HTTPS

HTTPS 大家都比较熟悉了,它是在 HTTP 基础上引入 SSL 层来建立安全通道,通过对传输内容进行加密以及身份验证,避免数据在传输过程中被中间人劫持、篡改或盗用的一种技术。Chrome 从 62 版本开始将带有输入数据的 HTTP 站点和以隐身模式查看的所有 HTTP 站点自动标记为 “不安全” 站点,可见在网络安全规范普及下,HTTPS 化是未来 Web 网站的一大趋势。

Nginx 可以简单快速地搭建起 HTTPS 服务,需要依赖于 http_ssl_module 模块。nginx -V 能够列出 Nginx 的编译参数,查看是否已安装 http_ssl_module 模块。

搭建 HTTPS 服务需要生成密钥和自签 SSL 证书(测试用,正式的需要签署第三方可信任的 SSL 证书),我们需要利用到 openssl 库。新建 nginx/ssl_cert 目录:

1)生成密钥 .key

openssl genrsa -out nginx_quick.key 1024

2)生成证书签名请求文件 .csr

openssl req -new -key nginx_quick.key -out nginx_quick.csr

3)生成证书签名文件 .crt

openssl x509 -req -days 3650 -in nginx_quick.csr -signkey nginx_quick.key -out nginx_quick.crt

完成这三步后,我们也就生成了 HTTPS 所需的密钥和 SSL 证书,直接配置到 nginx.conf 中:

# ...
server {
  listen       443 ssl;    # 监听端口
  server_name  localhost;  # 监听地址

  ssl_certificate /etc/nginx/ssl_cert/nginx_quick.crt;
  ssl_certificate_key /etc/nginx/ssl_cert/nginx_quick.key;

  # ...
}

页面缓存

我们常说的页面缓存主要分为三类:客户端缓存、代理缓存、服务端缓存,这里重点讨论的是代理缓存。

当 Nginx 做代理时,假如接收的大多是一些响应数据不怎么变化的请求,比如静态资源请求,使用 Nginx 缓存将大幅度提升请求速度。Nginx 中的缓存是以文件系统上的分层数据存储的形式实现的,缓存键可配置,并且可以使用不同的特定于请求的参数来控制进入缓存的内容。

Nginx 利用 proxy_cache_path 和 proxy_cache 来开启内容缓存,前者用来设置缓存的路径和配置,后者用来启用缓存:

http {
  # ...
  proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m max_size=10g inactive=60m;

  server {
    # ...

    proxy_cache mycache;

    # ...
  }
}

上边我们设置了一个缓存 mycache,并在 server 中启用:

1)/data/nginx/cache 指定了本地缓存的根目录;

2)level 代表缓存目录结构是两层的,最多设置3层,数字代表命名长度,比如 1:2 就会生成诸如 /data/nginx/cache/w/0d 的目录,对于大量缓存场景,合理的分层缓存是必要的;

3)keys_zone 设置了一个共享内存区,10m 代表内存区的大小,该内存区用于存储缓存键和元数据,保证 Nginx 在不检索磁盘的情况下能够快速判断出缓存是否命中;

4)max_size 设置了缓存的上限,默认是不限制;

5)inactive 设置了缓存在未被访问时能够持续保留的最长时间,也就是失活时间。