nginx 二十分钟入门
文章目录
Nginx 是什么?
Nginx(engine x)是一个高性能(主要体现在高并发,高可靠)的HTTP和反向代理web服务器。该web服务器由伊戈尔赛索耶夫(Igor Sysoev)在Rambler公司任职期间,利用 业余时间(lgor是清白的) 开发的基于 REST 架构风格,以统一资源描述符(Uniform Resources Identifier)URI 或者统一资源定位符(Uniform Resources Locator)URL 作为沟通依据,通过 HTTP 协议提供各种网络服务。
Nginx 应运而生?
1996年,互联网产业还远没有现在这么庞大,当时用户和访问规模还小,基础设施较差,产品的设计与发展多屈服于环境及各自的局限。Apache横空出世,在当时已卓越的性能,高度的稳定性,亮眼的跨平台性,最重要的是开源成为毫无争议的web服务器界最靓的崽。
2002年,随着互联网的发展Apache暴露除更多的问题,如消耗资源大,不支持高并发,自身重量级设计等。市场迫切需要一款轻量级高并发服务器来适应互联网的高速发展。俄罗斯工程师lgor Sysoev
在他为 Rambler Media 工作期间,使用 C 语言开发了 Nginx。
Nginx 使用基于事件驱动架构,使得其可以支持数以百万级别的 TCP 连接。高度的模块化和自由软件许可证使得Nginx生态圈飞速扩张。
Nginx 能做什么?
正向代理
替代用户去服务器交换数据,客户知道明确的目标网服务器,服务器不知道是哪个具体用户访问的。
Nginx 是个代购。
听说Iphone12出了,听说只有欧洲一家店在售,只能让身在国外的朋友买给我,带回国后一阵寒暄请他吃了顿饭,取回了我的iphone12和正规发票。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sQTGGdvy-1590458667551)(https://s1.ax1x.com/2020/05/21/Ybe5fx.png)]
反向代理
替代服务器与客户交互数据,客户不知道具体是那台服务器响应了请求,服务器知道明确的客户。
Nginx 是个背包客
我认识一个朋友在华强北,听说能原价买来华为metaX折叠屏手机,我就把钱给他让他去给我买,并许诺我给我个人发票。手机用了几天被我折断了,我找他三包,却不知道他在华强北哪一家买的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1V0iHO0p-1590458667553)(https://s1.ax1x.com/2020/05/21/YbKjr8.md.png)]
HTTP服务器
这个才是nginx 设计的初衷啊。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bFWFUrCN-1590458667555)(https://s1.ax1x.com/2020/05/21/YbGz6A.md.png)]
邮件代理服务器
无图
Nginx可以将IMAP,POP3和SMTP协议代理到承载邮件帐户的上游邮件服务器之一,因此可以用作电子邮件客户端的单个端点。这可能带来许多好处,例如:
- 轻松扩展邮件服务器的数量
- 根据不同的规则选择邮件服务器,例如,根据客户的IP地址选择最近的服务器
- 在邮件服务器之间分配负载
Tips: 安装nginx 的时候,记得开启 --with-mail——ssl_module 和 --with-openssl=[DIR]/opemssl-1.1.1
图片存储
无图
这个是应用了,nginx 文件存储的功能。适合少中量图片存储,搭建私人图床。如果有速度要求的话可以用缓存加持一下。
更多有意思的事情
知乎上找到了很多大家的奇技淫巧,学习学习。
- 和memcache结合,直接缓存网页内容,快速响应
- 自动裁剪图片,做缩略图
- 对客户端限速处理
- 对客户端限速处理
- 配合lua来开发Web应用。
- 防盗链
Nginx 的特点是什么?
一说Nginx,就想到6个字:轻快高热省小。
- 轻:轻量级
- 快:启动快,响应快
- 高:高并发,高可用
- 热:热部署
- 省:省带宽,省钱
- 小:体积小,占用内存小
Nginx 凭什么做到高并发?
Nginx使用epoll(linux2.6内核)和kqueue(freebsd)网络模型,官方号称单节点支持5W并发连接,根据硬件不同也是有差别的,单节点有2~3W并发也很优秀了。
-
多进程(单线程)
- Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程
- 每个子进程只有一个线程,采用的 IO多路复用模型epoll,实现高并发
-
IO多路复用的epoll 事件处理模型
- 一个文件描述符管理多个描述符,没有了描述符限制
- 将用户关系的文件描述符的时间存放到内核的一个时间表中,这样用户空间和内核空间只需一次copy。
- 只有就绪的FD定义的回调函数才会被执行,避免IO因FS监视数量增多而效率降低。
-
异步非阻塞(AIO)
- 异步非阻塞,IO利用率更高。
-
内存映射(mmap)
- 让内核缓存与磁盘进行映射,web服务器,直接复制页面内容即可。不需要先把磁盘的上的页面先输入到内核缓存去。
Nginx 凭什么做到热部署?
先看一下Nginx 线程架构图
看到了吧,就是这种结构才给nginx创造了热部署的可能性。
搞懂关系,举个例子:
- 一个master包工头领一帮worker马仔,master负责接项目,worker负责搬砖。
- master接收到热重启指令,告诉worker们,手里没活的跟我去干新项目,手里有活的先干着,干完再就给你们分新任务。
实际上nginx也就是这么干的:
通过命令行nginx -s reload #重新加载
完成不停机更新配置文件。
修改配置文件nginx.conf后,重新生成新的worker进程,当然会以新的配置进行处理请求,而且新的请求必须都交给新的worker进程,至于老的worker进程,等把那些以前的请求处理完毕后,kill掉即可。
nginx 如何实现的高可用?
请参看Nginx+Keepalived高可用集群
Nginx 作为企业级服务框架中的通讯兵,作为网关绝对不能出现单点问题。通过Keepalived + Nginx
的方式实现高可用。
搞懂关系,举个例子:
- "Nginx"是Java开发程序员(简称
小N
),任务非常多压力很大。公司担心这个程序员猝死项目停滞,就招聘了一位肤白貌美关键是职业素养高的项目经理-Keepalived
(简称小K
,人家之前可是负责整个LVS集群的管理)和一个小N的备岗(美其名曰给小N找了个小弟简称:小ND
)。 - 这位小K将需求分发给小N和小ND。时刻监控两位小弟的状态。
- 小N请了病假,小K就将所有的任务给了小ND,第二天小N来了,小K再给小N重新安排任务。
nginx 怎么体现小的?
拿最新的版本来看:
版本号 | 大小 |
---|---|
nginx-1.17.10.tar.gz | 1.07M |
nginx-1.17.10.zip | 1.5M |
nginx-1.18.0.tar.gz | 1.04M |
nginx-1.18.0.zip | 1.5M |
看到了吧,软件尺寸是不是很小?
nginx 使用
nginx 的使用包括安装和配置两部分:
安装 Nginx
nginx支持多平台,RHEL/CentOS、Debian、Ubuntu、SLES、Alpine。
官方安装教程
官方文档
这里仅展示Linux的安装实例:
-
安装编译工具及库文件
使用命令行执行# yum -y install make zlib zliv-devel gc-c++ libtool openssl openssl-devel
-
安装PCRE
PCRE 为Nginx 提供Rewrite支持# 下载PCRE $ cd /usr/local/src/ $ wget http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz #解压安装包 $ tar zxvf pcre-8.35.tar.gz #进入安装目录 $ ./configure $ make && make install
-
安装Nginx
# 下载安装包
$ cd /usr/local/src/
$ wget http://nginx.org/download/nginx-1.17.10.tar.gz
#解压安装包
$ tar zxvf nginx-1.17.10.tar.gz
#进入安装目录
$ cd nginx-1.17.10
#编译与安装
# --with-http_stub_status_module 开启 状态查看http://localhost/nginx_status
# --with-http_ssl_module 实现ssl证书及 rewrite
$ ./configure --prefix=/usr/local/webserver/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre=/usr/local/src/pcre-8.35
#查看是否安装成功
$ /usr/local/src/nginx/sbin/nginx -v
# 如果显示版本信息则证明安装完成
nginx 配置实例
为nginx 创建一个www 用户(也可以自定义,这个用户是要配置在nginx.conf user项中)
# 创建一个nginx 专用user: www; group: www
$ groupadd www
$ useradd -g www www
Nginx配置项介绍
nginx.conf配置文件的格式有点像springboot的application.yml的层级结构,不过样式上是类似json用花括号{}
进行分级的。
每个配置项必须以;
为结束符。
每个配置项必须以;
为结束符。
每个配置项必须以;
为结束符。
nginx配置文件结构图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vffFrUBG-1590458667560)(https://s1.ax1x.com/2020/05/22/YXaNf1.md.png)]
举个官方例子:
#!nginx
user www www; #linux上申请的用户,主要绑定nginx的文件归属
worker_processes 4; #[ auto | int 推荐==cpu核心数] 每个进程平均消耗10~12M内存
pid /var/run/nginx.pid; #主进程保存文件
error_log /var/log/nginx.error_log info; #配置日志文件文件及规则[ debug | info | notice | warn | error | crit ]
worker_rlimit_nofile 51200; #文件描述符数量,Linux内核2.4以上可用
#工作模式与连接数上限
events {
worker_connections 2000; #工作进程的最大连接数量,默认:1024
use kqueue; #设定指定工作模式[ kqueue | epoll | /dev/poll | select | poll ],Linux内核2.6以上可用
}
#整体环境配置--网站配置
http {
include conf/mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型
#charset utf-8; #默认编码
#设置日志格式(下小节细说:)
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
client_header_timeout 3m; #定义用于读取客户端请求标头的超时。
client_body_timeout 3m; #定义用于读取客户端请求体的超时时间。
send_timeout 3m; #发送超时时间
client_header_buffer_size 1k; #上传文件大小限制
large_client_header_buffers 4 4k; #设定请求缓存
gzip on; #开启gzip压缩响应模式
gzip_min_length 1100; #设置将被压缩的响应的最小长度。
gzip_buffers 4 8k; #设置用于压缩响应的缓冲区的数量和大小。默认情况下,缓冲区大小等于一个内存页。4K或8K,这取决于一个平台。
gzip_types text/plain; #除了“text /html”之外,还可以对指定MIME类型的响应进行GZIP。特殊值“*”匹配任何MIME类型(0.8·29)。“text/html”类型的响应总是被压缩。
output_buffers 1 32k; #设置用于从磁盘读取响应的缓冲区的数量和大小
postpone_output 1460; #客户端的数据将被推迟发送,直到nginx需要发送的数据至少有1460字节
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
tcp_nopush on; #防止网络阻塞
tcp_nodelay on; #防止网络阻塞
send_lowat 12000; #如果该指令设置为非零值,则nginx将尝试通过使用kqueue方法的NOTE_LOWAT标志或SO_SNDLOWAT套接字选项来最小化客户端套接字上的发送操作的数量。在这两种情况下都使用指定的大小。
keepalive_timeout 75 20; #长连接超时时间,单位是秒
#lingering_time 30; #延迟时间
#lingering_timeout 10; #延迟超时时间
#reset_timedout_connection on;
server {
listen one.example.com; #设置监听IP的地址和端口
server_name one.example.com www.one.example.com; #设置服务器名称
access_log /var/log/nginx.access_log main;
location / {
proxy_pass http://127.0.0.1/; 代理地址
proxy_redirect off; #代理转发
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m; #客户端最大上传文件大小
client_body_buffer_size 128k; #.用于接收客户端请求报文的body部分的缓冲区大小;默认为16k;
client_body_temp_path /var/nginx/client_body_temp; #用于接收客户端请求报文的body部分的缓冲区大小;默认为16k;
proxy_connect_timeout 70; #代理连接超时时间
proxy_send_timeout 90; #代理发送超时时间
proxy_read_timeout 90; #代理读取超时时间
proxy_send_lowat 12000; #代理发送延迟
proxy_buffer_size 4k; #代理个缓存大小
proxy_buffers 4 32k; #该指令设置缓冲区的大小和数量,从被代理的后端服务器取得的响应内容,会放置到这里. 默认情况下,一个缓冲区的大小等于内存页面大小,可能是4K也可能是8K,这取决于平台。
proxy_busy_buffers_size 64k; #nginx会在没有完全读完后端响应就开始向客户端传送数据,所以它会划出一部分busy状态的buffer来专门向客户端传送数据(建议为proxy_buffers中单个缓冲区的2倍),然后它继续从后端取数据。
proxy_temp_file_write_size 64k; #设置同时写入临时文件的数据量的总大小。通常设置为8k或者16k。
proxy_temp_path /var/nginx/proxy_temp; #定义proxy的临时文件存在目录以及目录的层级。
charset koi8-r; #字符集
}
error_page 404 /404.html; #错误页面
location = /404.html { #请求匹配
root /spool/www; #错误页面存放根目录
}
location /old_stuff/ { #请求匹配
rewrite ^/old_stuff/(.*)$ /new_stuff/$1 permanent;
}
location /download/ { #请求匹配
valid_referers none blocked server_names *.example.com; # 限制有效的来源
if ($invalid_referer) {
#rewrite ^/ http://www.example.com/;
return 403;
}
#rewrite_log on;
# rewrite /download/*/mp3/*.any_ext to /download/*/mp3/*.mp3
rewrite ^/(download/.*)/mp3/(.*)\..*$
/$1/mp3/$2.mp3 break;
root /spool/www;
#autoindex on;
access_log /var/log/nginx-download.access_log download;
}
location ~* \.(jpg|jpeg|gif)$ {
root /spool/www;
access_log off;
expires 30d;
}
}
}
Nginx 日志配置
日志配置语法描述
语 法: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
默认值:access_log logs/access.log combined;
作用域:http, server, location, if in location, limit_except
示 例:access_log /usr/logs/nginx-example.log example buffer=32k;
格式化日志语法描述
语 法:log_format name [escape=default|json] string ...;
默认值:log_format combined "...";
作用域:http
示 例:log_format example '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
日志级别
debug > info > notice > warn > error > crit > alert > emerg
日志变量
日志配置项 | 描述 |
---|---|
remote_addr | 客户端IP地址 |
http_x_forwarded_for | 客户端IP地址 |
remote_user | 客户端用户名称 |
request | 请求的URL及请求头信息 |
status | 请求状态 |
body_bytes_sent | 发送给客户端的字节数,不包括响应头的大小 |
bytes_sent | 发送给客户端的总字节数 |
connection | 连接的序列号 |
connection_requests | 获取摸一个连接的请求数量 |
msec | 日志写入时间,单位s,精度SSS |
pipe | 是否是通过pipelined发送的请求,是:P,否:. |
http_referer | 记录请求来源 |
http_user_agent | 客户端浏览器信息 |
request_length | 请求长度,包括请求行,请求头和请求正文 |
request_time | 请求处理时间,单位为s,精度SSS |
time_iso8601 | 标准格式下的本地时间 |
time_local | 通用日志格式下的本地时间 |
Nginx location配置项
基本语法:
location [= |~|~*|^~|@] pattern{...}
基本语法 | 匹配规则 | 正确示例 | 错误示例 |
---|---|---|---|
server_name example.com; location /abc{ | 没有修饰符 以制定模式开始 | example.com/abc example.com/abcd example.com/abc/ | example.cn/abc |
server_name example.com; location = /abc | 指定模式精确匹配 | example.com/abc | example.com/abcd |
server_name example.com; location ~ ^/abc$ | 指定正则表达式 区分大小写 | example.com/abc | example.com/aBc |
server_name example.com; location ~* ^/abc$ | 指定正则表达式 不区分大小写 | example.com/abc example.com/aBc | example.com/abc/ example.com/abcde |
server_name example.com; location /abc | 以指定模式开始 如果模式匹配 那么就停止搜索其他模式了 | ||
server_name example.com; location /abc | 定义命名location区段 这些区段客户段不能访问 只可由内部产生的请求来访问 |
匹配的顺序及优先级
- 普通匹配命中,如果有多个命中,记录下来最长的命中结果。
- 精准匹配命中,如果命中,立即返回结果并结束解析过程。
- ^~的匹配命中,则不会继续搜索正则命中,但是会继续搜索一般命中。
- 继续判断正则表达式的解析结果,按配置里的正则表达式顺序为准,由上到下开始匹配,一旦匹配成功立刻返回结果,否则将返回匹配度最高的哪个location块处理。
location匹配流程图
gzip模块配置
压缩配置项 | 描述 |
---|---|
gzip on | 开启gzip压缩输出 |
gzip_min_length 1k | 设置最小压缩文件大小 |
gzip_bufferd 4 16k | 设置压缩缓冲区的数量和大小 |
gzip_http_version 1.0 | 设置压缩工具版本 |
gzip_comp_level 2 | 设置压缩等级 |
gzip_types text/plain application/x-javascript text/css application/xml | 压缩类型,默认包含text/html |
gzip_vary on | 设置HTTP头来判断,是否需要压缩 |
FastCGI模块
Fastcgi配置项 | 描述 |
---|---|
fastcgi_connect_timeout 300 | 连接超时时间 |
fastcgi_send_timeout 300 | 发送超时时间 |
fastcgi_read_timeout 300 | 读取超时时间 |
fastcgi_buffer_size 64k | 设置缓冲大小 |
fastcgi_buffers 4 64k | 设置缓冲的数量和大小 |
fastcgi_busy_buffers_size 128k | 设置繁忙缓冲大小,默认值是fastcgi_buffer的2倍 |
fastcgi_temp_file_write_size 128k | 写入缓存文件使用多大的数据块,默认值是fastcgi_buffer的2倍 |
fastcgi_cache TEST | 开启fastcgi缓存,并指定名称 |
fastcgi_cache_valid 200 302 1h fastcgi_cache_valid 301 1d fastcgi_cache_valid any 1m | 应答代码缓存时间 |
负载均衡配置
upstream example.com{
ip_hash;
server 192.168.1.11:80;
server 192.168.1.12:80 down;
server 192.168.1.13:8009 max_fails=3 fail_timeout=20s;
}
Nginx 的负载均衡算法:
- 轮询:名请求按时间顺序逐一分配到后端服务器上,如果某一台服务器宕机,则被踢出队列
- 权重:在后台服务器地址后制定weight值,数值越大,访问概率越高
- ip_hash:每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题
- fair:可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。需下载upstream_fair模块。
- url_hash:按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。需要下载hash软件包。
后台服务器路由属性设置
- down:下线,表示该 服务器不会通过负载均衡被访问
- backup:备用机,只有其他服务器均处于繁忙或故障状态才会被访问
- max_files:允许请求失败的次数。当超过最大次数时,返回proxy_next_upstream模块定义错误
- fail_timeout:满足最大失败次数后,暂停服务时间。
Tips: 当负载算法为ip_hash后,后端服务器的状态不能为weight/backup
来两个实验
nginx虚拟主机
a. 提前准备好两个域名,并规划好两个网站的网页存放目录
b.编写nginx主配置文件的两个虚拟主机
server{
listen 80;
server_name example1.com;
index index.html index.htm index.php;
root html/example1;
access_log logs/access_example1.log;
}
server{
listen 80;
server_name example2.com;
index index.html index.htm index.php;
root html/example2;
access_log logs/access_example2.log;
}
c.检查配置项nginx -t
,重启nginx
nginx反向代理
a.在另外一台机器上安装web服务。
b.再nginx 主配置文件的server模块内,添加location
server{
listen 80;
server_name example1.com;
index index.html index.htm index.php;
root html/example1;
access_log logs/access_example1.log;
location / {
proxy_pass http://www.baidu.com;
}
}
server{
listen 80;
server_name example2.com;
index index.html index.htm index.php;
root html/example2;
access_log logs/access_example2.log;
location / {
proxy_pass http://www.baidu.com;
}
}
c.检查配置项nginx -t
,重启nginx
nginx负载均衡
a. 设置几台服务器主机
b. 配置主配置文件的http模块
upstream example1{
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=2;
server 192.168.1.12:8080 weight=1;
}
c.检查配置项nginx -t
,重启nginx
nginx实现SSL证书+rewrite
a.安装nginx 的时候开启--with-http_ssl_module
模块
b.再nginx 主配置文件的server模块你添加ssl配置项
server{
...
ssl on;
ssl_certificate /usr/local/nginx/conf/ssl/example.crt;
ssl_certificate_key /usr/local/nginx/cong/ssl/example.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_crphers on;
ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
}
c、生成证书和秘钥文件
#在实验环境中可以用命令生成测试,在生产环境中必须要在 https 证书厂商注册
$ openssl genrsa -out example.key 1024
#建立服务器私钥,生成 RSA 密钥
$ openssl req -new -key atguigu.key -out example.csr
#需要依次输入国家,地区,组织,email。最重要的是有一个 common name,
#可以写你的名字或者域名。如果为了 https 申请,这个必须和域名吻合,否则会引发浏览器警报。
#生成的 csr 文件交给 CA 签名后形成服务端自己的证书
$ openssl x509 -req -days 365 -sha256 -in example.csr -signkey example.key -out example.crt
#将私钥和证书复制到指定位置
$ cp example.crt /usr/local/nginx/conf/ssl/example.crt
$ cp example.key /usr/local/nginx/conf/ssl/example.key
d.设置nginx主配置文件,http自动跳转https
server{
...
listen 443;
}
server{
listen 80;
server_name example.com;
rewrite ^(.*)& https://example.com permanent;
root html;
index index.html index.htm index.php;
}
e.检查配置项nginx -t
,重启nginx