nginx概述
简介
- NGINX是一个免费、开源、高性能、轻量级的HTTP和反向代理服务器,也是一个电子邮件(IMAP/POP3)代理服务器,其特点是占有内存少,并发能力强。 Nginx 因为它的稳定性、丰富的模块库、灵活的配置和较低的资源消耗而闻名 。目前应该是几乎所有项目建设必备。
- Nginx由内核和一系列模块组成,内核提供web服务的基本功能,如启用网络协议,创建运行环境,接收和分配客户端请求,处理模块之间的交互。
nginx衍生版本
- 开源版 nginx.org
- 商业版 NGINX Plus
- 淘宝网发起的Web服务器 Tengine
- 基于Nginx和Lua的Web平台 OpenResty
nginx的优缺点
- 优点:
- 占内存小,可实现高并发连接,处理响应快
- 可实现http服务器、虚拟主机、反向代理、负载均衡
- Nginx配置简单
- 可以不暴露正式的服务器IP地址
- 缺点: 动态处理差:nginx处理静态文件好,耗费内存少,但是处理动态页面则很鸡肋,现在一般前端用nginx作为反向代理抗住压力;
带着一些问题来探究
- 为什么要使用nginx?
- 为啥nginx性能这么高?
- nginx如何支持热部署的?
- 什么是正向代理和反向代理?
- nginx应用场景?
- nginx的高可用如何保证?
- …
Nginx安装
- liunx
- windows
注册自启动
liunx
#1.创建开机自启动服务文件 一般存放/etc/systemd/system/ 改目录下
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
#2相关指令
#保存重载systemctl
systemctl daemon-reload
#设置nginx服务开机自启动
systemctl enable nginx.service
#启动nginx服务
systemctl start nginx.service
#停止nginx服务
systemctl stop nginx.service
#重启nginx服务
systemctl restart nginx.service
#重新读取nginx配置(这个最常用, 不用停止nginx服务就能使修改的配置生效)
systemctl reload nginx.service
windows
- 下载Windows Service Wrapper
- 下载后将该工具放入Nginx的安装目录下,并且将其重命名为 nginx-service.exe ,在该目录下新建 nginx-service.xml 文件,写入配置信息,配置好了之后就可以通过这个将Nginx注册为Windows服务。
nginx-service.xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<service>
<id>nginx</id>
<name>nginx</name>
<description>nginx</description>
<executable>D:\nginx\nginx-1.21.5\nginx.exe</executable>
<logpath>D:\nginx-1.8.0</logpath>
<logmode>roll</logmode>
<depend></depend>
<startargument>-p D:\nginx\nginx-1.21.5</startargument>
<stopargument>-p D:\nginx\nginx-1.21.5 -s stop</stopargument>
</service>
- 以上内容配置好了之后,在nginx安装目录下以管理员运行命令:.\nginx-service.exe install 就成功将其注册为Windows服务了,然后运行 .\nginx-service.exe start 启动服务。这时我们可以在Windows任务管理器的服务中查看该是否成功启动。
- 相关指令
#注册对应的系统服务
nginx-service.exe install
#删除对应的系统服务
nginx-service.exe uninstall
#停止对应的系统服务
nginx-service.exe stop
#启动对应的系统服务
nginx-service.exe start
nginx的常用命令
nginx -s reload # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen # 重启 Nginx
nginx -s stop # 快速关闭
nginx -s quit # 等待工作进程处理完成后关闭
nginx -T # 查看当前 Nginx 最终的配置
nginx -t # 检查配置是否有问题
系统架构和nginx的原理
我们当前的系统架构(用户访问的请求流转)
nginx的原理
Nginx 启动之后,系统中有两个进程,一个为 master,一个为 worker。master 作为管理员不参与任何工作,只负责给多个 worker 分配不同的任务(worker 一般有多个)。
worker 是如何工作的?
客户端发送一个请求首先要经过 master,管理员收到请求后会将请求通知给 worker,多个 worker 以争抢的机制来抢夺任务,得到任务的 worker 会将请求经由 下层服务等做请求转发、反向代理、访问数据库等。
一个 master 和多个 worker 的好处?
- 可以使用 nginx -s reload 进行热部署。
- 每个 worker 是独立的进程,如果其中一个 worker 出现问题,其它 worker 是独立运行的,会继续争抢任务,实现客户端的请求过程,而不会造成服务中断。
设置多少个 worker 合适?
Nginx 和 redis 类似,都采用了 io 多路复用机制(epoll模型),每个 worker 都是一个独立的进程,每个进程里只有一个主线程,通过异步非阻塞的方式来处理请求,每个 worker 的线程可以把一个 cpu 的性能发挥到极致,因此,worker 数和服务器的 cpu 数相等是最为适宜的。
realod的重载原理:
- 向 master 进程发送 HUP 信号( reload 命令);
- master 进程检查配置语法是否正确;
- master 进程打开监听端口;
- master 进程使用新的配置文件启动新的 worker 子进程;
- master 进程向老的 worker 子进程发送 QUIT 信号;
- 老的 worker 进程关闭监听句柄,处理完当前连接后关闭进程;
- 整个过程 Nginx 始终处于平稳运行中,实现了平滑升级,用户无感知;
nginx几个核心概念
正向和反向代理
正向代理:
-
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
-
正向代理是为我们服务的,即为客户端服务的,客户端可以根据正向代理访问到它本身无法访问到的服务器资源。
-
正向代理对我们是透明的,对服务端是非透明的,即服务端并不知道自己收到的是来自代理的访问还是来自真实客户端的访问。
反向代理:
-
反向代理是为服务端服务的,反向代理可以帮助服务器接收来自客户端的请求,帮助服务器做请求转发,负载均衡等。
-
反向代理对服务端是透明的,对我们是非透明的,即我们并不知道自己访问的是代理服务器,而服务器知道反向代理在为他服务。
-
反向代理的优势:
- 隐藏真实服务器;
- 负载均衡便于横向扩充后端动态服务;
- 动静分离,提升系统健壮性;
正反项代理图解:
负载均衡
负载均衡(Load Balance),意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。
nginx负载均衡方式:
- 轮询
轮询方式是Nginx负载默认的方式,顾名思义,所有请求都按照时间顺序分配到不同的服务上,如果服务Down掉,可以自动剔除,如下配置后轮训8080服务和8081服务。
upstream geek-server {
server localhost:8080;
server localhost:8081;
}
- 加权轮询
指定每个服务的权重比例,weight和访问比率成正比,通常用于后端服务机器性能不统一,将性能好的分配权重高来发挥服务器最大性能,如下配置后8080服务的访问比率会是8081服务的二倍。
upstream geek-server {
server localhost:8080 weight=2;
server localhost:8081 weight=1;
}
- **ip_hash **
每个请求都根据访问ip的hash结果分配,经过这样的处理,每个访客固定访问一个后端服务,如下配置(ip_hash可以和weight配合使用)。
upstream geek-server {
ip_hash;
server localhost:8080 weight=2;
server localhost:8081 weight=1;
}
- least_conn 最少连接
将请求分配到连接数最少的服务上。
upstream geek-server {
least_conn;
server localhost:8080 weight=2;
server localhost:8081 weight=1;
}
- fair
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream geek-server{
fair;
server localhost:8080 weight=2;
server localhost:8081 weight=1;
}
- hash
- random
动静态分离
动态与静态页面区别
静态资源: 当用户多次访问这个资源,资源的源代码永远不会改变的资源(如:HTML,JavaScript,CSS,img等文件)。
**动态资源:**当用户多次访问这个资源,资源的源代码可能会发送改变(如:.jsp、servlet 等)。
什么是动静分离
- 动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。
- 动静分离简单的概括是:动态文件与静态文件的分离。
为什么要用动静分离
使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。
为了加快网站的解析速度,可以把动态资源和静态资源用不同的服务器来解析,加快解析速度。降低单个服务器的压力。
nginx的核心配置
nginx目录结构
liunx下的:
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf # Nginx所有配置文件的目录
│ ├── fastcgi.conf # fastcgi相关参数的配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的原始备份文件
│ ├── fastcgi_params # fastcgi的参数文件
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒体类型
│ ├── mime.types.default
│ ├── nginx.conf # Nginx主配置文件
│ ├── nginx.conf.default
│ ├── scgi_params # scgi相关参数文件
│ ├── scgi_params.default
│ ├── uwsgi_params # uwsgi相关参数文件
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp # fastcgi临时数据目录
├── html # Nginx默认站点目录
│ ├── 50x.html # 错误页面优雅替代显示文件,例如当出现502错误时会调用此页面
│ └── index.html # 默认的首页文件
├── logs # Nginx日志目录
│ ├── access.log # 访问日志文件
│ ├── error.log # 错误日志文件
│ └── nginx.pid # pid文件,Nginx进程启动后,会把所有进程的ID号写到此文件
├── proxy_temp # 临时目录
├── sbin # Nginx命令目录
│ └── nginx # Nginx的启动命令
├── scgi_temp # 临时目录
└── uwsgi_temp # 临时目录
配置文件结构
Nginx 的典型配置示例:
# main段配置信息
user nginx; # 运行用户,默认即是nginx,可以不进行设置
worker_processes auto; # Nginx 进程数,一般设置为和 CPU 核数一样
error_log /var/log/nginx/error.log warn; # Nginx 的错误日志存放目录
pid /var/run/nginx.pid; # Nginx 服务启动时的 pid 存放位置
# events段配置信息
events {
use epoll; # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
worker_connections 1024; # 每个进程允许最大并发数
}
# http段配置信息
# 配置使用最频繁的部分,代理、缓存、日志定义等绝大多数功能和第三方模块的配置都在这里设置
http {
# 设置日志模式
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; # 减少网络报文段的数量
tcp_nodelay on;
keepalive_timeout 65; # 保持连接的时间,也叫超时时间,单位秒
types_hash_max_size 2048;
include /etc/nginx/mime.types; # 文件扩展名与类型映射表
default_type application/octet-stream; # 默认文件类型
include /etc/nginx/conf.d/*.conf; # 加载子配置项
# server段配置信息
server {
listen 80; # 配置监听的端口
server_name localhost; # 配置的域名
# location段配置信息
location / {
root /usr/share/nginx/html; # 网站根目录
index index.html index.htm; # 默认首页文件
deny 172.168.22.11; # 禁止访问的ip地址,可以为all
allow 172.168.33.44;# 允许访问的ip地址,可以为all
}
error_page 500 502 503 504 /50x.html; # 默认50x对应的访问页面
error_page 400 404 error.html; # 同上
}
}
- main 全局配置,对全局生效;
- events 配置影响 Nginx 服务器与用户的网络连接;
- http 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置;
- server 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块;
- location 用于配置匹配的 uri ;
- upstream 配置后端服务器具体地址,负载均衡配置不可或缺的部分;
nginx.config的结构
main # 全局配置,对全局生效
├── events # 配置影响 Nginx 服务器或与用户的网络连接
├── http # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置
│ ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│ ├── server # 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块
│ ├── server
│ │ ├── location # server 块可以包含多个 location 块,location 指令用于匹配 uri
│ │ ├── location
│ │ └── ...
│ └── ...
└── ...
用一张图清晰的展示它的层级结构:
配置文件 main 段核心参数
参数 | 代码块 | 描述 |
---|---|---|
user | user nginx lion; | 指定运行 Nginx 的 woker 子进程的属主和属组,其中组可以不指定。 |
pid | pid /opt/nginx/logs/nginx.pid # master主进程的的pid存放在nginx.pid的文件 | 指定运行 Nginx master 主进程的 pid 文件存放路径。 |
worker_rlimit_nofile_number | worker_rlimit_nofile 20480; # 可以理解成每个worker子进程的最大连接数量。 | 指定 worker 子进程可以打开的最大文件句柄数。 |
worker_rlimit_core | worker_rlimit_core 50M; # 存放大小限制 working_directory /opt/nginx/tmp; # 存放目录 | 指定 worker 子进程异常终止后的 core 文件,用于记录分析问题。 |
worker_processes_number | worker_processes 4; # 指定具体子进程数量 worker_processes auto; # 与当前cpu物理核心数一致 | 指定 Nginx 启动的 worker 子进程数量。 |
worker_cpu_affinity | worker_cpu_affinity 0001 0010 0100 1000; # 4个物理核心,4个worker子进程 | 将每个 worker 子进程与我们的 cpu 物理核心绑定。 |
worker_priority | worker_priority -10; # 120-10=110,110就是最终的优先级 | 指定 worker 子进程的 nice 值,以调整运行 Nginx 的优先级,通常设定为负值,以优先调用 Nginx 。 |
worker_shutdown_timeout | worker_shutdown_timeout 5s; | 指定 worker 子进程优雅退出时的超时时间。 |
timer_resolution | timer_resolution 100ms; | worker 子进程内部使用的计时器精度,调整时间间隔越大,系统调用越少,有利于性能提升;反之,系统调用越多,性能下降。 |
daemon | daemon off; # 默认是on,后台运行模式 | 指定 Nginx 的运行方式,前台还是后台,前台用于调试,后台用于生产。 |
配置文件 events 段核心参数
参数 | 代码块 | 描述 |
---|---|---|
use | use method; # 不推荐配置它,让nginx自己选择 | Nginx 使用何种事件驱动模型。 method 可选值为:select、poll、kqueue、epoll、/dev/poll、eventport |
worker_connections | worker_connections 1024 # 每个子进程的最大连接数为1024 | worker 子进程能够处理的最大并发连接数。 |
accept_mutex | accept_mutex on # 默认是off关闭的,这里推荐打开 | 是否打开负载均衡互斥锁。 |
server_name 指令
指定虚拟主机域名。
server_name name1 name2 name3
# 示例:
server_name www.geekproxy.com;
域名匹配的四种写法:
- 精确匹配: server_name www.nginx.com ;
- 左侧通配: server_name *.nginx.com ;
- 右侧统配: server_name www.nginx.* ;
- 正则匹配: server_name ~^www.nginx.*$ ;
匹配优先级:精确匹配 > 左侧通配符匹配 > 右侧通配符匹配 > 正则表达式匹配
root
指定静态资源目录位置,它可以写在 http 、 server 、 location 等配置中。
location /image {
root /opt/nginx/static;
}
# 当用户访问 www.test.com/image/1.png 时,实际在服务器找的路径是/opt/nginx/static/image/1.png
[注意] root 会将定义路径与 URI 叠加, alias 则只取定义路径。
alias
它也是指定静态资源目录位置,它只能写在 location 中。
location /image {
alias /opt/nginx/static/image/;
}
#当用户访问 www.test.com/image/1.png 时,实际在服务器找的路径是 /opt/nginx/static/image/1.png
**[注意] **使用 alias 末尾一定要添加 / ,并且它只能位于 location 中。
location
配置路径。
location [ = | ~ | ~* | ^~ ] uri { ... }
匹配规则:
- = 精确匹配;
- ~ 正则匹配,区分大小写;
- ~* 正则匹配,不区分大小写;
- ^~ 匹配到即停止搜索;
匹配优先级: = > ^~ > ~ > ~* > 不带任何字符。
实例:
server {
listen 80;
server_name www.geekproxy.com;
# 只有当访问 www.geekproxy.com/match_all/ 时才会匹配到/usr/share/nginx/html/match_all/index.html
location = /match_all/ {
root /usr/share/nginx/html
index index.html
}
# 当访问 www.geekproxy.com/1.jpg 等路径时会去 /usr/share/nginx/images/1.jpg 找对应的资源
location ~ \.(jpeg|jpg|png|svg)$ {
root /usr/share/nginx/images;
}
# 当访问 www.geekproxy.com/bbs/ 时会匹配上 /usr/share/nginx/html/bbs/index.html
location ^~ /bbs/ {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
location 中的反斜线
location /test {
...
}
location /test/ {
...
}
- 不带 / 当访问 www.geekproxy.com/test 时, Nginx 先找是否有 test 目录,如果有则找 test 目录下的 index.html ;如果没有 test 目录, nginx 则会找是否有 test 文件。
- 带 / 当访问 www.geekproxy.com/test 时, Nginx 先找是否有 test 目录,如果有则找 test 目录下的 index.html ,如果没有它也不会去找是否存在 test 文件。
return
停止处理请求,直接返回响应码或重定向到其他 URL ;执行 return 指令后, location 中后续指令将不会被执行。
return code [text];
return code URL;
return URL;
例如:
location / {
return 404; # 直接返回状态码
}
location / {
return 404 "pages not found"; # 返回状态码 + 一段文本
}
location / {
return 302 /bbs ; # 返回状态码 + 重定向地址
}
location / {
return https://www.baidu.com ; # 返回重定向地址
}
rewrite
根据指定正则表达式匹配规则,重写 URL 。
语法:rewrite 正则表达式 要替换的内容 [flag];
上下文:server、location、if
示例:rewirte /images/(.*\.jpg)$ /pic/$1; # $1是前面括号(.*\.jpg)的反向引用
**flag 可选值的含义:
- last 重写后的 URL 发起新请求,再次进入 server 段,重试 location 的中的匹配;
- break 直接使用重写后的 URL ,不再匹配其它 location 中语句;
- redirect 返回302临时重定向;
- permanent 返回301永久重定向;
server{
listen 80;
server_name www.geekproxy.com; # 要在本地hosts文件进行配置
root html;
location /search {
rewrite ^/(.*) https://www.baidu.com redirect;
}
location /images {
rewrite /images/(.*) /pics/$1;
}
location /pics {
rewrite /pics/(.*) /photos/$1;
}
location /photos {
}
}
按照这个配置我们来分析:
- 当访问 www.geekproxy.com/search 时,会自动帮我们重定向到 https://www.baidu.com。
- 当访问 www.geekproxy.com/images/1.jpg 时,第一步重写 URL 为 www.geekproxy.com/pics/1.jpg ,找到 pics 的 location ,继续重写 URL 为 www.geekproxy.com/photos/1.jpg ,找到 /photos 的 location 后,去 html/photos 目录下寻找 1.jpg 静态资源。
if 指令
语法:if (condition) {...}
上下文:server、location
示例:
if($http_user_agent ~ Chrome){
rewrite /(.*)/browser/$1 break;
}
condition 判断条件:
- $variable 仅为变量时,值为空或以0开头字符串都会被当做 false 处理;
- = 或 != 相等或不等;
- ~ 正则匹配;
- ! ~ 非正则匹配;
- ~* 正则匹配,不区分大小写;
- -f 或 ! -f 检测文件存在或不存在;
- -d 或 ! -d 检测目录存在或不存在;
- -e 或 ! -e 检测文件、目录、符号链接等存在或不存在;
- -x 或 ! -x 检测文件可以执行或不可执行;
实例:
server {
listen 8080;
server_name localhost;
root html;
location / {
if ( $uri = "/images/" ){
rewrite (.*) /pics/ break;
}
}
}
当访问 localhost:8080/images/ 时,会进入 if 判断里面执行 rewrite 命令。
autoindex
用户请求以 / 结尾时,列出目录结构,可以用于快速搭建静态资源下载网站。
autoindex.conf 配置信息:
server {
listen 80;
server_name www.autoindex.com;
location /download/ {
alias D:/nginx/nginx-1.21.5/logs/;
autoindex on; # 打开 autoindex,可选参数有 on | off
autoindex_exact_size on; # 修改为off,以KB、MB、GB显示文件大小,默认为on,以bytes显示出⽂件的确切⼤⼩
autoindex_format html; # 以html的方式进行格式化,可选参数有 html | json | xml
autoindex_localtime off; # 显示的⽂件时间为⽂件的服务器时间。默认为off,显示的⽂件时间为GMT时间
}
}
当访问 www.autoindex.com/download/ 时,会把服务器D:/nginx/nginx-1.21.5/logs/ 路径下的文件展示出来,如下图所示:
变量
Nginx 提供给使用者的变量非常多,但是终究是一个完整的请求过程所产生数据, Nginx 将这些数据以变量的形式提供给使用者。
下面列举些项目中常用的变量:
变量名 | 含义 |
---|---|
remote_addr | 客户端 IP 地址 |
remote_port | 客户端端口 |
server_addr | 服务端 IP 地址 |
server_port | 服务端端口 |
server_protocol | 服务端协议 |
binary_remote_addr | 二进制格式的客户端 IP 地址 |
connection | TCP 连接的序号,递增 |
connection_request | TCP 连接当前的请求数量 |
uri | 请求的URL,不包含参数 |
request_uri | 请求的URL,包含参数 |
scheme | 协议名, http 或 https |
request_method | 请求方法 |
request_length | 全部请求的长度,包含请求行、请求头、请求体 |
args | 全部参数字符串 |
arg_参数名 | 获取特定参数值 |
is_args | URL 中是否有参数,有的话返回 ? ,否则返回空 |
query_string | 与 args 相同 |
host | 请求信息中的 Host ,如果请求中没有 Host 行,则在请求头中找,最后使用 nginx 中设置的 server_name 。 |
http_user_agent | 用户浏览器 |
http_referer | 从哪些链接过来的请求 |
http_via | 每经过一层代理服务器,都会添加相应的信息 |
http_cookie | 获取用户 cookie |
request_time | 处理请求已消耗的时间 |
https | 是否开启了 https ,是则返回 on ,否则返回空 |
request_filename | 磁盘文件系统待访问文件的完整路径 |
document_root | 由 URI 和 root/alias 规则生成的文件夹路径 |
limit_rate | 返回响应时的速度上限值 |
实例演示 var.conf :
server{
listen 80;
server_name www.geekproxy.cn;
location / {
return 200 "
remote_addr: $remote_addr
remote_port: $remote_port
server_addr: $server_addr
server_port: $server_port
server_protocol: $server_protocol
binary_remote_addr: $binary_remote_addr
connection: $connection
uri: $uri
request_uri: $request_uri
scheme: $scheme
request_method: $request_method
request_length: $request_length
args: $args
arg_pid: $arg_pid
is_args: $is_args
query_string: $query_string
host: $host
http_user_agent: $http_user_agent
http_referer: $http_referer
http_via: $http_via
request_time: $request_time
https: $https
request_filename: $request_filename
document_root: $document_root
";
}
}
Nginx 的配置还有非常多,以上只是罗列了一些常用的配置,在实际项目中还是要学会查阅文档。
当我们访问 http://www.geekproxy.cn/test?pid=1231&cid=321 时,由于 Nginx 中写了 return 方法,因此 chrome 浏览器会默认为我们下载一个文件,下面展示的就是下载的文件内容:
remote_addr: 127.0.0.1
remote_port: 58300
server_addr: 127.0.0.1
server_port: 80
server_protocol: HTTP/1.1
binary_remote_addr:
connection: 11
uri: /test
request_uri: /test?pid=1231&cid=321
scheme: http
request_method: GET
request_length: 455
args: pid=1231&cid=321
arg_pid: 1231
is_args: ?
query_string: pid=1231&cid=321
host: www.geekproxy.cn
http_user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
http_referer:
http_via:
request_time: 0.000
https:
request_filename: D:\nginx\nginx-1.21.5/html/test
document_root: D:\nginx\nginx-1.21.5/html
Nginx 的配置还有非常多,以上只是罗列了一些常用的配置,在实际项目中还是要自行查阅相关文档。
nginx的应用场景
- 解决跨域访问
eg:
前端 server 的域名为: geek.proxy1.com
后端服务的域名为: geek.proxy2.com
现在我在 geek.proxy1.com 对 geek.proxy2.com 发起请求一定会出现跨域。
现在我们只需要启动一个 Nginx 服务器,将 server_name 设置为 geek.proxy1.com 然后设置相应的 location 以拦 截前端需要跨域的请求,最后将请求代理回 geek.proxy2.com 。如下面的配置:
server {
listen 80;
server_name geek.proxy1.com ;
location / {
proxy_pass geek.proxy2.com ;
}
}
- 适配PC与移动环境
location / {
# 移动、pc设备适配
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
set $mobile_request '1';
}
if ($mobile_request = '1') {
rewrite ^.+ http://geekproxy-H5.com;
}
}
- ** HTTP 请求转发到 HTTPS**
server {
listen 80;
server_name geek.proxy.com;
# 单域名重定向
if ($host = 'geek.proxy.com'){
return 301 https://geek.proxy.com$request_uri;
}
# 全局非 https 协议时重定向
if ($scheme != 'https') {
return 301 https://$server_name$request_uri;
}
# 或者全部重定向
return 301 https://$server_name$request_uri;
# 以上配置选择自己需要的即可,不用全部加
}
- 泛域名路径分离
经常有时候我们可能需要配置一些二级或者三级域名,希望通过 Nginx 自动指向对应目录,比如:
test1.doc.geekproxy.com自动指向 /usr/share/nginx/html/doc/test1 服务器地址;
test2.doc.geekproxy.com 自动指向 /usr/share/nginx/html/doc/test2 服务器地址;
server {
listen 80;
server_name ~^([\w-]+)\.doc\..geekproxy\.com$;
root /usr/share/nginx/html/doc/$1;
}
- 泛域名转发
和之前的功能类似,有时候我们希望把二级或者三级域名链接重写到我们希望的路径,让后端就可以根据路由解析不同的规则:
test1.serv.geekproxy.com/api?name=a 自动转发到 127.0.0.1:8080/test1/api?name=a ;
test2.serv.geekproxy.com/api?name=a 自动转发到 127.0.0.1:8080/test2/api?name=a ;
server {
listen 80;
server_name ~^([\w-]+)\.serv\.geekproxy\.com$;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:8080/$1$request_uri;
}
}
- 静态服务
server {
listen 80;
server_name www.autoindex.com;
charset utf-8; # 防止中文文件名乱码
location /download/ {
alias D:/nginx/nginx-1.21.5/logs/; # 静态资源目录
autoindex on; # 开启静态资源列目录
autoindex_exact_size off; # on(默认)显示文件的确切大小,单位是byte;off显示文件大概大小,单位KB、MB、GB
autoindex_localtime off; # off(默认)时显示的文件时间为GMT时间;on显示的文件时间为服务器时间
}
}
- 图片防盗链
server {
listen 80;
server_name *.geekproxy.com;
# 图片防盗链
location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked server_names ~\.google\. ~\.baidu\. *.geekproxy.com; # 只允许本机 IP 外链引用,百度和谷歌也加入白名单
if ($invalid_referer){
return 403;
}
}
}
- 请求过滤
# 非指定请求全返回 403
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 403;
}
location / {
# IP访问限制(只允许IP是 192.168.0.2 机器访问)
allow 192.168.0.2;
deny all;
root html;
index index.html index.htm;
}
- 配置图片、字体等静态文件缓存
由于图片、字体、音频、视频等静态文件在打包的时候通常会增加了 hash,所以缓存可以设置的长一点,先设置强制缓存,再设置协商缓存;如果存在没有 hash 值的静态文件,建议不设置强制缓存,仅通过协商缓存判断是否需要使用缓存。
# 图片缓存时间设置
location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ {
expires 10d;
}
# 如果不希望缓存
expires -1;
- 合并请求(第三方模块)
前端性能优化中重要一点就是尽量减少http资源请求的数量。通过nginx-http-concat模块(淘宝开发的第三方模块,需要单独安装)用一种特殊的请求url规则(例子:example.com/??1.js,2.js,3.js ),前端可以将多个资源的请求合并成一个请求,后台Nginx会获取各个资源并拼接成一个结果进行返回。例如上面的例子通过一个请求将1.js,2.js,3js三个js资源合并成一个请求,减少了浏览器开销。 本地server geekproxy.com为例,static/js文件夹下有三个文件,文件内容很简单,分别为:
#1.js
console.log('1');
#2.js
console.log('2');
#3.js
console.log('3');
# js资源http-concat
# nginx-http-concat模块的参数远不止下面三个,剩下的请查阅文档
location /static/js/ {
concat on; # 是否打开资源合并开关
concat_types application/javascript; # 允许合并的资源类型
concat_unique off; # 是否允许合并不同类型的资源
concat_max_files 5; # 允许合并的最大资源数目
}
- 图片处理(第三方模块)
在前端开发中,经常需要不同尺寸的图片。现在的云储存基本对图片都提供有处理服务(一般是通过在图片链接上加参数)。其实用Nginx,可以通过几十行配置,搭建出一个属于自己的本地图片处理服务,完全能够满足日常对图片的裁剪/缩放/旋转/图片品质等处理需求。要用到ngx_http_image_filter_module模块。这个模块是非基本模块,需要安装。 下面是图片缩放功能部分的Nginx配置:
# 图片缩放处理
# 这里约定的图片处理url格式:以 mysite-base.com/img/路径访问
location ~* /img/(.+)$ {
alias /Users/cc/Desktop/server/static/image/$1; #图片服务端储存地址
set $width -; #图片宽度默认值
set $height -; #图片高度默认值
if ($arg_width != "") {
set $width $arg_width;
}
if ($arg_height != "") {
set $height $arg_height;
}
image_filter resize $width $height; #设置图片宽高
image_filter_buffer 10M; #设置Nginx读取图片的最大buffer。
image_filter_interlace on; #是否开启图片图像隔行扫描
error_page 415 = 415.png; #图片处理错误提示图,例如缩放参数不是数字
}
- 页面内容修改(第三方模块)
- 配置开启 gzip 压缩
- …
最佳实践建议
-
为了使 Nginx 配置更易于维护,建议为每个服务创建一个单独的配置文件,存储在 /etc/nginx/conf.d 目录,根据需求可以创建任意多个独立的配置文件。
-
独立的配置文件,建议遵循以下命名约定 <服务>.conf,比如域名是 geekproxy.com,那么你的配置文件的应该是这样的 /etc/nginx/conf.d/geekproxy.com.conf,如果部署多个服务,也可以在文件名中加上 Nginx 转发的端口号,比如 geekproxy.com.8080.conf,如果是二级域名,建议也都加上 a.geekproxy.com.conf。
-
常用的、复用频率比较高的配置可以放到 /etc/nginx/snippets 文件夹,在 Nginx 的配置文件中需要用到的位置 include 进去,以功能来命名,并在每个 snippet 配置文件的开头注释标明主要功能和引入位置,方便管理。
-
Nginx 日志相关目录,内以 域名.type.log 命名(比如 geekproxy.com.access.log 和 geekproxy.com.error.log )位于 /var/log/nginx/ 目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。
nginx的一些线上问题总结(真实案例我们遇到过的)
dns缓存问题
- 问题出现的原因,提供公共上传服务的项目因升级其注册中心,同时更换了起SLB的负载机器便于管理;
- 切换了api.newrank.cn对应的解析域名到新的负载机器上
- 调用方因存在跨域问题所以均采用nginx做了一次代理转到api.newrank.cn的域名上;
- 出现问题的时候所以的上传服务均在报405的问题,理论上405应该是存在请求方式问题才会报,随即排查问题,尝试从业务提供方去排查问题,看提供服务或者是上游的负载均衡或者是nginx代理是否存在问题,排查许久尝试切换会原有的负载SLB,发现还是存在上述问题,尝试重启调用方的nginx发现问题得到解决
- 解决问题传送门
301转向https,POST请求问题:
通过301永久重定向hhtps 所以的请求方式均会被替换为GET请求,对于一些接口请求如果只支持POST则可能报405等异常;
磁盘临近爆满导致的代理大文件报错
某一台nginx所在服务器因磁盘爆满导致代理的某些大文件(js,css)无法被加载报错。
循环重定向500问题
进阶版深入了解
Nginx 的内部结构是由核心部分和一系列的功能模块所组成。这样划分是为了使得每个模块的功能相对简单,便于开发,同时也便于对系统进行功能扩展。Nginx 的模块是互相独立的,低耦合高内聚。
如果还想深入了解直接去撸源码。