5

本文是官网文档的入门学习笔记,官网链接:Beginner Guide

nginx入门

安装(centos7)

1) 配置yum源:vi /etc/yum.repos.d/nginx.repo
2) 按i进入vi工具的编辑模式,输入下面的yum配置:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/
gpgcheck=0
enabled=1

其中baseurl部分,需要替换实际的参数:
“OS” 换成 “rhel” 或 “centos”,
“OSRELEASE” 换成 “6” 或 “7”
由于我用的是centos7,所以baseurl=http://nginx.org/packages/centos/7/$basearch/

3) 按esc退出编辑模式,按:进入命令模式,输入wq,写入内容并退出vi工具。
4) 安装:yum install -y nginx

简介

nginx(读作engine x)是一个HTTP服务器,也可以用作反向代理服务器、邮件代理服务器。作者是Igor Sysoev。俄罗斯很多指明网站如Yandex、 Mail.Ru、 VK、Rambler都长期使用nginx。据Netcraft统计,截至2017年9月,有29.38%商业网站使用ngnix做服务器或做代理,比如有:Dropbox、Netflix、Wordpress.com、FastMail.FM

nginx有一个主进程和几个worker进程。主进程的作用是读取并执行配置,并维护worker进程。worker进程是实际处理请求的进程。
nginx采用事件驱动模型和基于系统的一些机制来高效分发请求给多个worker进程。worker进程的数量可以在配置文件中配置。

nginx的配置文件默认名称是nginx.conf,一般在以下这些目录中可以找到:

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

启动、停止、重新加载配置

可以直接运行nginx命令启动,nginx启动后,可以通过一下的语法来控制nginx:

nginx -s signal

上面的s代表signal,信号的意思

signal可以是以下的值:

  • stop — 快速地关闭
  • quit — 优雅地关闭
  • reload — 重新加载配置文件
  • reopen — 重新打开日志文件

例如,如果需要等待所有worker进程完成请求之后停止nginx,可以执行一下的命令:

nginx -s quit

假如您是使用userA帐号登录linux后启动nginx的,您应该同样使用userA帐号,而不是userB、userC

如果修改了配置文件,需要发送以下命令重新加载配置,否则配置不会生效:

nginx -s reload

当主进程收到重新加载配置的命令后,主进程会检查配置文件的语法并尝试应用新的配置。
如果成功了,主进程会启动一个新的worker进程,并发送消息给旧的worker进程,让旧的worker进程关闭。
如果不成功,主进程会回滚到旧的配置,并继续用旧的配置继续运行。
至于收到关闭命令的旧worker进程,会停止接收新的连接,处理完所有剩下的请求后,旧的worker进程就会结束。

另外,使用Unix系统提供的kill命令也可以向nginx进程发送关闭的信号(用进程id)。进程id默认是记录在/usr/local/nginx/logs/var/run目录下的nginx.pid文件中,知道了进程id之后(假如进程id是1628),就可以这样输入命令:

kill -s QUIT 1628

如果需要知道所有正在运行的nginx进程,可以使用ps命令:

ps -ax | grep nginx

配置文件的结构

nginx是由模块组成的,这些模块是通过在配置文件中声明的指令来控制的。指令有两种:简单指令(单条语句)和块指令(代码块)。
简单指令由指令名、参数组成,指令名和参数间用空格隔开,最后以分号(;)结束
块指令跟简单指令结构一样,但是区别就是块指令不以分号结束,而是用花括号( { 和 } )括起来
如果一个块指令可以在花括号内包含其它指令,那这个块指令叫context(例如:events, http, server, and location)。

在配置文件中,写在context以外的的指令,就是在main context中。比如下面的代码,eventshttp指令属于main context,http中有server,server中有location。

events{
  ...
}

http{
  server{
    location{
      ...
    }
  }
}

在配置文件中,井号#开头的就是注释。

通过vi /etc/nginx/nginx.conf打开配置文件,nginx配置文件内容如下:

user  nginx;
worker_processes  1; //<--简单指令

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {//<--块指令
    worker_connections  1024;
}


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;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

配置静态资源服务器

web服务器的一个重要功能是对外提供文件访问服务,如图片或静态html页面。接下来,我们将实现这样一个功能:
假设nginx所在的服务器有以下目录:

  • /data/www目录,用于存放html文件,请自行放一个index.html静态html文件进去
  • /data/images目录,用于存放的是图片,请自行放一些图片进去

我们需要设置nginx响应外部的请求,把这些目录下的文件提供对外访问。我们需要在配置文件的http块中设置一个server块,并在server块中设置两个location块。完整的代码如下:

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

默认情况下,nginx会监听80端口,因此无需在server块中配置端口80。

http下一般会有多个server配置,这些server块可以用端口名称来区分。
当nginx确定了采用哪个server来处理请求,nginx会拿到请求头中的URI信息,与location指令的参数来匹配。
如下图,就显示了请求头中的请求路径信息:
图片描述
图片描述

在下面这段代码中:

    location / {
        root /data/www;
    }

location是一条指令,/是指令的参数,location /的含义是:声明一个前缀,这个前缀会与请求头中的URI信息进行匹配(上面截图)。对于匹配的请求,URI路径会追加到root指令声明的参数后,组成服务器端文件的路径,即:/data/www`

再看一些例子来理解一下:

示例1:
location: /
root: /data/www
请求:http://127.0.0.1 (URI是"",匹配到location /)
服务器文件路径:root的参数 + URI = /data/wwww + "" = /data/www

示例2:
location: /
root: /data/www
请求:http://127.0.0.1/images/test1.jpg (URI是"/images/test1.jpg",匹配到location /)
服务器文件路径:root的参数 + URI = /data/wwww + "/images/test1.jpg" = /data/wwww/images/test1.jpg

示例3:
location: /images/
root: /data
请求:http://127.0.0.1/images/test1.jpg (URI是"/images/test1.jpg",匹配到location /images/)
服务器文件路径:root的参数 + URI = /data+ "/images/test1.jpg" = /data/images/test1.jpg

一定要看清楚上面2和3的区别!!服务器端文件路径是由root的参数和请求的URI拼出来的,而不是root的参数和location的参数,location的参数是用来匹配请求的

注意:如果有多个匹配的location,nginx会选前缀最长的那个。如下面这段代码:

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

当请求http://127.0.0.1/images/test1.jpg时,上面两个location都能匹配到URI:/images/test1.jpg。但是由于/images//长,所以nginx最终会匹配到location /images/

注意,这个配置:

    location /images/ {
        root /data;
    }

如果请求是 http://localhost/images/test1.jpg ,由于匹配到/images/,在服务器上的文件路径应该是 root的参数 + 请求的URI ,即:/data + /images/test1.jpg = /data/images/test1.jpg

加载新配置

如果你未启动nginx,启动后就可以应用新的配置了。如果nginx已经启动,需要执行以下命令让nginx加载新的配置:

nginx -s reload

如果nginx出现问题了,你可以在/usr/local/nginx/logs/var/log/nginx目录下找到access.logerror.log,看日志找原因。

完整配置示例:


user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


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;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
  
    server{
        location / {
            root /data/www;
        }
        location /images/ {
            root /data;
        }
    }

    include /etc/nginx/conf.d/*.conf;
}

配置代理服务器

nginx作为代理服务器的时候,它扮演的是一个中间角色(proxy)。负责接收客户端(client)的请求,代理请求到目标服务器(target),接收目标服务器的响应,最后把响应发送给客户端。其交互过程如下图:

                                    proxied
|--------|   request   |--------|   request   |--------|
|        |------------>|        |------------>|        |
| client |             |  proxy |             | target |
|        |<------------|        |<------------|        |
|--------|   response  |--------|   response  |--------|

例子:

需求:

假如浏览器请求http://localhost/,则把请求代理到http://localhost:8080/
假如浏览器请求http://localhost/test5.jpg,则不做代理,直接响应本机的/data/images/test5.jpg

实现:

# 省略其它代码...
http {
    # 省略其它代码...    
    #gzip  on;
  
    server{
        listen 8080;
        root /data/up1;
        
        location / {            
        }
    }

    server{
        location / {
            proxy_pass http://localhost:8080;
        }        
        location ~ \.(gif|jpg|png)$ {
            root /data/images;
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

代码解释:

代码段1
    server{
        listen 8080;
        root /data/up1;
        
        location / {            
        }
    }

代码段1的作用是声明一个server,监听8080端口(listen指令是用来监听的端口的,由于nginx默认是监听80端口,默认监听80端口则可以省略不写)。
root /data/up1一行声明把所有发送到8080端口的请求都用/data/up1目录下的内容来响应(请自行在/data/up1目录下创建测试用的index.html文件)。

请注意,root /data/up1是写在server块中,而不是location块中。
当我们配置了一个 location / { },location块中没有root指令,那这个location就会用server块下的root /data/up1的配置。
这个有点绕,但是这里是为了说明特殊情况。一般我们用这样就可以:

server{
    listen 8080;
   
    location / {
        root /data/up1;            
    }
}
代码段2
server{
    location / {
        proxy_pass http://localhost:8080;
    }        
    location ~ \.(gif|jpg|png)$ {
        root /data/images;
    }
}

代码段2声明了另一个server,监听80端口(不是代码段1中的8080端口了!)。
然后,映射了两种不同的请求路径:

  • 1) location /,如果匹配到这个路径的请求,那将会将请求代理到8080端口。

比如:

请求:http://localhost/(request-A),匹配到location /,就会再发送一个请求(request-B):http://localhost:8080/
然后代码段1配置的location /就会匹配到该请求(request-B),就会响应/data/up1/index.html

  • 2) location ~ \.(gif|jpg|png)$,用于匹配.gif、.jpg、.png后缀的图片请求。

比如:

请求http://localhost/test5.jpg,在两个location中会匹配到第二个(location ~ \.(gif|jpg|png)$),因为第二个location的前缀比第一个location的前缀长。
因此请求不会代理到http://localhost:8080,而是直接响应配置的/data/images目录下的test5.jpg文件(请自行添加测试图片文件)

另外,还需要注意:location ~ \.(gif|jpg|png)$用了正则表达式来匹配请求,location指令使用正则表达式,必须跟着一个波浪~符号做正则表达式的开头。

配置好之后,记得重新加载配置:nginx -s reload

文字看不懂就看图吧

当请求http://localhost/是,发生的代理过程如下:

|---------| http://localhost/      |------------------------------------------------|   
|   A     |----------------------->|          B                                     |----B同时是proxy和target
| client  |                        | match server at port 80 `location /`           |    
|         |                        |            ⬇                                   |
|         |                        |            ⬇proxy to `http://localhost:8080`   |             
|         |                        |            ⬇                                   |             
|         |                        | match server at port 8080 `location /`         |    
|         |                        |            ⬇                                   |
|         |                        |            ⬇serve default index.html file      |             
|         |                        |            ⬇                                   |             
|         |<-----------------------|      /data/up1/index.html                      |
|---------| /data/up1/index.html   |------------------------------------------------|

当请求http://localhost/test5.jpg是,没有发生的代理,其响应过程如下:

|---------| http://localhost/test5.jpg |--------------------------------------------------------|   
|   A     |--------------------------->|          B                                             |
| client  |                            | match server at port 80 `location ~ \.(gif|jpg|png)$`  |    
|         |                            |            ⬇                                           |
|         |                            |            ⬇serve match image file                     |             
|         |                            |            ⬇                                           |             
|         |<---------------------------|      /data/images/test5.jpg                            |
|---------| /data/images/test5.jpg     |--------------------------------------------------------|

煲煲菜
1.5k 声望155 粉丝

世上本没有bug,坑的人多了,也便成了bug