背景
现在大一点规模的公司都有自己的运维工程师,基于现在的架构体系,前端部署在哪,后端部署在哪,运维会设计对应的部署架构体系,故其实前端很多时候不需要过多关注前端代码怎么部署的,甚至也很少去关注,甚至很多时候前端同学只需要耕耘好自己的一亩三分地,也能干活,也能产出赋能。前端更多时候是与客户端即浏览器打交道,也会遇到很多Nginx导致的相关问题,例如跨域的代理问题,虽然遇到这类问题,可以抛给相应的运维甚至后端同学去解决,但是前端遇到这类问题,也不能干瞪眼什么也不知道啊,至少需要能够排查出问题吧。作为一个合格的研发,要知其然也知其所以然。甚至很多中小型公司,具体工种细分没有那么清晰,需要前端同学自己去搞CI/CD,去分环境自动打包部署,这个时候就需要前端同学必须熟悉Nginx了,主动学习才能进步。
什么是Nginx?
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。
Nginx的作用
可以做以下事情:
- 解决跨域(反向代理)
- 负载均衡
- 动静分离
- 请求过滤
- 配置gzip
- 静态资源服务器
- 流量整形
- 高速缓存
- 安全控制
Nginx具有以下特点:
- 更快:单次请求响应更快;
- 高拓展性:设计极具扩展性,有多个不同功能、不同层次、不同类型且耦合度极低的模块组成;
- 高可靠性:很多流量网站都在核心服务器上大规模使用Nginx;
- 低内存消耗:一般1万个非活跃的HTTP Keep-Alive连接在Nginx中仅消耗2.5MB内存;
- 高并发:单机支持10万以上的并发连接数;
- 热部署:master管理进程与worker工作进程的分离设计,使得Nginx能够支持热部署;
- 开源协议:使用BSD许可协议(还有什么协议?),免费使用,且可修改源码;
应用场景
-
HTTP服务器
Nginx本身是一个静态资源服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,例如当一个网 站只有静态页面的话,就可以通过这种方式来实现部署;
-
静态资源服务
静态服务器,通常会提供一个上传的功能,其他应用如果需要静态资源就可以从该静态服务器中获取。 (即动静分离的应用?)
-
反向代理服务器
反向代理(Reverse Proxy)方式是指代理服务器来接受Internet上的来自客户端的连接请求,然后 将该请求转给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此 时代理服务器对外就表现为一个反向代理服务器。
-
负载均衡
负载均衡也是Nginx常用的一个功能,负载均衡的意思是分摊到多个操作单元上进行执行,例如将服务器 分为多类型服务器,Web服务器、FTP服务器(是什么服务器?)、企业关键应用服务器和其他关键任 务服务器等,从而共同完成工作任务。
-
动静分离
动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好 拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思想。
正向代理与反向代理
代理是在客户端与目标服务器之间架设的一层服务器,代理将接受客户端的请求并将它转发给目标服务器,然后将目标服务器的响应转发给客户端。
不管是正向代理还是反向代理,实现的都是上面的功能。
正向代理
正向代理服务器是一个位于客户端和目标服务器之间的服务器,为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。
即正向代理中目标服务器并不知道访问它的真实用户是谁,因为和它交互的是代理服务器。
例:比如我们访问国外的YouTube、Facebook等网站,就是通过代理服务器实现的,这个就是正向代理的过程。
反向代理
正向代理中目标服务器不知道用户是谁,反向代理中则相反,是用户不知道目标服务器是谁。
用户将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器并获取数据后,再返回给客户端,这个过程中用户并不知道真正的请求发送到哪台服务器上了。
使用反向代理,目标服务器可以对客户端隐藏目标服务器 IP 地址。
反向代理的作用
- 防火墙的作用:当你的应用不想直接暴露给客户端(即客户端无法直接通过请求访问真正的服务器,只能通过Nginx,这样通过Nginx就可以过滤掉无权限或者非法的请求,来保障内部服务器的安全。)
- 负载均衡:本质上负载均衡就是反向代理的一种应用场景,可以通过nginx将接收到的客户端请求"均匀地"分配到这个集群中所有的服务器上(具体看负载均衡方式),从而实现服务器压力的负载均衡
反向代理的设置
示例:我们通过模拟内部服务器的端口启动的nodejs项目设置反向代理到80端口访问,配置如下:
// nginx.config
server {
listen: 80;
server_name localhost
location / {
proxy_pass http://127.0.0.1:8000;(upstream)
}
}
在 Nginx 反向代理是,会通过 location 功能匹配指定的 URI,然后把接收到的符合匹配 URI的请求通过 proxy_pass 转移给之前定义好的 upstream 节点池
负载均衡
上面提到了正向代理和反向代理,负载均衡就是反向代理的应用。
当一个应用单位时间内访问量激增,服务器的带宽及性能收到影响,影响大到自身承受能力时,服务器就会宕机崩溃,为了防止这种现象发生,以及实现更好的用户体验,我们可以通过配置Nginx负载均衡的方式来分担服务器压力。
这就是集群的概念,单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器上,即负载均衡。
当有一台服务器宕机时,负载均衡器就分配其他的服务器给用户,极大的增加网站的稳定性,当用户访问web时,首先访问的是负载均衡器,在通过负载均衡器将请求转发给后台服务器。
负载均衡的几种常见策略
负载均衡常用的有以下几种策略,分别是:轮询策略(Nginx默认方式)、权重策略 weight、最小连接数策略 least_conn、客户端ip绑定 ip_hash、最快响应时间策略 fair(第三方)、url_hash(第三方)
轮询策略(默认)
将所有客户端请求轮询分配给服务端。这种策略是可以正常工作的,但是如果其中某一台服务器压力太大,出现延迟,会影响所有分配在这台服务器下的用户。配置示例如下:
// nginx.config
upstream balanceServer {
server 192.168.0.1;
server 192.168.0.2;
}
权重策略 weight
指定不同ip的权重,权重与访问比成正相关,权重越高,访问越大,适用于不同性能的机器。配置示例如下:
// nginx.config
upstream balanceServer {
server 192.168.0.1 weight=2;
server 192.168.0.2 weight=8;
}
最小连接数策略 least_conn
把请求分配给连接数较少的后端服务器,它可以平衡每个队列的长度,并避免向压力大的服务器添加更多的请求。配置示例如下:
// nginx.config
upstream balanceServer {
least_conn;
server 10.1.22.33:12345;
server 10.1.22.34:12345;
server 10.1.22.35:12345;
}
客户端ip绑定 ip_hash
来自同一个ip的请求永远只分配一台服务器,有效解决了动态网页存在的session共享问题。配置示例如下:
// nginx.config
upstream balanceServer {
ip_hash;
server 10.1.22.33:12345;
server 10.1.22.34:12345;
server 10.1.22.35:12345;
}
最快响应时间策略 fair(第三方)
会将请求优先分配给相应最快的服务器,这种方式需要依赖到第三方插件 nginx-upstream-fair
,需要先安装。配置示例如下:
// nginx.config
upstream balanceServer {
fair;
server 10.1.22.33:12345;
server 10.1.22.34:12345;
server 10.1.22.35:12345;
}
url_hash(第三方)
// nginx.config
upstream balanceServer {
hash $request_uri;
server 192.168.244.1:8080;
server 192.168.244.2:8080;
server 192.168.244.3:8080;
server 192.168.244.4:8080;
}
健康检查
Nginx自带ngx_http_upstream_module(健康检测模块)本质上是服务器心跳的检查,通过定期轮询向集群里的服务器发送健康检查请求,来检查集群中是否有服务器处于异常状态。
如果检查到其中某台服务器异常,那么在通过客户端请求nginx反向代理进来的都不会被发送到该服务器上(直到下次轮询健康检查正常为止)。配置示例如下:
upstream backserver {
server 192.168.0.1 max_fails=1 fail_timeout=40s;
server 192.168.0.2 max_fails=1 fail_timeout=40s;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend;
}
}
涉及到两个配置:
fail_timeout
:设定服务器被认为不可用的时间段以及统计失败尝试次数的时间段,默认为10s。max_fails
:设定Nginx与服务器通信的尝试失败的次数,默认为:1次。
https服务
Nginx常用来配置Https认证,主要两个步骤:签署第三方可信任的SSL证书和配置HTTPS。
签署第三方可信任的SSL:
配置HTTPS要用到私钥example.key文件和example.crt证书文件,申请证书文件时要用到example.csr文件。
更多SSL证书:SSL证书介绍
Nginx配置https
要开启https服务,在配置文件信息块(server),使用监听命令listen的ssl参数,即监听443端口,定义服务器证书文件(SSL证书文件)和私钥文件,基本配置示例如下:
server {
# ssl参数
listen 443 ssl;//监听443端口,因为443端口是https的默认端口。80为http的默认端口
server_name example.com
# 证书文件
ssl_certification example.com.crt
# 私钥文件
ssl_certification_key example.com.key
}
- ssl_certification:证书的绝对路径
- ssl_certification_key:私钥的绝对路径
静态资源服务器
Nginx可以作为静态资源服务器,可以提供一个上传功能,这样其他的应用如果需要静态资源就可以从该静态资源服务器中获取。
配置示例如下:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location ~* .(png|gif|jpg|jpeg)$ {
expires 30d; # 设置过期时间为30天
add_header Cache-Control "public";
autoindex on;
access_log off;
try_files $uri $uri/ /index.php$is_args$args;
}
}
上面示例场景为:匹配以png|gif|jpg|jpeg
为结尾的请求,并将请求转发到本地路径,root
中指定的路径即nginx本地路径。同时也可以做一些缓存的设置。
基于此,可以做动静分离
。
动静分离
在Nginx配置动静分离时,需要将静态资源和动态资源分别放在不同的服务器中,并通过Nginx的反向代理功能
将请求转发到相应的服务器。具体步骤如下:
在Nginx配置文件中,添加如下配置:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
location / {
# 缓存配置,可根据实际情况调整
expires 30d # 设置有效期
add_header Cache-Control "public, max-age=7200";
}
}
在Nginx配置文件中,添加如下配置:
server {
listen 80;
server_name dynamic.example.com;
location / {
proxy_pass http://127.00.1:8000; # 动态资源服务器地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
其中,proxy_pass
指定动态服务器的地址,proxy_set_header
用于设置请求头;
3. 配置反向代理
在nginx配置文件中,添加如下配置:
server {
listen 80;
server_name www.example.com;
location /static/ {
# 静态资源请求转发到静态资源服务器
proxy_pass http://static.example.com/;
}
location / {
# 动态资源请求转发到动态资源服务器
proxy_pass http://dynamic.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
其中,location /static/
指定静态资源的请求路径,proxy_pass
用于转发请求。
4. 重启nginx服务
完成以上配置后,需要重启nginx服务,使配置生效。
通过以上配置,可以实现nginx的动静分离,提高网站的性能和稳定性。需要注意的是,静态资源和动态资源的分离应该根据实际情况进行调整,以达到最佳的性能和用户体验。
适配PC与移动环境
场景如下:当用户从移动端打开PC端baidu.com的场景时,将自动跳转指定移动端m.baidu.com,本质上是Nginx可以通过内置变量$http_user_agent
,获取到请求客户端的userAgent,从而知道当前用户使用的终端是移动端还是PC,进而针对性的重定向到H5网站还是PC网站。
示例代码如下:
server {
location / {
# 移动端、PC端agent获取
if ($http_user_agent ~* '(Android|webOS|iPhone)') {
set $mobile_request '1';
}
if ($mobile_request = '1') {
rewrite ^.+ http://m.baidu.com
}
}
}
配置gzip(静态文件压缩)
gzip是网页压缩的一种方式,经过gzip压缩后,网页大小可以变为原来的30%甚至更小,这样客户端需要加载的静态资源就更小,从而可以节约大量的带宽,提高传输效率,响应速度更快,会让用户浏览的体验更好。
server{
gzip on; # 于开启或 关闭gzip模块
gzip_buffers 32 4K; # 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。
gzip_comp_level 6; # 压缩级别,1-10,数字越大压缩的越好,压缩级别越高压缩率越大,压缩时间越长。
gzip_min_length 100; # 设置允许压缩的页面最小字节数,页面字节数从相应消息头的Content-length中进行获取。
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]."; # IE6对Gzip不友好,对Gzip(可以通过该指令对一些特定的User-Agent不使用压缩功能)
gzip_proxied on: # 用于设置启用或禁用从代理服务器上收到相应内容gzip压缩。
gzip_http_version 1.1; # 识别HTTP协议版本,其值可以是 1.1 或 1.0
gzip_proxied : off; # 用于设置启用或禁用从代理服务器上收到相应内容gzip压缩。
gzip_vary on; # 用于在响应消息头中添加Vary:Accept-Encoding,使代理服务器根据请求头中的Accept-Encoding识别是否启用gzip压缩。
}
解决跨域问题的配置
当出现403跨域报错或者No 'Access-Control-Allow-Origin' header is present on the requested resource
报错等,需要给Nginx服务器配置相应的header参数:
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Cpntrol-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Alive,X-Requseted-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
IP白名单(访问权限控制)
可以配置 nginx 白名单,规定哪些ip可以访问服务器,防爬虫必备。
- 简单配置
server {
location / {
deny 192.168.0.1; //禁止该ip访问
deny all; //禁止所有访问
}
}
- 白名单配置
建立白名单
vim /etc/nginx/white_ip.conf
...
192.168.0.1 1;
...
修改nginx配置(nginx.conf)
geo $remote_addr $ip_whitelist {
default 0;
include ip.conf;
}
// geo 指令主要是可以根据指定变量的值映射出一个新变量。如果不指定变量,默认为$remote_addr
为匹配项做白名单设置
server {
location / {
if ($ip_whitelist = 0) {
return 403; // 不在白名单内返回403
}
index index.html;
root /tmp;
}
}
请求过滤
根据状态码过滤
error_page 500 501 502 503 504 506 /50.html;
location = /50.html {
#将跟路径改编为存放html的路径
root /root/static/html;
}
根据URL名称过滤,精准匹配URL,不匹配的URL全部重定向到主页
location / {
rewrite ^.*$ /index.html redirect;
}
根据请求类型过滤
if ($request_method !~ ^(GET|POST|HEAD)$) {
return 403;
}
防盗链
可以防止资源被其他网站调用
location ~* .(gif|jpg|png)$ {
# 只允许 192.168.0.1 请求资源
valid_referers none blocked 192.168.0.1;
if ($invalid_referer) {
rewrite ^/ http://$host/logo.png;
}
}
根据文件类型设置过期时间
location ~.*.css$ {
expires 1d;
break;
}
location ~.*.js$ {
expires 1d;
break;
}
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
access_log off;
expires 15d; #保存15天
break;
}
# curl -x127.0.0.1:80 http://www.test.com/static/image/common/logo.png -I #测试图片的max-age
禁止文件缓存
开发环境经常改动代码,由于浏览器缓存需要强制刷新才能看到效果,我们可以通过禁止浏览器缓存来提高效率
location ~* .(js|css|png|jpg|gif)$ {
add_header Cache-Control no-store;
}
怎么安装Nginx?
点此进入官网
安装
- 可以选择 Stable version 版本下载到本地,下载完成后直接在本地解压后放入 linux 系统中;
- 或者可以直接在linux环境中使用命令下载,安装步骤如下:
首先可以买一台云服务器,我买的是华为云的,系统是CentOS,所以自带yum命令,登录服务器后直接执行以下命令:
# 进入
# 安装依赖包
yum install nginx
安装完成后,可以通过以下命令查看安装在哪:
whereis nginx
启动nginx服务,直接运行以下命令:
# 可以直接启动nginx服务
nginx
通过以下命令查看nginx状态:
ps -ef | grep nginx
出现master 则启动成功。
关闭命令:
kill -9 8011
(8011为上面查看nginx状态所得)则关闭nginx。
停止nginx命令:
nginx -s stop
重启nginx命令:
nginx -s reload
nginx启动状态时,在浏览器访问服务器的ip,会出现nginx欢迎页面,但是我的服务器却访问不了,可能有如下原因:
- 华为云ECS服务器默认不开启80端口,直接访问存在问题。需要进入华为官网云控制台中安全组添加(入规则:80),我们可以去配置安全组
添加入规则如下:
通过命令查看,可以确认Nginx已经启动并监听了80端口
netstat -anp | grep :80
添加后可以访问CentOS系统
如果访问不通,可能有以下原因:
- 华为云默认开启了防火墙,linux防火墙禁止访问80端口
检测防火墙开启的命令如下:
firewall-cmd --query-port=80/tcp
我的服务器显示:
防火墙未开启。
如果真是被防火墙禁止访问,可以有以下两种操作:
我现在防火墙是关闭状态,我要做的是打开防火墙,然后在防火墙列表添加80端口,步骤如下:
- 使用命令查询防火墙状态:
systemctl status firewalld
dead
状态即防火墙未开启。
- 开启防火墙
# 开启防火墙
systemctl start firewalld
# 查看防火墙状态
systemctl status firewalld
running
状态即防火墙开启了。
此时再执行以下命令:
firewall-cmd --query-port=80/tcp
显示如下:
通过ip访问系统已经访问不通了。
添加80端口,命令如下:
firewall-cmd --permanent --add-port=80/tcp
success
代表成功。
修改配置后重新启动才生效:
firewall-cmd --reload
如果想关闭防火墙,命令如下:
systemctl stop firewalld
上面通过ip访问的是CentOS页面,原因是nginx.conf中指向的就是CentOS的欢迎页面
所以Nginx已经安装成功并启动。
Nginx配置
nginx的默认配置文件通常是/etc/nginx/nginx.conf
,我们跳到/etc/nginx
目录中执行cat nginx.conf
可以查看配置文件的内容,部分内容如下:
user root;
...
http {
...
server {
listen 80; # 默认在80端口启动nginx服务
listen [::]:80;
server_name _; # 绑定的域名
root /usr/share/nginx/html; # 根目录,会加载这个目录下的html文件
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf; # 可以引入其他配置文件
location / { # 访问服务器跟路径
}
error_page 404 /404.html; # 访问的时候路径404
location = /40x.html { # 404时访问的html
}
error_page 500 502 503 504 /50x.html; # 服务器内部错误
location = /50x.html { # 5xx时访问的html
}
}
}
上面的配置的意思是我们访问服务的80端口时会自动加载/usr/share/nginx/html
目录下的html文件。
切换到/usr/share/nginx/html
目录下,修改其中的index.html
如下:
DOCTYPE html>
Hello nginx
nginx!
修改完后执行nginx -s reload
重启命令,然后刷新页面,页面就变成如下所示: