Nginx

Published: by Creative Commons Licence

  • Tags:

概念

nginx(engine x)是一个HTTP和反向代理服务器,一个邮件代理服务器,一个通用TCP/UDP代理服务器。nginx一开始由Igor Sysoev所编写,在世界各处都有广泛应用。

实践

安装

第一步,增加Centos7 EPEL仓库:

yum install epel-release

第二步,安装Nginx:

yum install nginx

第三步,启动Nginx:

systemctl start nginx

第四步,测试nginx正常启动:

wget localhost:80

配置ssl

上面步骤,我们仅能访问http://host:80,但是现在大部分浏览器都会将其标记为不安全。

我们需要先生成自己的私钥以及对应的证书crt文件。之后编辑/etc/nginx/nginx.conf文件,增加下面内容:

	server {
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        ssl_certificate "/root/.ssh/server.crt";
        ssl_certificate_key "/root/.ssh/server.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
	}

现在你就可以访问https://host:443了。(注意证书和私钥要设置为只读)

路径匹配

nginx路径匹配的一般语法为

location [ = | ~ | ~* | ^~ ] uri {...}

location表示这是一段映射关系,后面可以跟可选的修饰符,之后是uri,括号内撰写对应的操作。

nginx支持四种修饰符

  • = 表示只有请求地址完全匹配uri时才会被接受
  • ~ 表示uri为区分大小写的正则表达式,仅匹配正则表达式的地址才会被接受
  • ~* 表示uri为不区分大小写的正则表达式,仅匹配正则表达式的地址才会被接受
  • ^~ 表示只有uri为请求地址的前缀时,才会接受请求

由于可能一个请求会同时匹配多个location,而nginx会选取优先级最高的location来处理请求,下面列出的优先级从高到低:

  1. 匹配修饰符=修饰的location
  2. 从上到下匹配正则表达式(用~~*修饰的location)。
  3. 匹配uri长度最长的用^~修饰的location。

nginx还有一种路径的写法。

location / {
    try_files $uri $uri/ @custom
}
location @custom {...}

我们为下面的location赋予了一个别名custom,并允许在nginx.conf内部引用这个别名用作转发。

静态资源

nginx可以用于处理静态资源的下载。

location /a/ {
    root /data/;
}

所有形如/a/file的请求都会直接下载/data/a/file

还有一种写法是使用alias。

location /b/ {
    alias /data/;
}

此时所有形如/b/file的请求会直接下载/data/file

root和alias的区别在于root是本地路径拼接完整的请求路径,而alias是本地路径拼接多余的请求路径。

反向代理

反向代理主要用于负载均衡,nginx可以从多个站点无缝获得数据。

代理配置

在nginx配置文件中增加如下内容:

location /some/path/ {
    proxy_pass http://www.example.com/lnik/;
}

这样假如你访问host/some/path/index.html时,实际上nginx会把你的请求转发到http://www.example.com/lnik/index.html。这里的请求是可以跨协议的,比如nginx接受的是https协议,但是转发的时候却是以http协议进行转发。还有需要注意的是尾部的斜杆是有必要的。

nginx支持以其他协议进行转发:

协议 描述
proxy_pass 转发给http或https
fastcgi_pass 转发给FastCGI服务器
uwsgi_pass 转发给uwsgi服务器
scgi_pass 转发给SCGI服务器
memcached_pass 转发给memcached服务器

携带Headers

默认情况下,Nginx会设置host和connection两个头部,并且会剔除值为空的头部。Host头部会被赋值为$proxy_host,Connection会被赋值为close

你可以利用proxy_set_header来要求nginx在转发的时候携带指定头部,其用法类似于之前提到的proxy_pass。

location /some/path/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://localhost:8000;
}

如果你想删除头部,则只要将其设置为空字符串即可,比如:

proxy_set_header Host ""

设置Buffers

默认情况下,nginx会保存被代理服务器的响应内容在缓冲区中,直到从被代理服务器上获得了完整的响应内容,才会发送给客户端。缓冲区有助于在客户端较慢的时候优化性能表现,因为发送给客户端和从被代理服务器获取响应是同步的。

并且保存在缓冲区中的内容将会在客户端需要下载时重复使用。

用于开启和禁用缓冲的指令为proxy_buffering。默认它的值是on

proxy_buffers指令用于控制为每一个请求分配的缓冲区的大小和数量。响应的第一部分被保存在一个分离的缓冲区中,可以通过proxy_buffer_size指令设置其大小。这部分往往包含一些相对较小的响应头,因此可以设置得比其他响应内容得缓冲区小些。

location /some/path/ {
    proxy_buffers 16 4k;
    proxy_buffer_size 2k;
    proxy_pass http://localhost:8000;
}

一旦关闭了缓冲功能,来自被代理服务器得响应内容会同步地发送给客户端。这对于对交互式客户端是有必要得,提早返回数据有助于客户端可以尽快处理响应。

location /some/path/ {
    proxy_buffering off;
    proxy_pass http://localhost:8000;
}

负载均衡

多应用实例之间的负载均衡是一种提高资源使用率的常用技术,可以最大化吞吐,减少延迟,并且确保能容错。

Nginx可以作为一个非常有效的负载均衡服务,将流量分布到数个应用服务器,以提高性能,可伸缩性,以及服务的可靠性。

Nginx支持三种负载的均衡策略:

  • round-robin:以取余数的方式分配服务,比如你有3台服务器,那么第i个请求分配给服务i%3。(默认)
  • least-connected:将请求分配给活跃连接数最少的服务。
  • ip-hash:对ip进行哈希,之后取余,这样就可以确保来自同一个ip的请求会分配给同一台服务器来处理。
upstream myapp1 {
    least
}

上面的配置将要求nginx将所有http请求按最少连接数策略转发给三台服务器。

在反向代理的情况下HTTP,HTTPS,FastCGI,uwsgi,SCGI,memcached,gRPC都支持负载均衡。

如果你的三台服务器的性能并不平衡,比如一台特别强劲,而另外两台相对羸弱。我们可以通过为服务配置weight属性来表示其权值。weight=k表示该服务相当于k台服务,默认weight=1

upstream myapp1 {
	server srv1.example.com weight=3;
	server srv2.example.com;
	server srv3.example.com;
}

上面的内容等价于:

upstream myapp1 {
	server srv1.example.com;
	server srv1.example.com
	server srv1.example.com
	server srv2.example.com;
	server srv3.example.com;
}

附录

参考