nginx作为web服务以及nginx.conf详解

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
.cn 域名,1个 12个月
应用型负载均衡 ALB,每月750个小时 15LCU
简介: nginx作为web服务以及nginx.conf详解

1.nginx简介
nginx是一个优秀的web服务程序、反向代理程序。它采用非阻塞异步的套接字,使用epoll方式实现事件驱动,同时采用一个master+N个worker进程(默认)的方式处理请求,这种架构使得它在并发的处理能力上极其出色,可以比较轻松地解决C10K问题。

2.nginx处理请求的过程简单说明
master进程用于管理worker进程,例如接收外界信号、向worker进程发送信号、销毁worker进程、启动worker进程等等。

nginx之所以性能良好,完全是由它的架构决定的。每个worker进程是业务处理进程,负责监听套接字、处理请求、响应请求、代理请求至后端服务器等。

作为web server处理静态资源时每个worker进程的大致流程:

(1).监听套接字。
(2).与客户端建立连接。
(3).处理监听到的连接请求(加载静态文件)。
(4).响应数据。
(5).断开连接。

这几个过程是每个web server都具备的能力,但对于nginx来说,由于它的异步非阻塞,每个过程都不会阻塞(有些小过程必须阻塞的时候还是会阻塞),使得并发处理能力很好。

从监听套接字开始说。每个worker进程都是平等的,它们都可以去监听套接字,正常情况下不可避免地会造成争抢和"惊群问题",而nginx采用"争抢"accept互斥锁的方式,只有持有accept互斥锁的worker进程才有资格将连接请求接到自己的队列中并完成TCP连接的建立。但每个进程是相互独立而平等的,谁有资格去"争抢"互斥锁且有更大几率争抢成功?只要worker进程当前建立的连接数小于worker_connections指令指定的值(实际上源码中设置的是该值的7/8),就允许争抢互斥锁,因为连接数超过了该值的7/8表示已经非常繁忙。除了繁忙程度限制资格,还有epoll_wait的timeout的指标,等待越久的worker进程争抢能力越强。总之,在某一时刻,一定只有一个worker进程监听并accept新的连接请求。

当已经监听到连接请求时,worker进程与它进行三次握手,并最终accpet到自己的内存池中,并和客户端交互数据,处理客户端发送的http请求并响应数据给客户端。但是,nginx的高效就在于它的异步非阻塞,无论是在TCP连接进入ESTABLISHED之前,还是等待客户端发送请求,亦或者是等待加载本地静态资源的I/O,以及响应数据给客户端的任意一个过程中,nginx都是非阻塞的,在任意等待发生时都可以去处理其它事情。当等待的某个资源已经准备成功时将产生事件通知worker进程,worker进程可随后去处理。在此过程中,由于worker进程绑定在一个CPU核心上(推荐如此做),所有的连接都放在内存池中,这使得上下文切换时是极其轻量的,极大地减轻了CPU消耗。从理论上来说,当每个worker绑定了一个CPU核心时,它的并发处理能力主要依赖于内存的大小。

实际上apache httpd的event MPM也是异步非阻塞的,也可以采用epoll,但它采用的是多线程方式,虽然异步,但它的异步似乎不体现在并发能力上,而仅仅只是一些具有特殊状态的连接(如长连接)的异步处理,在处理过程中cpu还是不断地需要在各线程之间大量切换,并发能力并不比worker MPM强多少,相比nginx更是远远不如。

3.nginx命令
[root@xuexi nginx]# nginx -h
nginx version: nginx/1.12.0
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
-?,-h : this help
-v : 输出版本号
-V : 输出版本号以及编译选项
-t : 检查配置文件的语法
-T : 检查配置文件的语法并输出配置的内容
-q : 静默模式,不输出任何信息
-s signal : 向主进程发送信号:stop, quit, reopen, reload
-p prefix : 设置nginx的basedir(默认为编译时的prefix)
-c filename : 指定配置文件
-g directives : 提前设置全局指令
-V选项输出编译选项。

[root@xuexi nginx]# nginx -V
nginx version: nginx/1.12.0
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx-1.12.0 --pid-path=/var/run/nginx/nginx.pid --lock-path=/var/lock/subsys/nginx.lock --user=nginx --group=nginx --with-http_ssl_module --with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre
(1).使用默认配置文件直接启动nginx和指定配置文件启动nginx

nginx -c /usr/local/nginx/conf/nginx.conf
(2).运行时重载配置文件。当nginx主进程接收到重载配置文件的命令后,它会先检查新配置文件语法,然后载入该配置文件到内存中并解析。然后,主进程fork一系列新的worker进程,并发送QUIT信号给旧的worker进程(graceful stop)。旧的工作进程接收到QUIT信号后,会停止接受新的连接请求,并继续处理旧的连接直到请求处理完成后才退出。

nginx -s reload
(3).运行时快速关闭nginx。

nginx -s stop
(4).运行时优雅关闭nginx。所有的工作进程会停止接受新的连接,并继续服务旧的连接请求直到所有的请求完成后才退出。

nginx -s quit
(5).运行时重新打开日志文件。

ngnix -s reopen

4.nginx模块及http功能速览
Nginx的代码由一个核心和一系列的模块组成。

核心(core functionality)主要用于提供全局应用的基本功能,创建必要的运行时环境及确保不同模块之间平滑地进行交互等,对应于配置文件的main段和event段。核心涉及的指令官方文档:http://nginx.org/en/docs/ngx_core_module.html。

还有很多功能都通过模块实现,nginx是高度模块化程序。如web相关的功能模块有"ngxhttp_module",和mail相关的功能模块有"ngxmail_module",和tcp代理、负载均衡相关的功能模块有"ngxstream*_module",这些类别的模块中又分为很多类别的模块,如http类别的模块中有基本核心模块、事件类模块、缓存类模块、SSL相关模块、负载均衡类模块upstream等等。

以下是http功能模块类中常见的模块。

http类模块名 模块功能说明
ngx_http_core_module http核心模块,对应配置文件中的http段,包含很多指令,如location指令
ngx_http_access_module 访问控制模块,控制网站用户对nginx的访问,对应于配置文件中的allow和deny等指令
ngx_http_auth_basic_module 通过用户名和密码认证的访问控制,如访问站点时需要数据用户名和密码,指令包括auth_basic和auth_basic_user_file
ngx_http_charset_module 设置网页显示字符集。指令之一为charset,如charset utf-8
ngx_http_fastcgi_module fastcgi模块,和动态应用相关。该模块下有非常多的子模块。
ngx_http_flv_module 支持flv视频流的模块,如边下边播
ngx_http_mp4_module 同flv模块
ngx_http_gzip_module 压缩模块,用来压缩nginx返回的响应报文。一般只压缩纯文本内容,因为压缩比例非常大,而图片等不会去压缩
ngx_http_image_filter_module 和图片裁剪、缩略图相关模块,需要安装gd-devel才能编译该模块
ngx_http_index_module 定义将要被作为默认主页的文件,对应指令为index。"index index.html,index.php"
ngx_http_autoindex_module 当index指令指定的主页文件不存在时,交给autoindex指令,将自动列出目录中的文件autoindex {on/off}
ngx_http_log_module 和访问日志相关的模块,指令包括log_format和access_log
ngx_http_memcached_module 和memcached相关的模块,用于从memcached服务器中获取相应响应数据
ngx_http_proxy_module 和代理相关,允许传送请求到其它服务器
ngx_http_realip_module 当nginx在反向代理的后端提供服务时,获取到真正的客户端地址,否则获取的是反向代理的IP地址
ngx_http_referer_module 实现防盗链功能的模块
ngx_http_rewrite_module 和URL地址重写相关的模块,需要安装pcre-devel才能编译安装该模块
ngx_http_scgi_module simple cgi,是cgi的替代品,和fastcgi类似,但更简单
ngx_http_ssl_module 提供ssl功能的模块,即实现HTTPS
ngx_http_stub_status_module 获取nginx运行状态信息
ngx_http_upstream 和负载均衡相关模块
这些模块共同组成了nginx的http功能。

5.nginx配置文件简单说明
nginx的配置文件有很多个,如下。其中主配置文件为nginx.conf,其他配置文件在需要的时候使用include指令将其包含到主配置文件中。

[root@xuexi ~]# ls /usr/local/nginx/conf/
fastcgi.conf fastcgi_params koi-utf mime.types nginx.conf scgi_params uwsgi_params win-utf
fastcgi.conf.default fastcgi_params.default koi-win mime.types.default nginx.conf.default scgi_params.default uwsgi_params.default
其中".default"后缀的是对应前缀配置文件的备份配置文件,".params"是对应前缀的参数文件。如fastcgi.conf是和fastcgi相关参数的配置文件,fastcgi.params是fastcgi的参数文件,fastcgi.conf.default是fastcgi.conf的备份文件。

关于主配置文件nginx.conf,由于Nginx高度模块化,所以它是分段配置的,核心模块为core,对应配置文件中的Main和Events段。此外还有其他一些模块。配置文件中每一个指令必须以分号";"结束,否则语法错误。

5.1 main和events段
Main用于配置错误日志、进程及权限等相关的参数,Events用于配置IO模型,如epoll、kqueue、select或poll等,它们是必备模块。如下配置:

user nobody; # worker进程身份,默认使用编译时指定值.语法为"user user_name [group_name]"

worker_processes 4; # worker进程数量,该指令值依赖因素较多,例如是否CPU密集型、是否IO密集型。

                  # 在初始时设置为cpu的总核数是一个不错的选择。

error_log logs/error.log; # 错误日志文件,禁用错误日志"error_log /dev/null LEVEL;"

error_log logs/error.log notice; # 级别:debug|info|notice|warn|error|crit|alert|emerg,默认为error

error_log logs/error.log info;

pid logs/nginx.pid;

lock_file logs/nginx.lock;

events {
worker_connections 1024; # 每个worker进程的最大连接数
multi_accept on; # 是否一次性将监听到的连接全接收进来,默认为off,关闭时一次接收一条连接
accept_mutex on # 默认为on,开启时表示以串行方式接入新连接,否则将通报给所有worker。

                            # 这可能会浪费资源并产生不可预计的后果,例如惊群问题

}
如果某个文件采用了相对路径,则其相对的基准为basedir。例如编译时--prefix指定为/usr/local/nginx,则指定pid为logs/nginx.pid时,其实际路径为/usr/local/nginx/logs/nginx.pid。

worker_processes的值和work_connections的值决定了最大并发数量。例如上面的配置中,每个worker进程最大允许1024个连接,配置了4个worker进程,所以并发数量为10244=4096。但在反向代理场景中计算方法不同,因为nginx既要维持和客户端的连接,又要维持和后端服务器的连接,因此处理一次连接要占用2个连接,所以最大并发数计算方式为:worker_processesworker_connections/2。此外还需注意,除了和客户端的连接、与后端服务器的连接,nginx可能还会打开其他的连接,这些都会占用文件描述符,从而影响并发数量的计算。最后还需注意,最大并发数量还受"允许打开的最大文件描述符数量"限制,可以使用"worker_rlimit_nofile"指令修改或直接修改操作系统的对应内核参数。

可以在main段使用worker_cpu_affinity指令绑定CPU核心。nginx通过位数识别CPU核心以及核心数,指定位数上占位符为1表示使用该核心,占位符为0表示不使用该核心。例如2核cpu的位数分别为01和10,4核的位数分别为1000,0100,0010以及0001,同理8核和16核。在结合worker_processes指令一起使用时,要注意worker进程和核心的对应方式,例如:

每个worker分别对应cpu0/cpu1/cpu2/cpu3

worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;

有4核心,但只有两worker,第一个worker对应cpu0/cpu2,第二个worker对应cpu1/cpu3

worker_processes 2;
worker_cpu_affinity 0101 1010;
在events段,可以使用"use"指令可以指定使用哪种I/O模型,Linux上默认是epoll,通常可以不用手动去设置,因为nginx默认会采用最佳配置。

以下是main段和events段的配置示例,大多数采用的默认值,需要修改的大致就是worker数量、每个worker最大连接数以及进程绑定cpu。

worker_processes 4;
events {
worker_connections 1024;
}

5.2 http段

5.2.1 配置文件概览
http段是由http相关模块支持的。以下是默认配置项。注意,http根段下使用相对路径是相对conf目录的,如"include extra/.conf"表示的是conf/extra/.conf;非根段内的相对路径如server段内使用相对路径是相对于的安装目录的,例如nginx安装在/usr/local/nginx下,当location中的root设置为html时,它表示的路径是/usr/local/nginx/html/。

http {
include mime.types; # nginx支持的媒体文件类型。相对路径为同目录conf下的其他文件
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  logs/access.log  main;

sendfile        on;   # 启用sendfile传输模式,此模式是"零拷贝"
#tcp_nopush     on;   # 只在sendfile on时有效。让数据包挤满到一定程度才发送出去,挤满之前被阻塞

#keepalive_timeout  0;   # keepalive的超时时间
keepalive_timeout  65;

#gzip  on;               # 是否启用gzip压缩响应报文

server {                    # 定义虚拟主机
    listen       80;        # 定义监听套接字
    server_name  localhost; # 定义主机名加域名,即网站地址

    #charset koi8-r;        # 默认字符集

    #access_log  logs/host.access.log  main;         # 访问日志路径

    location / {                        # location容器,即URI的根
        root   html;                    # 站点根目录,即DocumentRoot,相对路径时为<prefix>/html
        index  index.html index.htm;    # 站点主页文件
    }

    #error_page  404    /404.html;      # 出现404 page not fount错误时,使用/404.html页响应客户端

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;      # 出现50x错误时,使用/50x.html页返回给客户端
    location = /50x.html {                        # 定义手动输入包含/50x.html时的location
        root   html;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
#    listen       8000;
#    listen       somename:8080;
#    server_name  somename  alias  another.alias;

#    location / {
#        root   html;
#        index  index.html index.htm;
#    }
#}

}

5.2.2 root指令和alias指令
root指令设置站点根目录,即httpd的documentroot,但又有所不同,因为nginx可以在多个上下文位置处使用root指令,例如Location容器中。

如果配置如下:

location /i/ {
root /data/w3;
}
那么nginx将使用文件/data/w3/i/top.gif响应请求"/i/top.gif"。

root指令仅仅只是将匹配的URI追加在root路径后,如果要改变URI,应该使用alias指令,它会对URI进行替换。例如:

location /i/ {
alias /data/w3/images/;
}
那么nginx将使用文件/data/w3/images/top.gif响应请求/i/top.gif。因此,如果alias指令的路径最后一部分包含了URI,则最好使用root指令,而非alias指令,虽然它们都能成功响应。

location /images/ {
alias /data/w3/images/;
}

location /images/ {
root /data/w3/;
}
它们都能使用相对路径,相对的是prefix。例如编译路径为/usr/local/nginx,则"root html"指的是"/usr/local/nginx/html"。

与root和alias指令相关的变量为$document_root、$realpath_root。其中$document_root的值即是root指令、alias指令的值,而$realpath_root的值是对root、alias指令进行绝对路径换算后的值。

5.2.3 location容器
该指令对规范化后的URI进行匹配,并对匹配的路径封装一系列指令。 语法:

location [ = | ~ | ~ | ^~ ] uri { ... }
其中: location /uri/ {}:表示对/uri/目录及其子目录下的所有文件都匹配。所以"location / {}"的匹配范围是最大的。
location = /uri/ {}:表示只对目录或文件进行匹配,不对目录中的文件和子目录进行匹配。所以一般只用来做文件匹配
location ~ /uri/ {}:表示区分大小写的正则匹配。
location ~
/uri/ {}:表示不区分大小写的正则匹配。
location ^~ /uri/ {}:表示禁用正则匹配,即精确字符串匹配,此时正则中的元字符被解释成普通字符。

它们的匹配优先级规则为:nginx先检查URI的前缀路径,在这些路径中找到最精确匹配请求URI的路径。然后nginx按在配置文件中的出现顺序检查正则表达式路径,匹配上某个路径后即停止匹配并使用该路径的配置,否则使用最大前缀匹配的路径的配置。

使用"="前缀可以定义URI和路径的精确匹配。如果发现匹配,则终止路径查找。例如请求"/"很频繁,定义"location = /"可以提高这些请求的处理速度,因为查找过程在第一次比较以后即结束。

以下是一个优先级的示例。

location = / {
[ configuration A ]
}

location / {
[ configuration B ]
}

location /documents/ {
[ configuration C ]
}

location ^~ /images/ {
[ configuration D ]
}

location ~* .(gif|jpg|jpeg)$ {
[ configuration E ]
}
请求"/"能匹配A和B,但最精确匹配为A。
请求"/index.html"的前缀"/"能匹配A和B,但A只能匹配"/"自身,因此最终匹配配置B。(前缀也能匹配E,但文件名无法匹配)
请求"/documents/document.html"的前缀能匹配B和C,但C更精确,因此匹配配置C。(前缀也能匹配E,但文件名无法匹配)
请求"/images/1.gif"的前缀能匹配B、D和E,且D和E都是最长路径匹配,但^~优先级更高,因此匹配配置D。
请求"/documents/1.jpg"的前缀能匹配B、C,同样也能匹配E,且E比B的匹配更精确,因此最终匹配配置E。

大致可以将规则简化为如下优先级:

(location = uri ) > (location ^~ uri) > (location *~|~ uri) > (location uri)
即等号优先级最高,非正则匹配次之,再之后是正则匹配,它们之间有位置的先后顺序,优先级最低的是没有使用任何符号的匹配。

由此也可以知道,"location / {}"这种方式是一种特殊的uri匹配,无论什么uri路径,都能往这里面装,可以认为它是默认匹配,当其它location都匹配不上时就会匹配它。

5.2.4 error_page指令
当出现对应状态码的错误时,指定返回的URI路径。语法为:

error_page code ... [=[response]] uri;
配置文件中的error_page部分默认为:

location / {
root html;
index index.html index.htm;
}

error_page 404 /404.html;

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
上面的配置文件中,假如取消了404错误的error_page行注释,当出现404错误时,其uri为/404.html,然后会对其进行location的匹配,由于只有"location / {}"能匹配到,所以它的目录为/html/,即404.html文件路径为/html/404.html。对于50x的error_page,其uri为"/50x.html",所以会对其进行location匹配,发现可以精确匹配到"location = /50x.html {}",当然"location / {}"也能匹配到,但是它的优先级更低,所以当出现50x错误时,将从/html目录下寻找50x.html,这里正好和"location / {}"重复了,但它们的匹配过程是不一样的。假如改为如下配置:

location / {
root html;
index index.html index.htm;
}

error_page 404 /404.html;

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /www/a.com/;
}
出现50x错误时,将返回/www/a.com/50x.html文件,而不再是/html/50x.html。

5.2.5 allow和deny
这两个指令由ngx_http_access_module模块提供,用于允许或限制某些IP地址的客户端访问。nginx中的allow和deny规则很简单,从上向下匹配,只要匹配到就停止。例如:

allow 10.0.0.8
allow 192.168.100.0/24
deny all
允许10.0.0.8和192.168.100网段的访问,其他的都拒绝。

5.2.6 add_header添加相应首部字段
用于在响应首部中添加字段。例如:

server {
add_header RealPath $realpath_root;
}
将添加一个名为RealPath的字段,值为变量realpath_root的值。

[root@xuexi ~]# curl -I http://localhost/
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Tue, 17 Oct 2017 08:10:14 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 17 Oct 2017 03:20:10 GMT
Connection: keep-alive
ETag: "59e576ea-264"
RealPath: /usr/local/nginx-1.12.1/html # 此为自定义添加字段
Accept-Ranges: bytes

5.3 虚拟主机和server_name指令
nginx使用server容器定义一个虚拟主机。在nginx中,没有严格区分基于IP和基于名称的虚拟主机,它们通过listen指令和server_name指令结合起来形成不同的虚拟主机。

例如:

基于IP地址的虚拟主机

server {
listen 80;
server_name 192.168.100.25;
location / {
root /www/longshuai/;
index index.html index.htm;
}
}
server {
listen 80;
server_name 192.168.100.26;
location / {
root /www/xiaofang/;
index index.html index.htm;
}
}

基于名称的虚拟主机

server {
listen 80;
server_name www.longshuai.com;
location / {
root /www/longshuai/;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.xiaofang.com;
location / {
root /www/xiaofang/;
index index.html index.htm;
}
}

基于端口的虚拟主机

server {
listen 80;
server_name 192.168.100.25;
location / {
root /www/longshuai/;
index index.html index.htm;
}
}
server {
listen 8080;
server_name 192.168.100.25;
location / {
root /www/xiaofang/;
index index.html index.htm;
}
}
其中server_name指令可以定义多个主机名,第一个名字为虚拟主机的首要主机名。例如:

server_name example.com www.example.com;
主机名中可以含有星号(""),以替代名字的开始部分或结尾部分(只能是起始或结尾,如果要实现中间部分的通配,可以使用正则表达式)。例如".example.org"不仅匹配www.example.org,也匹配www.sub.example.org。下面两条指令是等价的。

server_name example.com .example.com www.example.;
server_name .example.com www.example.*;
也可以在主机名中使用正则表达式,就是在名字前面补一个波浪线("~"):

server_name www.example.com ~^www\d+.example.com$;
nginx允许定义空主机名:

server {
listen 80;
server_name "";
return 444;
}
这种主机名可以让虚拟主机处理没有"Host"首部的请求,而不是让指定"地址:端口"的默认虚拟主机来处理,而这正是本指令的默认设置。即使用非默认的虚拟主机处理请求头中不含"Host"字段的请求。一般这样的请求处理方式是直接丢弃请求,并返回一个非标准的状态码来立即关闭连接,例如上面的444。

如果server块中没有定义server_name,nginx使用空名字作为虚拟主机名。

5.4 虚拟主机的匹配规则
通过名字查找虚拟主机时,如果一个名字可以匹配多个指定的配置,比如同时匹配上通配符和正则表达式,按下面优先级,使用先匹配上的虚拟主机:

确定的名称;
最长的以星号起始的通配符名字,比如".example.com";
最长的以星号结束的通配符名字,比如"mail.
";
第一个匹配的正则表达式名字(按在配置文件中出现的顺序)。
当开始接入请求时,(1)nginx首先判断请求的套接字,即IP和端口号;(2)然后在listen套接字中选择一个能匹配名称的虚拟主机,如果没有选出能匹配的名称,则使用该套接字的默认虚拟主机。默认情况下,监听套接字的默认虚拟主机为该套接字主机组中的第一个虚拟主机,但可以通过listen指令的default_server属性手动指定。

例如下面定义了4个虚拟主机:前3个都监听在192.168.100.1:80上,第四个监听在192.168.1.2:80上。

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

server {
listen 192.168.100.1:80 default_server;
server_name example.net www.example.net;
...
}

server {
listen 192.168.100.1:80;
server_name example.com www.example.com;
...
}

server {
listen 192.168.1.2:80;
server_name example.com www.example.com;
...
}
(1).从192.168.100.1:80上请求www.example.com,能匹配虚拟主机3,于是使用虚拟主机3的配置进行响应;
(2).从192.168.100.1:80上请求www.longshuai.com时,无法匹配任何虚拟主机,于是使用默认虚拟主机2的配置进行响应。如果将listen的属性default_server去掉,则使用虚拟主机1进行响应;
(3).从192.168.100.2:80上请求www.example.com时,使用虚拟主机4进行响应;
(4).从192.168.100.2:80上请求www.example.org时,由于无法匹配该套接字上的任何主机,于是使用默认虚拟主机响应,即虚拟主机4。

5.5 stub_status指令获取nginx状态信息
使用ngx_http_stub_status_module模块提供的功能可以获取nginx运行的状态信息。对应的指令只有一个,即stub_status。

例如,在某一个server下加上如下配置获取该server的状态信息。

server {
listen 80;
server_name www.longshuai.com;
location / {
root /www/longshuai/;
index index.html index.htm;
}
location /status {
stub_status on;
}
}
还可以明确指定访问该信息不记录日志,且提供访问控制,不让外界人随意获取信息。

location /status {
stub_status on;
access_log off;
allow 192.168.100.0/24;
deny all;
}
重载配置文件后,只需在浏览器中输入"主机名/status"即可获取信息。

Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
状态信息意义如下:

第一行active connections:291表示当前处于活动状态的客户端连接数,包括正处于等待状态的连接。
第四行reading数量为6,表示nginx正在读取请求首部的数量,即正在从socket recv buffer中读取数据的数量;writing数量为179表示nginx正在将响应数据写入socket send buffer以返回给客户端的连接数量;waiting数量为106表示等待空闲客户端发起请求的客户端数量,包括长连接状态的连接以及已接入但socket recv buffer还未产生可读事件的连接,其值为active-reading-writing。
第二行accepts的数量为16630948表示从服务启动开始到现在已经接收进来的总的客户端连接数;handled的数量为16630948表示从服务启动以来已经处理过的连接数,一般handled的值和accepts的值相等,除非作出了连接数限定;requests的数量为服务启动以来总的客户端请求数。一个连接可以有多个请求,所以可以计算出平均每个连接发出多少个请求。
以下是第二行几个参数的官方原文:
accepts:The total number of accepted client connections.
handled:The total number of handled connections. Generally, the parameter value is the same as accepts unless some resource limits have been reached (for example, the worker_connections limit).
requests:The total number of client requests.
关于nginx第二行的这几个状态,举个例子。第一个字段(accepts)表示餐厅已经接进来的客人数量,第二个字段(handled)表示吃完饭后离去的客人数量,第三个字段表示总共有多少人想进餐厅。第二个字段一般等于第一个字段,如果小于第一个字段,说明有客人只吃到一半就被丢出去了。

6.访问日志access_log
nginx的访问日志相关功能由ngx_http_log_module模块提供,指令包括log_format、access_log和open_log_file_cache。
nginx的日志可以先缓冲到buffer中,一定时间后再写入到日志文件中。从buffer刷盘到本地日志文件中时,可以进行压缩。
nginx的worker进程的运行身份需要有日志创建的权限,即对日志所在目录有写权限。
可以在多种上下文中定义是否开启日志以及日志的格式。最常见的三个上下文是http,server,location。
open_log_file_cache指令存在的意义是为了缓存日志文件描述符。之所以提供这个指令,是因为nginx每次日志的写入(从缓存中刷盘到本地日志文件中)都会打开、关闭一次日志文件。对于日志写入极其频繁的机器可以使用该指令缓存日志文件描述符,使得在缓存有效期内都可以续写到旧日志文件中。

6.1 log_format指令
log_format指定日志的格式,语法如下:log_format name string...;。其中name指定日志格式名称,配置文件中name名称不能重复。

以下是默认提供的main格式。

log_format main '$remote_addr - $remote_user [$time_local] "$request" '

'$status $body_bytes_sent "$http_referer" '

'"$http_user_agent" "$http_x_forwarded_for"';

在main后面的是一堆变量,除了这些变量之外还有其他很多变量可用,但如非特殊需求,默认的main格式就已经够完美了。以下是变量的意义:

$remote_addr:客户端的地址。如果nginx提供的web服务在后端,如前面有代理服务器或负载均衡等设备时,该变量只能获取到前端的IP地址。此时要获取到真正客户端地址需要使用变量$http_x_forward_for,但要求前端服务器要开启x_forward_for设置。
$http_x_forward_for:如上所述。
$remote_user:远程客户端用户名称。
$time_local:记录访问时间和时区信息。
$request:记录用户访问时的url和http协议信息。如:"GET /favicon.ico HTTP/1.1"。
$status:记录客户端请求时返回的状态码,如成功的状态码为200,page not found的状态码为404。
$body_bytes_sent:记录服务器响应给客户端的主体大小。
$http_referer:记录此次请求是从哪个链接过来的,需要模块ngx_http_referer_module支持,默认已装,可以防止倒链问题。
$http_user_agent:记录客户端的浏览器信息。如使用什么浏览器发起的请求,是否是压力测试工具在测试等。
例如,以下是默认格式的日志信息。

192.168.100.27 - - [23/Apr/2017:23:08:56 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"
192.168.100.27 - - [23/Apr/2017:23:08:56 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"
192.168.100.27 - - [23/Apr/2017:23:08:56 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"
192.168.100.27 - - [23/Apr/2017:23:08:56 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"
192.168.100.1 - - [23/Apr/2017:23:08:56 +0800] "GET /status HTTP/1.1" 200 109 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.100.1 - - [23/Apr/2017:23:08:56 +0800] "GET /status HTTP/1.1" 200 109 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.100.1 - - [23/Apr/2017:23:08:56 +0800] "GET /status HTTP/1.1" 200 109 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.100.27 - - [23/Apr/2017:23:08:57 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"
192.168.100.27 - - [23/Apr/2017:23:08:57 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"
192.168.100.27 - - [23/Apr/2017:23:08:57 +0800] "GET /index.html HTTP/1.0" 200 17 "-" "ApacheBench/2.3"

6.2 access_log指令
access_log主要用于定义使用什么格式的日志,日志存放路径。语法如下:

access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
path指定路径,path里可以使用变量。format指定日志格式,不写时或者配置文件中未配置access_log指令时,默认为combined。buffer=size指定日志缓冲区大小(默认64K),flush=time指定日志刷盘的时间,if=condition指定某些条件,gzip=level指定日志刷盘前先压缩的压缩级别(默认gzip=1)。

当指定了buffer或者gzip任意一个时,都会使用buffer先缓冲日志,然后再刷盘。

例如

access_log /spool/logs/nginx-access.log gzip buffer=32k;

6.3 日志文件的分割
默认nginx不会自动分割日志,也不支持在配置文件中使用cronolog以及rotatelogs(apache支持,因为支持管道传递)。要实现nginx的日志分割,需要通过移动旧日志、生成新日志来实现。

mv old_log new_log

然后

nginx -s reload

或者

nginx -s reopen

或者

kill -s USR1 master_pid
pid可以通过pid文件获得。

kill -s USR1 $(cat /var/run/nginx/nginx.pid)
要实现自动分割,需要使用脚本,并设置定时任务。

cat /usr/local/nginx/logs/cut_longhsuai.sh

!/bin/bash

cut the access log for www.longshuai.com

basedir=/usr/local/nginx
old_log_path=$basedir/logs/access.log
log_save_path=$basedir/logs
save_logname=access$(date -d "yesterday" +"%Y%m%d").log

[ -f "$old_log_path" ] || exit 1
/bin/mv $old_log_path $log_save_path/$save_log_name
$basedir/sbin/nginx -s reopen
再添加定时任务计划。

chmod +x /usr/local/nginx/logs/cut_longshuai.sh

crontab -e
00 00 * /bin/sh /usr/local/nginx/logs/cut_longshuai.sh &>/dev/null

7.配置web身份认证
需要输入用户名和密码才能访问站点的功能为web身份认证功能。nginx中由ngx_http_auth_basic_module模块提供该功能。指令包括auth_basic和auth_basic_user_file。这两个指令可以在http根段、server段、location段使用。

auth_basic string | off
auth_basic_user_file path/to/user_passwd_file # 密码文件使用相对路径时是相对conf目录的
passwd_file的格式为:

user1:passwd1
user2:passwd2
需要注意的是,密码文件不能使用明文密码的方式。该类文件一般使用apache提供的工具htpasswd生成,该工具在httpd-tools包中,具体用法见htpasswd命令。也可以使用openssl passwd生成相关密码然后复制到密码文件中。以下是一个示例:

server {
listen 80;
server_name www.longshuai.com www1.longshuai.com;
location / {
root /www/longshuai/;
index index.html index.htm;
auth_basic "Auth your name";
auth_basic_user_file /usr/local/nginx/htpasswd;
}
}
然后使用htpasswd生成密码文件/usr/local/nginx/conf/htpasswd。

yum -y install httpd-tools
htpasswd -b -c -m /usr/local/nginx/conf/htpasswd Jim 123456
htpasswd -b -m /usr/local/nginx/conf/htpasswd Tom 123456
-b选项是表示batch模式,不用交互输入密码。-c表示创建密码文件,只能为第一个用户使用该选项,否则后面使用会覆盖前面已经创建过的。-m表示强制使用md5。Jim和Tom是需要验证的用户名,123456是密码。查看生成的密码文件。

[root@xuexi nginx]# cat htpasswd
Jim:$apr1$URdS8lcY$GyghBlYInlqfkto0ndnH1.
Tom:$apr1$B/orDxHj$1jIWk1X5XabpH3hcFQzoN1
然后重载配置文件,在浏览器中测试。测试时最好不要用IE。

也可以使用openssl passwd生成,下面的"-apr1"(数值1而非字母L的小写)选项是为apache密码做相关支持的。

openssl passwd -apr1 123456
$apr1$rD/3/kFH$L8KYfzAWFtHO8mOiR9dci1

或者加点盐

openssl passwd -apr1 -salt 'xyz' 123456
$apr1$xyz$j0n99G44SENB4NmJiwEfJ0
然后将得到的密码复制到密码文件中对应的用户名后面即可。如将得到的"$apr1$xyz$j0n99G44SENB4NmJiwEfJ0"作为"Admin"用户的验证密码。

Admin: $apr1$xyz$j0n99G44SENB4NmJiwEfJ0

8.配置https
https功能由ngx_http_ssl_module模块提供。https连接的认证过程见SSL握手机制。简单版的过程如下:

客户端say hello,并发送一个随机数给服务端。
服务端say hello,并回复一个随机数给客户端。
服务端发送数字证书给客户端。
客户端使用信任的CA公钥解密数字证书得到服务端的公钥。
客户端使用服务端的公钥加密一个预备主密钥并发送给服务端。
服务端使用自己的私钥解密预备主密钥。
双方都得到了2个随机数加一个预备主密钥。通过这3个随机数形成一个会话主密钥,即session key。至此ssl握手结束,连接的认证过程也完毕。
对于服务端而言,在配置https时,需要提供自己的数字证书用于发送给客户端,还要提供自己的私钥用于解密客户端发送的预备主密钥。当ssl连接建立完成后,后续连接要传输的数据都采用session key进行加密,但注意session key是对称加密,客户端和服务端是一样的。

还需注意,在创建证书请求时,由于需要指定common name,这是需要使用https的站点,因此每个ssl证书只能为一个server_name提供https服务。不过,通过特殊的配置方法,也能让一个ssl证书服务于整个域名或域名内的某些主机。例如,https://www.baidu.com使用的证书就是颁发给"baidu.com"的,而不是该域名下的某一台主机。如何实现这样的功能,可以网上搜索下关键字"ssl SubjectAltName",若有需要,我会另开一篇文章介绍实现方法。

以下是配置文件中默认的关于SSL相关的指令设置。

server {

listen 443 ssl;

server_name localhost;

ssl_certificate cert.pem;

ssl_certificate_key cert.key;

ssl_session_cache shared:SSL:1m;

ssl_session_timeout 5m;

ssl_ciphers HIGH:!aNULL:!MD5;

ssl_prefer_server_ciphers on;

location / {

root html;

index index.html index.htm;

}

}

以下是建立https的相关过程:

自建CA。
cd /etc/pki/CA
(umask 077;openssl genrsa -out private/cakey.pem 2048)
openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 3650
建立相关序列和索引文件。
touch index.txt
echo "01" > serial
nginx端生成证书请求。
(umask 077;openssl genrsa -out /usr/local/nginx/longshuai.key 2048)
openssl req -new -key /usr/local/nginx/longshuai.key -out /usr/local/nginx/longshuai.csr
CA为证书请求颁发证书。
openssl ca -in /usr/local/nginx/longshuai.csr -out longshuai.crt
将颁发的证书发送给nginx端。这里由于CA和nginx在同一主机上,所以直接移动即可。
mv longshuai.crt /usr/local/nginx/
此时,在/usr/local/nginx/目录下就有了nginx自己的私钥文件和证书文件。
[root@xuexi nginx]# ls longshuai*
longshuai.crt longshuai.csr longshuai.key
修改配置文件,配置ssl相关选项。
[kod.jsfgx.org)
[kod.thzjpx.org)
[kod.sunlinbo.com)
[kod.antingfly.org)
[kod.ibmaix.cn)
[kod.jgjgzx.com)
[kod.028web.com)

server {
listen 443 ssl;
server_name www.longshuai.com;

ssl_certificate /usr/local/nginx/longshuai.crt;
ssl_certificate_key /usr/local/nginx/longshuai.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

location / {
root html;
index index.html index.htm;
}
}
重载配置文件。
测试。在浏览器上输入https://www.longshuai.com测试。将会提示证书安全存在问题,说明配置成功。以后只要在客户端安装证书即可正常访问。测试时,建议使用IE浏览器或使用IE内核的浏览器测试,这样比较直观。使用firefox、chrome等浏览器可能会因为是自建的CA而出现一些问题。

相关文章
|
1月前
|
XML JSON 数据安全/隐私保护
Web服务
【10月更文挑战第18天】Web服务
48 9
|
1月前
|
自然语言处理 大数据 应用服务中间件
大数据-172 Elasticsearch 索引操作 与 IK 分词器 自定义停用词 Nginx 服务
大数据-172 Elasticsearch 索引操作 与 IK 分词器 自定义停用词 Nginx 服务
64 5
|
1月前
|
XML JSON 安全
Web服务是通过标准化的通信协议和数据格式
【10月更文挑战第18天】Web服务是通过标准化的通信协议和数据格式
150 69
|
12天前
|
负载均衡 前端开发 JavaScript
Nginx 代理多服务
以上是 Nginx 代理多服务的几种常见方式,在实际应用中,可以根据具体的业务需求和系统架构选择合适的代理方式,并结合其他 Nginx 的功能和配置来优化和完善系统的性能和功能。
|
13天前
|
Go UED
Go Web服务中如何优雅平滑重启?
在生产环境中,服务升级时如何确保不中断当前请求并应用新代码是一个挑战。本文介绍了如何使用 Go 语言的 `endless` 包实现服务的优雅重启,确保在不停止服务的情况下完成无缝升级。通过示例代码和测试步骤,详细展示了 `endless` 包的工作原理和实际应用。
32 3
|
14天前
|
JSON Go UED
Go Web服务中如何优雅关机?
在构建 Web 服务时,优雅关机是一个关键的技术点,它确保服务关闭时所有正在处理的请求都能顺利完成。本文通过一个简单的 Go 语言示例,展示了如何使用 Gin 框架实现优雅关机。通过捕获系统信号和使用 `http.Server` 的 `Shutdown` 方法,我们可以在服务关闭前等待所有请求处理完毕,从而提升用户体验,避免数据丢失或不一致。
15 1
|
20天前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
1月前
|
XML JSON 安全
定义Web服务
【10月更文挑战第18天】定义Web服务
61 12
|
30天前
|
缓存 负载均衡 应用服务中间件
Nginx 实现一个端口代理多个前后端服务
【10月更文挑战第19天】Nginx 的强大功能不仅限于此,它还可以与其他技术和工具相结合,为我们的应用提供更强大的支持和保障。在不断发展的互联网时代,掌握 Nginx 的使用技巧将为我们的工作和生活带来更多的便利和效益。
|
1月前
|
前端开发 Java API
JAVA Web 服务及底层框架原理
【10月更文挑战第1天】Java Web 服务是基于 Java 编程语言用于开发分布式网络应用程序的一种技术。它通常运行在 Web 服务器上,并通过 HTTP 协议与客户端进行通信。
26 1
下一篇
无影云桌面