Nginx是C语言编写的服务器程序,可以作为WEB服务器,反向代理,负载均衡组件,邮件代理,以及HTTP缓存服务器,初始作者为俄罗斯Igor Sysoev,首次发布版本为2004年10月4日,其开源软件协议为2-clause-BSD,可以运行在多种BDS、HP-UX、IBM AIX,Linux、 MAC、Solaris、Windows。
Nginx初衷是为了解决WEB服务器C-10K问题,及并发连接1万,在线程模型下难以实现,Nginx使用Linux内核的异步时间驱动机制(EPOLL)构建出高性能,轻量化的服务器。
$sudo apt-get update
$sudo apt-get install nginx
$sudo yum -y install epel-release
$sudo yum -y update
$sudo yum -y install nginx
注:截至2020.2,Yum目前为1.16版本,NGINX仓库为1.17
一、修改yum配置文件,添加软件仓库配置
$sudo vi /etc/yum.repos.d/nginx.repo
二、添加如下内容,< OS >为rhel或者cetnos,< OSRELEASE>为OS发行版本号,如6、6.x、7.x
[nginx]
name=nginx.repo
baseurl=https://nginx.org/packages/mainline/< OS>/< OSRELEASE>/$basearch/
gpgcheck=0
enabled=1
三、Update软件仓库,安装Nginx并运行
$sudo yum update
$sudo yum -y install nginx
$sudo nginx
Way1、增加Nginx stable软件仓库并安装
$zypper addrepo -G -t yum -c 'https://nginx.org/packages/sles/12' nginx
$zypper install nginx
Way2、增加Nginx mainline软件仓库并安装
$zypper addrepo -G -t yum -c 'https://nginx.org/packages/mainline/12' nginx
$zypper install nginx
一、安装依赖库
PCRE
$wget ftp://ftp.csx.ac.uk/pub/software/programing/pcre/pcre-8.43.tar.gz
$tar -zxvf pcre-8.43.tar.gz
$cd pcre-8.43
$./configure
$make
$sudo make install
zlib
$wget http://zlib.net/zlib-1.2.11.tar.gz
$tar -zxvf zlib-1.2.11.tar.gz
$cd zlib-1.2.11
$./configure
$make
$sudo make install
OpenSSL
$wget https://www/openssl.org/source/openssl-1.1.1c.tar.gz
$tar -zxvf openssl-1.1.1c.tar.gz
$cd openssl-1.1.1c
$./configure darwin64-x86_64-cc --prefix=/usr
$make
$sudo make install
二、获取Nginx源码
$wget https://nginx.org/download/nginx-1.17.6.tar.gz
$tar -zxvf nginx-1.17.6.tar.gz
$ cd nignx-1.17.6
三、编译安装
$./configure
--sbin-path=/usr/local/nginx/nginx
--conf-path=/usr/local/nginx/nginx.conf
--pid-path=/usr/local/nginx/nginx.pid
--with-pcre=../pcre-8.43
--with-zlib=../zlib-1.2.11
--with-http_ssl_module
--with_stream
--with-mail-dynamic
--add-module=/usr/build/nginx-rtmp-module
--add-dynamic-module=/usr/build/3party_module
###编译安装启动
$make
$sudo make install
$sudo nginx
Nginx模块化概念
Nginx由主程序以及模块构成,Nginx的功能通过模块提供,配置文件中的指令和变量由模块提供,A用户的配置文件拷贝道B用户上不一定可以启动Nginx
Nginx由核心功能以及一系列的模块化构成,下面的模块默认会在nginx内,在configure命令中添加–without-< MODULE-NAME>可以取消某个模块的编译
Module Name | Description |
---|---|
–with-http ssl module | 开启HTTPS支持,需要OpenSSL |
–with-http stub status module | 提供基本信息的访问。Nginx Plus自带这个扩展包 |
–with-http v2 module | 开启支持HTTP/2 |
–with-stream | 开启TCP、UDP代理功能。要将其编译为一个单独的动态模块,请将选项更改为–with-stream=dynamic |
对于在默认编译中的模块,可以在configure过程中,使用–with=< MODULE-NAME>添加
$./configure
--sbin-path=/usr/local/nginx/nginx
--conf-path=/usr/local/nginx/nginx.conf
--pid-path=/usr/local/nginx/nginx.pid
--with-pcre=../pcre-8.43
--with-zlib=../zlib-1.2.11
--with-http_ssl_module
--with_stream
--with-mail-dynamic
其中mail、stream、geoip、image_filter、perl、xslt可以编译为动态模块
$apt-get install nginx-plus-module-< name>
$wget https://nginx.org/download/nginx-1.15.10.tar.gz
$tar -zxvf nginx-1.15.10.tar.gz
$ cd nginx-1.15.10
$./configure --with-compat --add-dynamic-module=../nginx-foo-modules
$make modules
略
Issue 1:Proxy Connection is Forbidden
Issue 2:File Access is Forbidden
Issue 3:NGINX Cannot Bind to Additional Port
解决方案:
1、关闭SELinux
#临时关闭
setenforce 0
#永久关闭
sed -i '7s/enable/disabled/' /etc/selinux/config
reboot
2、设置或者关闭防火墙规则
#设置防火墙规则
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd reload
#关闭防火墙
sytemctl stop firewalld
/etc/nginx/
cat nginx.conf
http {
include conf.d/*.conf;
}
/etc/nginx/conf.d
cat virtualserver1.conf
server{
listen #请求监听
location < url>{
#请求处理规则
}
}
upstream{
#后端服务器配置
}
/var/log/nginx/
error.log #错误日志
access.log #每次请求记录,可配合格式
- Main
- Event
- HTTP
- Server
- Location
- Upstream
- Stream
- Server
- Upstream
#Main:上下文定义最高级别的指令,例如worker的数量,linux用户,PID文件的位置,Log文件的位置等等
user nginx;
worker_processes 5;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
worker_rlimit_nofile 8192;
#Event:用于管理连接处理的指令,比如每个worker进程的连接数
events {
worker_connections 4096;
}
#HTTP:定义Nginx如何处理HTTP/HTTPS连接,包含后台资源,如Pool成员,在http上下文中的其他指令会被其子集上下文继承,如upstream、server、location
http {
include /etc/nginx/mime.types;
include /etc/nginx/proxy.conf;
include /etc/nginx/fastcgi.conf;
index index.html index.htm index.php;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$status" '
'"$request" $body_bytes_sent "$http_referer"'
'$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;
server_names_hash_bucket_size 128;
gzip on;
# upstream:定义后端服务器组
upstream xx{
www.domain1.com weigth=2;
www.domain2.com;
}
#Server:定义虚拟服务器或虚拟主机,用来处理HTTP请求,定义可以是一个FQDN域名,IP地址,或者Unix Socket
server {
listen 80;
listen [::]:80;
server_name www.domain.com;
access_log /var/log/nginx/host.access.log main;
#Location:进一步定义如何处理一个URL
location / {
root /usr/share/nginx/html;
index index.html index.htm;
fastcgi_pass 127.0.0.1:1025;
}
#Steram:定义如何处理TCP/UDP流量
}
Nignx接受到REQUEST后会首先判断使用在nginx.conf文件中的那个server进行处理,选择server通过server中的两个指令进行判断
Directive | Nginx Uses |
---|---|
listen 80; | 0.0.0.0:80 |
listen 127.0.0.1:8080; | 127.0.0.1:8080 |
listen 127.0.0.2; | 127.0.0.2:80 |
listen unix:/var/run/nginx.sock | Must use absolute path |
< no listen directive> | 0.0.0.0:80 |
假定DNS服务上配置example.com为192.168.1.10
同IP端口下的不同服务
server {
listen 192.168.1.10;
server_name www.example.org;
}
server {
listen 192.168.1.10;
server_name www.example.com;
}
Server_name指令匹配报文头中的Host字段,默认为’ ‘’,通常是一个FQDN域名或IP地址,该指令一般用来做同IP端口下不同服务的区分,server_name可以采用通配符前缀,后缀的方式,也可以使用正则表达式
server {
listen 80;
server_name ~^(www|host1).*\.example\.com$;
}
server {
listen 80;
server_name ~^(subdoamin|www|host1|set).*\.example\.com$;
}
当没有精确匹配和通配符前后缀匹配的时候,Nginx会用perl的正则表达式匹配逻辑进行server bolck匹配,请注意按照正则表达式进行匹配的时候,没有所谓的“best match”,而是按照在配置文件中的顺序进行匹配
如上例,两个server block都可以匹配到www.example.com的请求,第二个server bolck更精细,但是第一个server block会处理http://www.example.com
server {
listen 80;
server_name www.example.org;
return 200 "this is listen 80 \n";
}
server {
listen 192.168.1.10;
server_name www.example.com;
return 200 "this is listen 192.168.1.10,www.example.com\n";
}
Location配置块定义具体的uri应该如何响应
=,,*^~用于uri的匹配
@用来创建一个内部location表示,可以用在类似try_flie的命令中
常用Location修饰器
Module Name | Description |
---|---|
~* | 不区分大小写正则表达式 |
~ | 区分大小写正则表达式 |
^~ | 不使用正则表达式 |
= | 精准匹配 |
该指令用来实现反向代理和负载均衡,其语法为
Syntax:proxy_pass URL;
Default:-
Context:location,if in location,limit_except(server)
对于HTTP类型需要写在location上下文
location /name/ {
proxy_pass http://1.1.1.1/test/;
}
对TCP流量可以直接写在server block
server {
listen 1111;
proxy_connect_timeout 1s;
proxy_timeout 2s;
proxy_pass backend;
}
Nginx HTTP转发流量式proxy行为,不同于网络意义上的路由转发,防火墙的NAT,硬件负载均衡的LB,默认请求流量会被拆分到多连接,响应流量可能会被缓存。
在http,server,location上下文使用server_tokens off消除版本信息,nginx plus中使用参数“ ”可以彻底删除server报文头,也可以使用add_header
proxy_http_version可以指定http版本号,推荐在keepalive连接和NTLM authentication
后端响应中的“Date”,“Server”,“X-pad”,and “X-Accel-…”报文头默认不发送给客户端
TCP行为描述
配置 | Proxy的TCP行为 |
---|---|
Proxy-pass http://backend | 客户端用一个TCP连接发起多个request,Nginx将针对每个request发起一个后端TCP连接,每个TCP连接发送一个request |
Proxy_http_version 1.1 Proxy-pass http://backend | 客户端用一个TCP连接 发起多个request,Nginx将针对每一个equest发起一个后端TCP连接,每个TCP连接发送一个request |
Proxy_http_version 1.1 Proxy-pass http://backend upstream keepalive | 客户端用多个TCP发起多request,Nginx创建少量连接,复用已经打开的TCP连接,发送多个request |
Stream下配置proxy_pass | 客户端每建立一个TCP连接,在三次握手完成后,nginx就和后端建立一TCP连接 |
如果proxy_pass指令中包含路径,那么request路径会被改写为proxy_pass的路径,行为和root命令保持一直
如果proxy_pass指令不包含路径,那么实际request中的路径添加上location中的路径
在代理转发HTTP request中,部分客户端的真实信息会丢失,nginx会替换为自身的信息转发request,此时可以通过“ proxy_set_header ”将指定的信息插入请求中,然后代理发送到外部
#example
server {
listen 80;
proxy_set_header Host $Host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://backend-server.com
}
}
add_header执行respense中报文头的修改,可以用于添加nginx信息,debug,以及通过修改cache-control重新定义在客户端的缓存行为
只有当respense code为200,201,204,206,301,302,303,304,307,308才生效,除非设定为always
该指令可从上下文中继承,如本级配置没有配置,那么上层配置会被继承
#example
server {
listen 80;
add_header <custom_header><value>;
}
keepalive指令指定客户端侧到Nginx测连接的最大请求数量和超时时间,默认为每一个TCP连接100个request,超时时间为63sec
error_log - 记录Nginx服务器所有运行信息
access_log - 记录访问Nginx服务器的流量细节
server {
listen 192.168.2.72:82;
server_name www.example.org;
error_log /var/log/nginx/server1_info.log info;
location /error {
error_log /var/log/nginx/server1_info.log error;
}
describe | 类型 |
---|---|
upstream/client timed out | 1 |
connect() faild | 2 |
no live upstream | 3 |
upstream/client permaturely closed connection | 4 |
102:Connection reset by peer | 5 |
client intended to send too large body | 6 |
upstream sent invalid HTTP header | 7 |
SSL hanshake mistake | 8 |
others | 9 |
类型 | 错误日志 | 原因 | 解决方法 |
---|---|---|---|
1 | upstream/client timed out(110:Connection timed out) while connecting to upstream | nginx与upstream建立tcp连接超时,nginx默认连接建立超时时间为200s | 排查upstream是否能正常建立tcp连接 |
1 | upstream/client timed out(110:Connection timed out) while reading response header from upstream | nginx从upstream读取响应超时,nginx默认的读超时为20s,读超时不是整体读的时间超时,而是指两次读操作之间的超时,整体读耗时有可能超过20s | 排查upstream响应请求为什么过于缓慢 |
1 | client timed out110:Connection timed out) while SSL handshaking | nginx与客户端建立SSL连接时,客户端超时 | 排查报错流量占比,如较高可适当调高响应的time out参数 |
1 | client timed out110:Connection timed out) while waiting for request | nginx与客户端建立tcp连接后,等待客户端发送request的过程中,客户端发送超时 | 排查报错流量占比,如较高可适当调高响应的time out参数 |
2 | connect() faild(104:Connection reset by peer) while connetciong to upstream | nginx与upstream建立tcp连接时被reset | 排查upstream是否能正常建立tcp连接 |
2 | connect() faild(111:Connection refused) while connecting to upstream | ginx与upstream建立tcp连接时被拒 | 排查upstream是否能正常建立tcp连接 |
2 | (111:Connection refused) while sending request to upstream | nginx和upstream连接成功后发送request时,若遇到后端upstream挂掉或者不通,会受到该错误 | 排查upstream server的状态 |
3 | no live upstream while connecting to upstream | nginx向upstream转发请求时发现upstream状态全部为down | 排查nginx的upstream的建康检查为什么失败 |
4 | upstream prematurely closed connection | nginx在与upstream建立完tpc连接后,试图发送请求或者读取响应时,连接被upstream强制关闭 | 排查upstream程序是否异常,是否能正常处理http请求 |
4 | pstream prematurely closed connection(104:Connection reset bu peer)while sending to client | nignx在与client建立完tcp连接后,试图发送响应给客户端时,连接被客户端强制关闭 | 一般是正常现象,比如客户端异常关闭,排查该异常流量占比 |
5 | recv() failed(104 Connection reset by peer)while reading response header from upstream | nginx从upstream读取响应连接被对方reset | 排查upstream应用tcp连接是否异常 |
5 | peer closed connection in SSL handsharke(104:Connection reset by peer) while SSL handshaing | nginx与client进行ssl连接握手过程中,客户端reset了连接 | 一般是正常现象,比如客户端异常关闭,排查该异常流量占比 |
5 | recv() failed(104 Connection reset by peer)while sending to client | nginx在生成响应返回客户端连接被对方reset | 一般是正常现象,比如客户端异常关闭,排查该异常流量占比 |
6 | client intended to send too large body | 客户端试图发送过大的请求body,nginx默认最大允许的大小为1m,超过此大小,客户端会收到http 413错误码 | 1.调整请求客户端的请求body大小;2.调大相关域名的nginx配置:client_max_body_size; |
7 | upstream sent invalid HTTP header while reading response header from upstream | nginx不能正常解析从upstream返回来的响应头 | 排查upstream应用配置 |
8 | SSL_do_handshake() failed | SSL握手失败 | 排查nginx ssl相关配置 |
8 | cloud not add new SSL session to the session cache while SSL handshaking | ssl_session_cache配置参数过小不满足需求 | 增大 |
8 | ngx_skab_alloc() failed:no memory in SSL session shared cache | ssl_session_cache配置参数过小不满足需求 | 增大 |
9 | client closed keepalive connection | 客户端正常关闭与nginx的连接 | 正常现象,如不希望见到此类信息,调整error log到notice级别或以上 |
Sytax: access_log path [format [buffer=size] [gzip[=level]];
access_log off;
Default: access_log logs/access.log combined;
Context: http,server,location,if in location,limite_except
#example
access_log /path/to/log.gz combined gzip fulsh=5m;
access_log syslog:server=192.168.2.1 debug;
默认的combind日志格式
'$remote_addr - $remote_user [$time_local] "$status" ' '"$request" $body_bytes_sent "$http_referer"' '$status $body_bytes_sent "$http_referer" '"$http_user_agent" ';
通过logrotate管理nginx日志文件
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 640 nginx adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid];then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
logrotate常用配置
compress #通过gzip 压缩转储以后的日志
nocompress #不做gzip压缩处理
copytruncate #用于还在打开中的日志文件,把当前日志备份并截断;是先拷贝再清空的方式,拷贝和清空之间有一个时间差,可能会丢失部分日志数据。
nocopytruncate #备份日志文件不过不截断
create mode owner group #轮转时指定创建新文件的属性,如create 0777 nobody nobody
nocreate #不建立新的日志文件
delaycompress #和compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress #覆盖 delaycompress 选项,转储同时压缩。
missingok #如果日志丢失,不报错继续滚动下一个日志
errors address #专储时的错误信息发送到指定的Email 地址
ifempty #即使日志文件为空文件也做轮转,这个是logrotate的缺省选项。
notifempty #当日志文件为空时,不进行轮转
mail address #把转储的日志文件发送到指定的E-mail 地址
nomail #转储时不发送日志文件
olddir directory #转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir #转储后的日志文件和当前日志文件放在同一个目录下
sharedscripts #运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个,那么每个日志轮转后都会执行一次脚本
prerotate #在logrotate转储之前需要执行的指令,例如修改文件的属性等动作;必须独立成行
postrotate #在logrotate转储之后需要执行的指令,例如重新启动 (kill -HUP) 某个服务!必须独立成行
daily #指定转储周期为每天
weekly #指定转储周期为每周
monthly #指定转储周期为每月
rotate count #指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
dateext #使用当期日期作为命名格式
dateformat .%s #配合dateext使用,紧跟在下一行出现,定义文件切割后的文件名,必须配合dateext使用,只支持 %Y %m %d %s 这四个参数
size(或minsize) log-size #当日志文件到达指定的大小时才转储,log-size能指定bytes(缺省)及KB (sizek)或MB(sizem).
当日志文件 >= log-size 的时候就转储。 以下为合法格式:(其他格式的单位大小写没有试过)
size = 5 或 size 5 (>= 5 个字节就转储)
size = 100k 或 size 100k
size = 100M 或 size 100M
log_format apm ’ "$time local” client=$remote_addr’
'method=$request method request="$request"'
'request length=$request length '
'status=$status bytes sent=$bytes sent'
'body bytes sent=$body bytes sent'
'referer=$http referer'
'user_agent="$http_user agent"'
'upstream addr=$upstream addr'
'upstream_status=$upstream_status'
'request time=$request time'
'upstream_response time=$upstream_response_time '
'upstream connect time=$upstream connect time'
'upstream header time=$upstream header time';
log_format trace '$remote addr - $remote user [stime local] "$request"' '$status
$body_bytes sent "$http referer""shttp user agent"' '"$http_x forwarded for" $request id';
server {
listen 80;
location / {
proxy_pass http://app_server;
proxy_set header X-Request-ID $request id; # Pass to app
access log /var/log/nginx/access trace.log trace;
Reload流程
1.更新nginx.conf配置文件向Master发送SIGUP信号,或者执行nginx -s reload
2.Master进程使用新配置启动新的worker进程
3.老配置worker进程在完成已存在连接时优雅的退出
4.Nginx始终保持运行中,平滑的更换了配置文件
仅有7个性能参数指标
浏览器打开,需要安装–http_stub_status module
http://nginx.server/stub_status