Nginx学习笔记

作者: 无知者云 | 来源:发表于2018-12-20 11:03 被阅读5次

首先提醒一下,国内绝大多数程序员都把Nginx的读音搞错了(甚至包括很多国外的程序员),Nginx官方推荐的正确的读音应该是:Engine-X,而不是En-jingks.

Nginx分为主进程(master process)和工作进程(worker process),每个进程中只有一个线程(也可以配置线程池),通过IO多路复用(底层使用epoll/kqueue等技术)和事件循环达到高并发(这点跟Node.js比较相似)。主进程负责总体协调工作,比如在配置文件更新后重新应用配置、协调哪个worker process应该退役等等。工作进程的个数一般设置为CPU的个数。

还有个Nginx Plus,它是Nginx背后的商业公司,提供比Nginx开源版更多功能的Nginx软件,以及一些有关Nginx的技术支持服务,Nginx和Nginx Plus的对比在这里

安装Nginx

通过Yum安装

首先安装epel-release源:

sudo yum install epel-release

然后安装Nginx:

sudo yum install nginx

最后启动Nginx:

sudo systemctl start nginx

查看安装之后的文件路径:

 rpm -ql nginx

在笔者的CentOS/7虚拟机上,Nginx的配置文件位于/etc/nginx/nginx.conf,默认静态资源目录为/usr/share/nginx/html/

对于不同的操作系统或安装方式,在安装完Nginx之后,配置文件放置的位置可能不一样,因此如果一个地方找不到,不妨试试其他目录。以下是几个比较常见的地方:

  • /etc/nginx/nginx.conf
  • /usr/local/nginx/conf/nginx.conf
  • /usr/local/etc/nginx/nginx.conf

默认静态资源文件目录:

  • /usr/share/nginx/html

通过Docker安装

Docker官网提供了Nginx镜像,运行Docker:

$ sudo docker run -p 8081:80  -d nginx

如果要对外提供静态资源文件:

$ sudo docker run -p 8081:80 -v /some/content:/usr/share/nginx/html:ro -d nginx

此时,将本机静态资源文件夹/some/content映射成了nginx的默认静态资源文件夹,然后将Docker的80端口映射到了宿主机的8081端口,此时访问http://localhost:8081/便可以访问宿主机中/some/content/下的静态文件了。

当然,要指定静态资源文件,更好的方式是通过Dockerfile将资源拷贝到Docker容器中,通常前端项目便可以通过这种方式构建Docker镜像:

FROM nginx
COPY /some/content /usr/share/nginx/html

另外,如果要定制化Nginx的配置,也可以通过Dockerfile:

FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf

以上Dockerfile将宿主机的nginx.conf文件拷贝到Docker容器中。

更多安装方式请参考Nginx官网

Nginx命令行

可以通过发信号的方式对Nginx进行控制,发信号有两种方式,一种是通过nginx命令,一种是通过kill,详细请参考官网,这里列出通过该nginx控制Nginx的功能,命令格式:

nginx -s <SIGNAL>

其中,SIGNAL取值和功能如下:

  • quit – 安全地关闭
  • reload – 重新加载配置文件
  • reopen – 重新打开日志文件
  • stop – 直接关闭

配置文件

Nginx的主配置文件nginx.conf通过上下文context组织结构,context中可以包含配置项directive,而directive又可以反过来包含context

Nginx包含以下顶层的context

  • events - 通用的与连接相关的配置
  • http - http流量相关配置
  • mail - 邮件流量相关配置
  • stream - TCP/UDP流量相关配置

位于顶层context之外的directive也被称为在main context中。

Virtual Server(Server Block)

在每个流量配置context中(http,mailstream),都可以通过server配置多个虚拟服务器(Virtual Server),server下的配置基于context的不同而不同。比如对于httpserver下可以配置多个location来处理不同的URL,而对于mailstreamserver中则可以配置端口或者Socket。

示例配置文件

user nobody; # a directive in the 'main' context

events {
    # configuration of connection processing
}

http {
    # Configuration specific to HTTP and affecting all virtual servers  

    server {
        # configuration of HTTP virtual server 1       
        location /one {
            # configuration for processing URIs starting with '/one'
        }
        location /two {
            # configuration for processing URIs starting with '/two'
        }
    } 
    
    server {
        # configuration of HTTP virtual server 2
    }
}

stream {
    # Configuration specific to TCP/UDP and affecting all virtual servers
    server {
        # configuration of TCP virtual server 1 
    }
}

配置继承

有些directive可以位于多种context中, 此时便形成了一种继承关系,即子context将继承父context中的directive配置,当然子context也可以通过显式配置的方式覆盖继承自父context的配置。

另外,主配置文件nginx.conf可以通过include来包含其他配置文件,一个常用的实践是nginx.conf只负责配置nginx本身,而将server相关的配置放到各自的配置文件中,然后在nginx.conf文件中include这些文件。

虚拟服务器选择

Nginx处理HTTP请求原理:先根据server中的listenserver_name等判断该请求应该由哪个server来处理,然后通过匹配server下的location来决定应该由哪个location来处理,服务器配置示例如下:

server {
    listen      80;
    server_name example.org www.example.org;
    ...
}

需要注意一下几点:

  • 如果没有listen,那么Nginx默认监听所有网卡的80端口(以root启动nginx),或者默认监听所有网卡的8000端口(非root启动)
  • server_name的前后可以使用通配符*来匹配任意字符,但是*不能出现在域名中间
  • 可以使用~server_name进行正则匹配。

Nginx通过将server_name与请求中的Host头信息进行匹配,通过以下顺序,第一个满足匹配条件的胜出:

  • 精确匹配
  • *开头的最长server_name
  • *结尾的最长server_name
  • 第一个匹配的正则表达式
  • 如果以上都没有匹配到,则匹配标有default_server的server
  • 如果以上都没有匹配到,则选择第一个server

Location匹配

在Nginx决定了由哪个server处理请求之后,将进一步将请求URL与该server中的各个location匹配,以最终决定由哪个location来处理该请求。

location分为两

  • 前缀字符串,示例:
location /some/path/ {
    ...
}
  • 正则表达式,示例:
location ~ \.html? {
    ...
}

匹配规则如下:

  • 先将请求URL与所有location进行前缀匹配
  • 如果某个前缀命中的的location=修饰符,则选择之并停止匹配
  • 如果最长前缀的location^~修饰符,则停止匹配,并选择之
  • 保存最长的前缀匹配location
  • 进行正则表达式匹配,根据location出现的顺序进行匹配
  • 找到第一个匹配成功的正则表达式location,选择之,停止匹配(请注意,只要有正则表达式匹配上,那么先前保存的最长前缀匹配将失效)
  • 如果没有匹配上的正则表达式,那么匹配先前保存的最长前缀匹配

神奇的斜杠/

todo

服务静态文件

先将静态资源拷贝到/data/www目录下,然后在http中配置:

server {
    location / {
        root /data/www;
    }
}

此时访问http://localhost/,如果/data/www下有index.html文件,那么将直接返回index.html文件内容。

另外,还可以通过index直接指定默认的index文件:

location / {
    root /data/www;
    index index.html index.php;
}

当前很多单页面应用采用了HTML5的History API,在使用Nginx时,由于所有的URL都将被Nginx处理,但是单页面有只有一个页面,也即所有URL都将路由到同一个页面,比如Index.html,再有浏览器根据URL做客户端路由。此时可以通过try_files对Nginx进行配置:

server {
  ...
  location / {
    try_files $uri /index.html;
  }
}

在上例中,Nginx会先尝试访问原URL资源,如果资源不存在则返回index.html。

try_files的工作机制是会依次访问参数中的资源直到正常返回,需要注意,最后的参数资源必须存在,不然nginx将报错。更多详情请参考Nginx官网这里

负载均衡

首先在http中定义多台机器组,组名为backend:

    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }

然后就可以在server中引用backend了,完整例子:

http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }
    
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}

配置负载均衡方式

upstream中可以配置以哪种方式分发请求:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

Nginx有以下方式分发请求:

  • Round Robin(默认) - 依次轮训
  • Least Connection - 连接最少的节点胜
  • IP Hash - 通过IP地址的hash值进行路由,可以保证来源相同的请求总是路由到同一个节点,进而支持sticky session
  • 通用Hash - 通过自定义算法计算Hash值来决定路由

每种方式都有其自定义的配置,更多详情请参考Nginx官网

Health Check

如果upstream服务器返回不正常,那么Nginx将在一段时间内不再向该服务代理请求:

upstream backend {
    server backend1.example.com;
    server backend2.example.com max_fails=3 fail_timeout=30s;
    server backend3.example.com max_fails=2;
}

上例中,对于backend2.example.com,如果超过了3(max_fails)次返回失败,那么Nginx将在30秒内(fail_timeout)不再路由到该节点,30秒后再次启用该节点。

默认情况下,max_fails=1,fail_timeout=10s。

代理多个应用

配置HTTPS

最佳实践

设置worker_processes

通常的做法是将worker_processes设置成与CPU的数量相同,也可以设置为auto让Nginx自动为你决定。

worker_processes auto; 

停用access_log

启动access_log后Nginx记录每一次请求,这将增加磁盘空间并给Nginx带来额外负担,如果你确定不需要access_log,可以:

access_log off;

去掉Nginx版本号

server_tokens off; #为了安全

基于server配置gzip

配置gzip是把双刃剑,不配吧数据量太大,配了吧有安全风险。因此推荐的实践是只针对静态资源文件使用gzip,并且基于server单独配置:

server {
    listen         80;
    server_name    example1.com;
    gzip           on;
    gzip_types text/html text/css image/jpg image/jpeg image/png image/svg;
}

server {
    listen         443 ssl;
    server_name    example2.com;
    gzip           off;
}

注意add_header

add_header用于向最终返回给客户端的response中添加HTTP Header信息,需要注意的是add_header并不享受Nginx的继承机制,意味着如果子context中有add_header,那么它将覆盖所有的父context中的add_header配置。比如,在http中配置了3个add_header,然后在server中配置了1个add_header,那么server中的add_header会将http中的所有3个add_header给覆盖掉。

防止加入iframe

某些钓鱼网站会通过iframe的方式将你的网站加入钓鱼网站,此时我们可以通过Nginx配置声明自己的网站不应该被放入iframe中,在server中配置:

add_header X-Frame-Options DENY;

启用XSS过滤器

以下配置中,Nginx会通知浏览器启用XSS过滤器,虽然对于多数浏览器来说这个是默认设置:

add_header X-XSS-Protection "1; mode=block";

调优

  • Nginx中,当使用sendfile函数时,TCP_NOPUSH才起作用,因为在sendfile时,Nginx会要求发送某些信息来预先解释数据,这些信息其实就是报头内容,典型情况下报头很小,而且套接字上设置了TCP_NODELAY。有报头的包将被立即传输,在某些情况下(取决于内部的包计数器),因为这个包成功地被对方收到后需要请求对方确认。这样,大量数据的传输就会被推迟而且产生了不必要的网络流量交换。而通过设置TCP_NOPUSH=on,表示将所有HTTP的header一次性发出去,参考这里
  • Nginx的TCP_NODELAY只有在配置长连接时才起作用,因为长连接可能引起小包的阻塞,配置TCP_NODELAY可以避免该阻塞,参考这里
  • Use the tcp_nopush directive together with the sendfile on;directive. This enables NGINX to send HTTP response headers in one packet right after the chunk of data has been obtained by sendfile().
  • 在 nginx 中,tcp_nopush 配置和 tcp_nodelay “互斥”。
  • 默认情况下,nginx已经自动开启了对client连接的keep alive支持(同时client发送的HTTP请求要求keep alive)。
  • 默认nginx访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,后端执行完毕后主动关闭该链接)。
  • location值的最后含有斜杠,比如/hello/,然后该location有设置的proxy_pass,那么当客户端访问不带最后斜杠的/hello时,Nginx将301重定向到带有斜杠的/hello/参考这里

相关文章

  • Nginx学习笔记-基本操作

    title: Nginx学习笔记-基本操作date: 2018-07-08tags: [nginx]categor...

  • Nginx学习笔记-项目部署

    title: Nginx学习笔记-项目部署date: 2018-08-18tags: [nginx]categor...

  • Nginx学习笔记

    Nginx学习笔记 目录 yum安装nginx 本地编译安装nginx niginx配置文件说明 1.yum安装n...

  • Nginx安装使用教程

    一、Nginx代理转发到应用服务1、 Nginx入门学习笔记Windows系统:1、到nginx官网下载,解压即可...

  • Nginx

    Nginx学习笔记 1、Nginx初识 Nginx 是一个高性能的Http和反向代理服务器。也是一个IMAP/PO...

  • Nginx学习笔记

    1.什么是负载均衡?通过某种负载分担技术,将外部发送来的请求按照某种策略分配到服务器集合的某一台服务器上,而接收到...

  • nginx学习笔记

    一、常见服务器 Apache \ IIS \ Tomcat \ Lighttpd \ Nginx 二、nginx....

  • Nginx学习笔记

    基于《实战Nginx:取代Apache的高性能Web服务器》 2010年版本 第一章 Nginx简介 1.Ngin...

  • Nginx学习笔记

    Nginx在运行时有一个主进程和多个worker进程,主进程负责总体管理等工作,比如重新加载配置文件以及管理wor...

  • Nginx学习笔记

    nginx的启动参数 例子: 检查配置文件是否正确,只做语法检查,并不进行测试. nginx -t -c 启动服务...

网友评论

    本文标题:Nginx学习笔记

    本文链接:https://www.haomeiwen.com/subject/znkkhqtx.html