程序员工具工具使用

Nginx学习笔记

2018-12-20  本文已影响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之后,配置文件放置的位置可能不一样,因此如果一个地方找不到,不妨试试其他目录。以下是几个比较常见的地方:

默认静态资源文件目录:

通过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取值和功能如下:

配置文件

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

Nginx包含以下顶层的context

位于顶层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;
    ...
}

需要注意一下几点:

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

Location匹配

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

location分为两

location /some/path/ {
    ...
}
location ~ \.html? {
    ...
}

匹配规则如下:

神奇的斜杠/

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有以下方式分发请求:

每种方式都有其自定义的配置,更多详情请参考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";

调优

上一篇 下一篇

猜你喜欢

热点阅读