前言
在最近的一年里,或多或少地接触了一些nginx相关的知识,每次在项目中使用的时候都是针对某一个特定的场景去认识nginx,导致了回过头来再看nginx还是显得那么陌生,归根结底还是因为没有系统地去梳理nginx相关的知识点,在脑海里没有能形成一个系统的概念。所以我决定花些时间,去将平时零碎的知识点梳理完整。
什么是nginx?
Nginx是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡。
这篇文章可以结合我的上一篇《使用jenkins持续集成 vue项目实现自动化部署》文章进行了解,在上一篇中涉及到了在实际开发过程中nginx的一种使用方式。
一、快速搭建
登录进入服务器,查看yum源是否存在
yum list | grep nginx
看到如下图所示,表示yum源是存在的,且默认的源仅支持1.1.12nginx版本(我这里已经替换了原先默认的源)。
如果不存在或者不是我们需要的版本,可以重新配置nginx的yum源。
vim /etc/yum.repos.d/nginx.repo
将以下代码复制到上面打开的文件中。
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/
gpgcheck=0
enabled=1
其中 “OS” 替换成 “centos”,“OSRELEASE” 替换成 “7”。这里根据个人情况修改对应的操作系统和版本号。
如果不确定系统信息的同学,可以执行cat /etc/redhat-release
命令进行查看。
保存并退出后,再次执行上面查看yum源的命令,即可看到更新后的yum源的信息了,下面就可以安装nginx了。
#安装nginx
yum install nginx
#查看nginx版本
nginx -v
这里看到正常打印了nginx的版本,说明Nginx就安装成功啦。
二、基本配置文件
要想了解nginx,那我们就必须知道nginx有哪些文件,这些文件都装在了哪些目录。执行下面的命令打印所有nginx相关的目录,基础常用的一些文件目录如下图所示。
#rpm是linux的包管理工具,-q 表示查询程序是否安装,-l 表示返回包的list
rpm -ql nginx
1. nginx.conf文件解读
#打开nginx.conf
vim /etc/nginx/nginx.conf
#指定nginx的工作进程的用户及用户组
user nginx;
#指定工作进程的个数,默认是1个,具体可以根据服务器cpu数量进行设置,如果不知道cpu的数量,可以设置为auto
worker_processes 1;
#全局错误日志,error_log <FILE> <LEVEL>
#错误级别有六种[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log warn;
#进程pid文件存放位置
pid /var/run/nginx.pid;
#工作模式及连接数上限
events {
#参考事件模型,use [ select | poll | kqueue | epoll | rtsig | /dev/poll | eventport ]
use epoll;
#epoll是多路复用IO(I/O Multiplexing)中的一种方式,仅用于linux2.6以上内核,可以大大提高nginx的性能 use epoll;
#单个后台worker process进程的最大并发链接数
worker_connections 1024;
# 并发总数是 worker_processes 和 worker_connections 的乘积
# 即 max_clients = worker_processes * worker_connections
# 在设置了反向代理的情况下,max_clients = worker_processes * worker_connections / 4
# 为什么上面反向代理要除以4,应该说是一个经验值
# 根据以上条件,正常情况下的Nginx Server可以应付的最大连接数为:4 * 8000 = 32000
# worker_connections 值的设置跟物理内存大小有关
# 因为并发受IO约束,max_clients的值须小于系统可以打开的最大文件数
# 而系统可以打开的最大文件数和内存大小成正比,一般1GB内存的机器上可以打开的文件数大约是10万左右
# 我们来看看360M内存的VPS可以打开的文件句柄数是多少:
# $ cat /proc/sys/fs/file-max
# 输出 34336
# 32000 < 34336,即并发连接总数小于系统可以打开的文件句柄总数,这样就在操作系统可以承受的范围之内
# 所以,worker_connections 的值需根据 worker_processes 进程数目和系统可以打开的最大文件总数进行适当地进行设置
# 使得并发总数小于操作系统可以打开的最大文件数目
# 其实质也就是根据主机的物理CPU和内存进行配置
# 当然,理论上的并发总数可能会和实际有所偏差,因为主机还有其他的工作进程需要消耗系统资源。
}
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; #nginx访问日志存放位置
sendfile on; #开启高效传输模式
#tcp_nopush on; #减少网络报文段的数量
#设置长连接的超时时间,单位是秒
keepalive_timeout 65;
#gzip on; #开启gzip压缩,降低带宽使用和加快传输速度,但增加了CPU的使用
include /etc/nginx/conf.d/*.conf; #包含的子配置项位置和文件
}
2. default.conf文件解读
一般我们的子配置项文件都存放在 “/etc/nginx/conf.d” 目录下。
#打开default.conf
vim /etc/nginx/conf.d/default.conf
server {
listen 80; #监听端口
server_name localhost; #设置访问域名,多个域名用空格隔开即可
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html; #服务器默认启动路径
index index.html index.htm; #默认访问文件
}
#error_page 404 /404.html; #设置404页面
# redirect server error pages to the static page /50x.html
# 将错误页面重定向到50x.html
error_page 500 502 503 504 /50x.html; #错误状态码的显示页面
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
三、Nginx服务的启动、停止与重启
1. 启动nginx服务
systemctl start nginx.service
查看是否启动成功,看到如下图打印的信息则表示已经成功启动了nginx。尝试访问外网IP,看看是否能正常打开nginx的欢迎页面。如果未能正常打开,确认服务器的80端口是否开启。
#ps 查看进程的命令
#a 显示终端上的所有进程,包括其他用户的进程
#u 以用户为主的格式来显示程序状况
#x 显示所有程序,不以终端机来区分
#grep 表示全局正则表达式版本,它的使用权限是所有用户。
ps aux | grep nginx
补充:
当我们不清楚端口使用情况的时候,可以通过下面的命令查看端口号的占用情况。
netstat -tlnp
aliyun服务器端口开启方式:
1. 登录进入aliyun控制台,并找到当前使用的ECS实例。
2. 进入”安全组列表”,选择配置规则。
3. 选择添加安全组规则,配置如下。
4. 配置完成,点击确定即可。
2. 停止nginx服务
#systemctl 停止
systemctl stop nginx.service
#killall 杀死进程
killall nginx
3. 重启nginx服务
systemctl restart nginx.service
4. mac下启动 nginx 服务
brew services start nginx
四、Nginx访问设置
1. 设置错误页面
打开nginx子默认配置文件 “default.conf”
vim /etc/nginx/conf.d/default.conf
error_page指令用于设置错误页面,如下图所示。500、502、503、504这些是常见的HTTP的错误代码,/50x.html用于当发生上述指定的任意一个错误的时候,使用网站根目录下的/50x.html进行处理。这里通过location = /50x.html进行匹配,最终用户看到的错误页面为 “/usr/share/nginx/html” 目录下的 50x.html页面。
设置格式:error_page ...
2. 权限指令deny和allow
deny,设置禁止访问的IP
#禁止IP:123.123.123.123访问
location / {
deny 123.123.123.123;
}
#禁止所有IP访问
location / {
deny all;
}
allow,设置允许访问的IP
#只允许IP:123.123.123.123访问
location / {
allow 123.123.123.123;
}
#允许所有IP访问
location / {
allow all;
}
deny和allow的优先级
nginx的权限指令是从上往下执行的,在同一个块下deny和allow指令同时存在时,谁先匹配谁就会起作用,后面的权限指令就不会执行了。如下图,如果 “deny 111.111.111.111” 触发了,那它后面的两条都不会触发。
location / {
deny 111.111.111.111;
allow 222.222.222.222;
deny 333.333.333.333;
}
其实他们的关系就像 “if...else if...else if”,谁先触发,谁起作用。
if (deny 111.111.111.111) {...}
else if (allow 222.222.222.222) {...}
else if (deny 333.333.333.333) {...}
3. location详解
语法规则:
# = 开头表示精准匹配
# ~ 大小写敏感# ~* 忽略大小写
# ^~ 只需匹配uri开头
# @ 定义一个命名的 location,在内部定向时使用,例如 error_page
location [ = | ~ | ~* | ^~ ] /uri/ { ... }
location @name { ... }
1. 任意匹配
# 匹配所有请求,但是正则和最长字符串会优先匹配
location / {
#规则
}
2. “=” 精准匹配
# 精确匹配 / ,可以匹配类似 `http://www.example.com/` 这种请求,'/'后不能带有任何内容
location = / {
#规则
}
3. “~” 大小写敏感
location ~ /Test/ {
#规则
}
#可以匹配 http://www.test.com/Test/#不可以匹配 http://www.test.com/test/
4. “~*” 大小写忽略
# ~* 会忽略uri部分的大小写
location ~* /Test/ {
#规则
}
#可以匹配
#可以匹配 http://www.test.com/test/
5. “^~” 只匹配uri开头
#以 /test/ 开头的请求,都可以匹配上
location ^~ /test/ { #规则
}
#可以匹配 http://www.test.com/test/
6. “@” 定义一个命名的 location,在内部定向时使用,例如 error_page
#以 /img/ 开头的请求,如果链接的状态为 404。则会匹配到 @img_err 这条规则上。
location /img/ {
error_page 404 @img_err;
}
location @img_err {
# 规则
}
7. 以某内容结尾
# 匹配所有以 gif,jpg或jpeg 结尾的请求
location ~* \.(gif|jpg|jpeg)$ {
#规则
}
总结
location匹配顺序:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ,* 正则顺序) > (location 部分起始路径) > (/)
五、Nginx设置虚拟主机
1. 基于端口号
进入 “/etc/nginx/conf.d” 目录下,创建配置文件。
vim 8001.conf
输入以下内容(设置的监听端口号,确保是在服务器的安全组中打开了的),保存并退出。
server {
listen 8001; #监听8001端口
server_name localhost;
location / {
root /usr/share/nginx/html; #设置访问路径
index html8001.html; #默认文件
}
}
进入设置的访问路径,添加html8001.html文件,重启nginx。
systemctl restart nginx.service
访问 “http://外网IP:8001” 就可以看到我们新添加的html8001.html页面啦
2. 基于IP
通过IP设置虚拟主机,需要我们在拥有多个IP的情况下,将上面(1.基于端口)的server配置中的“server_name localhose” 改成 “server_name IP(对应的IP地址)”,保存并重启nginx。
3. 基于域名
先将要配置的域名进行解析(这样才能将域名和IP关联),再将上面(1.基于端口)的server配置中的“server_name localhose” 改成 “server_name 域名(对应的域名)”,保存并重启nginx。
六、Nginx反向代理
1. 理解正向代理和反向代理
- 正向代理
为了从目标服务器(图一中的Server)获取内容,客户端(图一中的Client)向代理服务器(图一中的Proxy)发送请求并指定目标,然后代理服务器向目标服务器转交客户端的请求并将获得的内容返回给客户端。这个过程就是正向代理。
例如 ”科学上网“
我们不能直接访问国外的某些网站,但是可以通过访问代理服务器,然后代理服务器从目标网站中获取数据并返回给我们。
类比 ”租房“
身份:租客(客户端)、中介(代理服务器)和房东(目标服务器)
租客想要租房子,但是租客无法联系到房东。所以这里租客就主动引入了中介,租客通过中介,租到了房东的房子。(”主动引入中介“ 即 主动配置代理)
- 反向代理
代理服务器(图二 Proxy)接受客户端(图二 Client)的请求,然后将请求转发给被代理的服务器(图二Server)。Proxy从Server上获取到请求结果并返回给Client,此时代理服务器对外就表现为一个反向代理服务器。
类比 ”租房“
身份:租客(客户端)、二房东/亲戚/中介(代理服务器)和房东(目标服务器)
”租客“ 直接找到 ”二房东/亲戚/中介“ 想要租房子, ”二房东/亲戚/中介“ 代替 ”房东“ 将房子租给了 ”租客“,这样的过程就是反向代理。(这里租客其实并不清楚,”二房东/亲戚/中介“ 是否是房子真正的主人,房子是一个被代理的结果。)
- 总结
正向代理,Proxy代理的是客户端Client,代替客户端Client去和服务器Server交互;
反向代理,Proxy代理的是服务器Server,代替服务器Server去和客户端Client交互。
(在区分正向代理和反向代理的时候,一定要分清到底是谁代理的谁。)
2. Nginx设置反向代理
打开 ”8001.conf“ 配置文件
vim /etc/nginx/conf.d/8001.conf
修改配置如下
# 将 ”http://IP:8001“ 代理到 ”https://www.baidu.com/“
server {
listen 8001;
server_name localhost;
location / {
proxy_pass https://www.baidu.com/
}
}
保存并退出,重启nginx后,访问 ”http://IP:8001“
从上图我们可以看到,虽然我们访问的地址是 ”http://IP:8001“,但显示的内容却是百度。这个时候我们的反向代理就算是设置成功了(这里和重定向是不一样的)。
3. 反向代理常用指令
补充:
#设置代理地址
proxy_pass https://www.baidu.com/
#设置请求头-并将头信息传递到服务器端,不属于请求头的参数中也需要传递时,重定义下即可
proxy_set_header Host $host:$server_port; #服务器名称和端口一起通过代理服务器传递
#配置nginx与代理服务器尝试建立连接的超时时间,单位秒
proxy_connect_timeout 300
#设置与代理服务器的读超时时间,单位秒
proxy_read_timeout 300
#配置服务器数据回传时间,单位秒
proxy_send_timeout 300
#指定修改被代理服务器返回的响应头中的location头域跟refresh头域数值
proxy_redirect off
七、Nginx适配PC端和移动端
在某些情况下,访问一个网站需要区分PC端和移动端(不是靠自适应来实现的,而是分开编写的方式)。那我们就可以通过nginx提供的内置变量 “$http_user_agent” ,获取到客户端的 “userAgent” 来判断用户目前是处于PC端还是移动端,从而实现展示不同的页面给用户。
进入 ”/usr/share/nginx“ 目录下,创建两个文件夹 ”pc“ 和 ”mobile“。
vim /usr/share/nginx
mkdir pc
mkdir mobile
在pc文件夹下,分别创建index.html。
vim /usr/share/nginx/pc/index.html
输入以下内容
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>pc</title>
</head>
<body>
<h1>pc 这是移动端的页面</h1>
</body>
</html>
mobile文件的操作方式和pc文件一致,只要index.html中的内容方便区分pc和mobile即可。
打开 ”8001.conf“ 配置文件。
vim /etc/nginx/conf.d/8001.conf
配置修改,保存退出后重启nginx。
server{
listen 8001;
server_name localhost;
location / {
root /usr/share/nginx/pc;
#if里的判断条件可以根据实际需求进行修改
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
root /usr/share/nginx/mobile;
}
index index.html;
}
}
访问 ”http://IP:8001”,打开浏览器的调试功能,分别看一下pc端和移动端下的展示情况,如下图所示即配置成功。
八、Gzip压缩
gzip是网页的一种压缩技术,经过gzip压缩后,页面大小可以变为原来的30%甚至更小。gzip网页压缩的实现需要浏览器和服务器的支持,实际上就是服务器端压缩,传到浏览器后浏览器解压并解析。
gzip的配置说明
#是否开启gzip模块,on表示开启,off表示关闭
gzip on;
#设置允许压缩的页面最小字节(从header头的Content-Length中获取)
gzip_min_length 1k;
#设置gzip申请内存的大小,其作用是按块大小的倍数申请内存空间,param2:int(k) 后面单位是k。
#这里设置以16k为单位,按照原始数据大小以16k为单位的4倍申请内存
#如果没有设置,默认值是申请跟原始数据相同大小的内存空间去存储gzip压缩结果
gzip_buffers 4 16k;
#识别http协议的版本
gzip_http_version 1.1;
#设置gzip压缩等级,等级越底压缩速度越快文件压缩比越小,反之速度越慢文件压缩比越大
#等级1-9,9 压缩比最大但处理最慢(传输快但比较消耗cpu)
gzip_comp_level 2;
#设置需要压缩的MIME类型,非设置值不进行压缩,即匹配压缩类型
gzip_types text/plain application/x-javascript text/css application/xml;
#用于在响应消息头中添加Vary:Accept-Encoding
#使代理服务器根据请求头中的Accept-Encoding识别是否启用gzip压缩
gzip_vary on;
打开nginx全局配置文件
vim /etc/nginx/nginx.conf
设置gzip压缩
http {
...
gzip on;
gzip_types text/plain text/html application/javascript text/css;
...
}
为了方便看出设置gzip压缩后的效果,百度搜索 “网页Gzip压缩检测” ,分别记录压缩前和压缩后的检测结果。
设置前
设置后
从两张图中可以看到,设置前和设置后的差距还是挺大的。
同时,设置gzip压缩后,我们在浏览器调试工具可以看到HTTP响应头的信息中,“Content-Encoding” 为gzip类型。
此时就说明我们成功开启了gzip压缩。
文中若有问题和不足之处欢迎指正,不胜感激,谢谢~
点个赞再走吧(#^.^#)~