NGINX 是一个免费的,开源的,高性能的 HTTP 服务器和反向代理,以及 IMAP / POP3 代理服务器。 NGINX 以其高性能,稳定性,丰富的功能集,简单的配置和低资源消耗而闻名。
概述
为方便描述,下文简称 NGX。
虽然 NGINX
市场占有率并不占有绝对优势,但是对比其他 WEB
服务器还是有很大优势。
- 作为网页服务器:相比
Apache
,NGINX
使用更少的资源,支持更多的并发连接(能够支持高达50000
个并发连接数的响应),静态页面处理性能比Apache
高3
倍以上,但对动态内容支持较弱,需要其他依赖进行实现,并且组件不如Apache
丰富。 - 作为负载均衡服务器:相比
Perlbal
,NGINX
既可以在内部直接支持Rails
和PHP
程序对外进行服务, 也可以支持作为HTTP
代理服务器对外进行服务。采用C
语言进行编写,不论是系统资源开销还是CPU
使用效率都要好很多。
其他优势
NGINX
配置相对简洁,启动过程迅速,服务宕机可能性低,并且支持服务平滑升级。Apache
是同步多进程模型,一个连接对应一个进程;NGINX
是异步的,多个连接(万级别)对应一个进程。NGINX
的优势是处理静态请求,CPU
内存使用率低,Apache
适合处理动态请求,所以一般前端用NGINX
作为反向代理抗住压力,Apache
作为后端处理动态请求。
NGINX 部署
支持发行版
官方预编译版本支持以下发行版
RHEL/CentOS
版本 | 支持的平台 |
---|---|
6 | x86_64, i386 |
7 | x86_64, ppc64le |
8 | x86_64 |
Debian
版本 | 代号 | 支持的平台 |
---|---|---|
6 | squeeze | x86_64, i386 |
7 | wheezy | x86_64, i386 |
8 | jessie | x86_64, i386 |
9 | stretch | x86_64, i386 |
10 | buster | x86_64, i386 |
Ubuntu
版本 | 代号 | 支持的平台 |
---|---|---|
14.04 | trusty | x86_64, i386, aarch64/arm64 |
16.04 | xenial | x86_64, i386, ppc64el, aarch64/arm64 |
18.04 | bionic | x86_64 |
19.04 | disco | x86_64 |
SLES
版本 | 支持的平台 |
---|---|
12 | x86_64 |
15 | x86_64 |
Alpine
版本 | 支持的平台 |
---|---|
3.8 | x86_64 |
3.9 | x86_64 |
3.10 | x86_64 |
安装说明
RHEL/CentOS
安装基础包
sudo yum install yum-utils
导入官方源
sudo vim /etc/yum.repos.d/nginx.repo
插入以下内容
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
小贴士:默认情况下会安装stable
分支,若要启用mainline
分支,请执行下述命令。
sudo yum-config-manager --enable nginx-mainline
安装 NGINX
sudo yum install nginx
Debian
安装基础包
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring
设置软件仓库
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
若想使用 mainline
分支,请执行
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
导入官方密钥
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
配置仓库权重,使用官方仓库,而不是发行版仓库
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
安装 NGINX
sudo apt update && sudo apt install nginx
Ubuntu
安装基础包
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
设置软件仓库
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
注意:因Ubuntu 18.04
彻底移除了x86
架构的支持,因此需要加入[arch=amd64]
只检索amd64
,否则会有报错信息。
若想使用 mainline
分支,请执行
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
导入官方密钥
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
配置仓库权重,使用官方仓库,而不是发行版仓库
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
安装 NGINX
sudo apt update && sudo apt install nginx
软件包来源校验
存储库都使用数字签名来验证下载软件包的来源与完整性(是否被篡改)。检查校验签名,则需要下载官方签名密钥将其导入系统密钥池。
在 Debian
或 Ubuntu
中不导入密钥会报以下错误:
W: GPG error: http://nginx.org/packages/ubuntu bionic InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY ABF5BD827BD9BF62
E: The repository 'http://nginx.org/packages/ubuntu bionic InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
也可以使用以下命令导入密钥:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABF5BD827BD9BF62
注意:后面的密钥串ABF5BD827BD9BF62
应替换为错误信息中的数值。
NGINX 模块
自动索引模块
ngx_http_autoindex_module
官方文档:点击跳转
配置模板:
location / {
root html;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}
语法:
autoindex on/off;
默认参数:off
字段位置:http, server, location
参数:
autoindex_exact_size off; # 单位换算
# 可选参数:on | off ,默认 on 单位为 byte,off 换算为 kB,MB,GB
autoindex_localtime on; # 时间格式
# 可选参数:on |off ,默认 off 显示的文件时间为GMT时间。on 显示的文件时间为文件的服务器时间。
charset utf-8,gbk; # 字符集设置
# 可选参数:UTF-8 | GBK | GB2312 ,添加GBK后即可解决中文乱码
autoindex_format html; # 网页格式
# 可选参数: html | xml | json | jsonp ,默认 html 。
状态监测模块
ngx_http_stub_status_module
官方文档:点击跳转
配置模板:
location = /basic_status {
stub_status;
}
语法:
stub_status;
默认参数: —
字段位置:server, location
访问限制模块
ngx_http_access_module
官方文档:点击跳转
配置模板:
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
deny all;
}
语法:
allow address | CIDR | unix: | all;
默认参数: —
字段位置:http, server, location, limit_except
用户认证模块
ngx_http_auth_basic_module
官方文档:点击跳转
配置模板
location / {
auth_basic "closed site";
auth_basic_user_file conf/htpasswd;
}
语法:
auth_basic string | off;
默认: off
auth_basic_user_file file;
字段位置:http, server, location, limit_except
注意:密码文件需严格按照以下格式进行生成。密码文件名可使用变量。
# comment
name1:password1
name2:password2:comment
name3:password3
生成密码可以使用 Apache 工具包中的小工具进行生成
sudo yum install httpd-tools
sudo htpasswd -c /etc/nginx/auth_conf password
连接限制模块
ngx_http_limit_conn_module
官方文档:点击跳转
配置模板1:
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
...
server {
...
location /download/ {
limit_conn addr 1;
}
配置模板2:
http {
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
...
server {
...
limit_conn perip 10;
limit_conn perserver 100;
}
语法:
limit_conn zone number;
默认: —
字段位置:http, server, location
日志:
limit_conn_log_level info | notice | warn | error;
默认:error;
字段位置:http, server, location
状态:
limit_conn_status code;
默认:503;
字段位置:http, server, location
请求限制模块
ngx_http_limit_req_module
官方文档:点击跳转
配置模板:
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
...
server {
...
location /search/ {
limit_req zone=one burst=5;
}
语法:
limit_req zone=name [burst=number] [nodelay];
默认: —
字段位置:http, server, location
示例用法:
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
location /search/ {
limit_req zone=one burst=5;
}
说明:允许每秒平均不超过 1 个请求,并发不超过 5 个请求。
如果不希望在请求受限的情况下拒绝过多的请求,则应使用以下参数来推迟多余的请求:
limit_req zone=one burst=5 nodelay;
日志:
limit_req_log_level info | notice | warn | error;
默认: error;
字段位置:http, server, location
状态:
limit_req_status code;
默认: 503;
字段位置:http, server, location
日志记录模块
ngx_http_log_module
官方文档:点击跳转
NGINX
提供完备的日志记录功能,此模块可以深度定义日志格式,便于筛选可用信息。
配置模板:
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
access_log /spool/logs/nginx-access.log compression buffer=32k;
语法:
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
日志变量详解:
$remote_addr, $http_x_forwarded_for # 记录客户端IP地址
$remote_user # 记录客户端用户名称
$request # 记录请求的URL和HTTP协议
$status # 记录请求状态
$body_bytes_sent # 发送给客户端的字节数,不包括响应头的大小
$bytes_sent # 发送给客户端的总字节数
$msec # 日志写入时间。 单位为秒, 精度是毫秒。
$http_referer # 记录从哪个页面链接访问过来的
$http_user_agent # 记录客户端浏览器相关信息
$request_length # 请求的长度(包括请求行, 请求头和请求正文)。
$request_time # 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始, 直到把最后一个字符发送给客户端后进行日志写入为止。
$time_iso8601 # ISO8601标准格式下的本地时间。
$time_local # 通用日志格式下的本地时间。
日志缓存功能:
open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
默认:off;
字段位置:http, server, location
参数 | 描述 |
---|---|
max | 设置缓存中的最大文件描述符数量,如果缓存被占满,采用LRU算法将描述符关闭 |
inactive | 设置存活时间,默认是 10s |
min_uses | 设置在 inactive 时间段内,日志文件最少使用多少次后,该日志文件描述符记入缓存中,默认是1次 |
valid | 设置检查频率, 默认 60s |
off | 禁用缓存 |
NGINX 配置
此部分配置实质上是核心模块中内容(ngx_http_core_module
),但是使用频率最高,因此单独拿出来进行分析。
监听端口(listen
)
示例配置:
server {
listen 80;
server_name www.domain.com;
root /var/www/html/domain.com;
index index.php index.html
...
}
注意:浏览器在访问页面时会默认访问 80
端口,因此网站的监听端口请勿修改(若做了端口转发或者负载均衡可使用其他端口),以防访客无法正常使用。
根目录(root
)
示例配置:
server {
listen 80;
server_name www.domain.com;
root /var/www/html/domain.com;
index index.php index.html
...
}
root
指定了此主机的根目录,所有资源会在此目录下寻找,因此请设置正确的根目录,部分产品解压后存在多个目录,请分辨实际的网站目录并指定。
补充:指定根目录后可以使用文件的相对地址来指定资源。
与之相关的还有一个 alias
作用与 root
相似,会将root
目录重定向为alias
地址。
举个例子:
server {
listen 80;
index index.html;
location /request_path/code/ {
alias /local_path/code/;
}
}
实际请求:/local_path/code/index.html
server {
listen 80;
index index.html;
location /request_path/code/ {
root /local_path/code/;
}
}
实际请求:/local_path/code/request_path/code/index.html
索引页面(index
)
示例配置:
server {
listen 80;
server_name www.wavengine.com;
root /var/www/html/wavengine/blog;
index index.php index.html
...
}
说明:指定索引页面后,NGINX
会按指定的顺序在根目录下搜索,显示为当前主机的主页。
虚拟主机 (VH
)
虚拟主机是指在一个 NGINX 配置文件中指定多个网站
$ cat /etc/nginx/conf.d/all.conf
配置文件模板
server {
listen 80;
server_name blog.domain.com;
root /var/www/html/domain.com/blog;
...
}
server {
...
listen 80;
server_name ftp.domain.com;
root /var/www/html/domain.com/ftp;
}
也可以将多个主机拆分为多个文件(文件名可以自定义,但必须以 .conf
结尾)
$ ll
-rw-r--r-- 1 root root 1.1K Apr 17 09:46 default.conf
-rw-r--r-- 1 root root 353 Aug 14 00:07 ftp.conf
-rw-r--r-- 1 root root 2.6K Aug 14 23:01 blog.conf
total 12K
小贴士:推荐在主配置文件上/etc/nginx/nginx.conf
配置http
段配置,在/etc/nginx/conf.d/
中配置server
段配置。不同的域名可以监听在同一个端口,请求会根据请求的域名进行自动分配,但是若同一域名绑定相同的地址会触发优先级问题(应尽量避免)。
资源定位(location
)
location
用于在一个主机中匹配用户访问的资源,并进行处理和回应。
匹配符 | 匹配规则 | 优先级 |
---|---|---|
= | 表示精确匹配 | 1 |
^~ | 表示以某字符串开头 | 2 |
~ | 表示区分大小写的正则匹配 | 3 |
~* | 表示不区分大小写的正则匹配 | 4 |
!~ | 表示区分大小写不匹配的正则 | 5 |
!~* | 表示不区分大小写不匹配的正则 | 6 |
/ | 通用匹配,任何请求都会匹配到 | 7 |
注意:~
与~*
正则匹配规则在匹配后会寻找更精准的location
再次进行匹配。
文件检查(try_files
)
按指定顺序检查文件是否存在,并使用第一个找到的文件进行请求处理,若全找不到则内部重定向至最后一个参数;同时将根据请求root
和alias
指令从文件参数构造文件的路径。可以通过在名称的末尾指定斜杠来检查目录的存在,例如:$uri/
。
字段位置:server
, location
示例配置:
server {
listen 80;
server_name test.domain.com;
root /test/code;
index index.html;
location / {
try_files $uri @java_page;
}
location @java_page {
proxy_pass http://127.0.0.1:8080;
}
}
说明:此配置表示若用户访问示例地址后会在/test/code
下寻找index.html
若不存在文件会将请求导向本地端口8080
进行解析(Tomcat)。
最后一个参数也可以指向一个命名空间,比如下面的例子,同理最后一个参数也可以用返回码。
location / {
try_files $uri $uri/index.html $uri.html =404;
}
location / {
try_files $uri $uri/ @drupal;
}
location ~ \.php$ {
try_files $uri @drupal;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /path/to$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param QUERY_STRING $args;
}
location @drupal {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
需要注意的一点是若在 location 中使用,最后的参数请写完整相对路径。如下配置文件
location /web/mall {
root /data;
try_files $uri $uri/ @router;
index index.html;
}
location @router{
rewrite ^.*$ /web/mall/index.html last;
}
比如访问 http://www.domain.com/web/mall
,若没有找到文件会被内部重写到 http://www.domain.com$uri
中,而不是 http://www.domain.com/web/mall$uri
,因此在 @router 中使用需要写完整的相对路径,比如单页面 Vue 项目。
NGINX 负载均衡
LB
(Load Balance
,负载均衡)是将一个任务分摊到多个操作单元上进行执行,从而分摊压力,增加吞吐量、加强数据处理能力、提高网络的灵活性和可用性。
NGINX 的负载均衡实质上是“反向代理”。
反向代理与负载均衡之间的关系:如果后端是一台服务器就叫反向代理,如果有多台就是负载均衡。反向代理才能实现负载均衡,负载均衡是做反向代理的目的之一。
“正向代理”和“反向代理”的区别:
简单地理解,正向代理隐藏用户身份,反向代理隐藏服务器身份。
正向代理与反向代理
举个例子:
我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。
正向代理的用途:
(1)访问原来无法访问的资源。
(2)作为缓存,加速访问资源。
(3)对客户端访问授权,上网进行认证。
(4)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息。
举个例子:
我是一个用户,我访问某个网站,但是实质上给我提供数据的是另一个服务器,但是它隐藏在代理服务器后,我只能知道我连接的是谁,但是不知道具体谁给我提供的服务。隐藏了真实服务器的信息,提高了安全指数。
反向代理的用途:
(1)保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击。
(2)负载均衡,分摊压力,提高数据处理能力。
NGINX 反向代理配置
语法:
proxy_pass URL;
默认参数:—
字段位置:location, if in location, limit_except
跳转重定向
语法:
proxy_redirect default;
可选参数:proxy_redirect off;proxy_redirect redirect replacement;
默认参数:proxy_redirect default;
字段位置:http, server, location
头部设定
在默认使用反向代理时会遇到一个问题,抓包时可在头部信息中看到真实服务器地址及端口,这是不合理的,因此需要使用重新定义头部信息功能。
语法:
proxy_set_header field value;
默认参数:proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
字段位置:http, server, location
例子:
# 用户请求的时候HOST的值是www.wavengine.com, 那么代理服务会像后端传递请求的还是www.wavengine.com
proxy_set_header Host $http_host;
# 将$remote_addr的值放进变量X-Real-IP中,$remote_addr的值为客户端的ip
proxy_set_header X-Real-IP $remote_addr;
# 客户端通过代理服务访问后端服务, 后端服务记录真实客户端地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
其他参数:
# 代理服务连接后端服务器的连接超时时间,建议使用默认值
语法:proxy_connect_timeout time;
默认参数:proxy_connect_timeout 60s;
字段位置:http, server, location
# 代理服务等待后端服务器的响应时间
语法:proxy_read_timeout time;
默认参数:proxy_read_timeout 60s;
字段位置:http, server, location
# 后端服务器在规定时间之内必须传完所有的数据至代理
语法:proxy_send_timeout time;
默认参数:proxy_send_timeout 60s;
字段位置:http, server, location
代理缓冲区
代理缓冲功能开启的情况下,NGINX
会把后端返回的内容先放到缓冲区当中,然后再返回给客户端,边收边传, 不是全部接收完再传给客户端。
语法:proxy_buffering on | off;
默认参数:proxy_buffering on;
字段位置:http, server, location
语法:proxy_buffer_size size;
默认参数:proxy_buffer_size 4k|8k;
字段位置:http, server, location
语法:proxy_buffers number size;
默认参数:proxy_buffers 8 4k|8k;
字段位置:http, server, location
配置优化
在同一个配置文件中全部定义这些参数会导致配置文件冗余复杂,可读性差。因此将这部分配置写入一个配置文件,然后统一调用。
比如:
vim /etc/nginx/proxy_params
写入以下内容
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;
在其他配置文件中可以直接使用:
location / {
proxy_pass http://127.0.0.1:8080;
include proxy_params;
}
NGINX 负载均衡
负载均衡的作用是分摊压力,因此需要一台服务器暴露在外面用于分配工作,其他的服务器用于实际承担工作内容,因此需要定义一个“负载均衡池”,就是一个定义工作服务器的清单。这个清单在 NGINX
中称为 upstream
。
配置模板:
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
配置说明:定义了一个负载均衡池,其中有五台机器。weight
定义了权重,数值越大,分配使用的概率越大。backup
则是定义为备用机器,在其他机器可用的时候不会使用,只有当全部非备用机器宕机后才会实际使用。
在 upstream
中支持健康检查功能,可检测服务器的可用性,并对此进行实时调整。
配置模板:
resolver 10.0.0.1;
upstream dynamic {
zone upstream_dynamic 64k;
server backend1.example.com weight=5;
server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
server 192.0.2.1 max_fails=3;
server backend3.example.com resolve;
server backend4.example.com service=http resolve;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://dynamic;
health_check;
}
}
参数 | 说明 |
---|---|
down | 不参与负载均衡 |
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 达到允许请求失败的次数后, 会在此时间内不参与负载均衡 |
max_conns | 限制最大的接收连接数 |
负载均衡调度算法
方式 | 说明 |
---|---|
轮询 | 按时间顺序逐一分配到不同的后端服务器(默认) |
weight | 加权轮询,值越大,分配到的访问几率越高 |
ip_hash | 每个请求按访问IP的校验结果分配,来自同一IP的固定访问一个后端服务器(不推荐) |
url_hash | 按照访问URL的校验结果来分配请求,每个URL定向到同一个后端服务器(不推荐) |
least_conn | 最少连接数,哪个机器连接数少就分发新连接 |
NGINX 缓存
通常情况下缓存是用来减少后端压力,将压力尽可能的往前推,减少后端压力,提高网站并发延时。
通常在完善架构下会使用 Memcached
或 Redis
来优化缓存,提高缓存的 IO ,加快取用速率。
语法:
proxy_cache zone | off;
默认参数:proxy_cache off;
字段位置:http, server, location
缓存路径:
proxy_cache_path path [levels=levels]
[use_temp_path=on|off] keys_zone=name:size [inactive=time]
[max_size=size] [manager_files=number] [manager_sleep=time][manager_threshold=time]
[loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
默认参数:—
字段位置:http
缓存有效期:
proxy_cache_valid [code ...] time;
默认参数:—
字段位置:http, server, location
示例:
proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m;
缓存支持断点续传:
location /tmp-test/ {
proxy_cache tmp-test;
proxy_cache_valid 200 206 304 301 302 10d;
proxy_cache_key $uri;
proxy_set_header Range $http_range;
proxy_pass http://127.0.0.1:8081/media_store.php/tmp-test/;
}
NGINX 实例
用反向代理方式实现动静分离实例
将用户的访问的请求分离,动态请求和静态请求剥离开,保证服务的可用性,即使某一种不可用也不影响另一种。
系统 | 部署服务 | 地址 | 节点 |
---|---|---|---|
CentOS | NGINX | 192.168.69.112 | N.1 |
CentOS | NGINX | 192.168.69.113 | N.2 |
CentOS | Tomcat | 192.168.69.114 | N.3 |
在节点 2 (192.168.69.113)操作:
新建配置文件:
sudo vim /etc/nginx/conf.d/access.conf
写入以下内容:
server{
listen 80;
root /code;
index index.html;
location ~ .*\.(png|jpg|gif)$ {
gzip on;
root /soft/code/images;
}
}
准备一个静态资源(png)
sudo wget -O /code/images/nginx.png http://nginx.org/nginx.png
在节点 3 (192.168.69.114)操作:
部署动态环境:
[root@domain ~]# wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.7/bin/apache-tomcat-9.0.7.tar.gz
[root@domain ~]# mkdir /opt/tomcat
[root@domain ~]# tar xf apache-tomcat-9.0.7.tar.gz -C /opt/tomcat/
编辑动态页面:
[root@domain ~]# vi /opt/tomcat/apache-tomcat-9.0.7/webapps/ROOT/java_test.jsp
写入以下内容:(注意不要使用vim
)
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<HTML>
<HEAD>
<TITLE>JSP Test Page</TITLE>
</HEAD>
<BODY>
<%
Random rand = new Random();
out.println("<h1>Random number:</h1>");
out.println(rand.nextInt(99)+100);
%>
</BODY>
</HTML>
在节点 1 (192.168.69.112)操作:
编辑配置文件:
[root@domain ~]# vim /etc/nginx/conf.d/proxy.conf
写入以下内容:
upstream static {
server 192.168.69.113:80;
}
upstream java {
server 192.168.69.114:8080;
}
server {
listen 80;
server_name 192.168.69.112;
location / {
root /code;
index index.html;
}
location ~ .*\.(png|jpg|gif)$ {
proxy_pass http://static;
include proxy_params;
}
location ~ .*\.jsp$ {
proxy_pass http://java;
include proxy_params;
}
}
编辑网页文件:
[root@domain ~]# vim /code/index.html
写入以下内容:
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试ajax和跨域访问</title>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type: "GET",
url: "http://192.168.69.112/java_test.jsp",
success: function(data) {
$("#get_data").html(data)
},
error: function() {
alert("fail!!,请刷新再试!");
}
});
});
</script>
<body>
<h1>测试动静分离</h1>
<img src="http://192.168.69.112/nginx.png">
<div id="get_data"></div>
</body>
</html>
部署完成,现在访问
http://192.168.69.112/java_test.jsp
http://192.168.69.112/nginx.png
http://192.168.69.112/index.html
查看效果
配置请求头解决静态文件跨域问题
在使用 Vue.js 等框架时,打包生成的 CSS 和 JS 文件相对较大,一般会选择对接 CDN 来进行提速,但是此种部署方式会导致一个问题,静态资源跨域问题。
No 'Access-Control-Allow-Origin' header is present on the requested resource
出现这种问题后就需要给服务器添加相应的请求头
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
参数 | 说明 |
---|---|
Access-Control-Allow-Origin | 服务器默认不允许跨域,配置此参数后即可接受跨域请求 |
Access-Control-Allow-Headers | 跨域请求允许的请求头类型 |
Access-Control-Allow-Methods | 跨域请求允许的请求方式 |
- 配置
Access-Control-Allow-Headers
可以避免出现Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response
这类错误,这个错误表示当前请求Content-Type
的值不被支持。其实是发起了application/json
的类型请求导致的。 - 配置
Access-Control-Allow-Methods
可以避免出现Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
这类错误。 - 配置
OPTIONS
添加 204 的返回,是为了处理在发送 POST 请求时 NGINX 依然拒绝访问的错误,发送"预检请求"时,需要用到方法 OPTIONS ,所以服务器需要配置允许该方法。
这里涉及到一个概念预检请求(Preflight Request),其实上面的配置涉及到了一个 W3C 标准 CROS(Cross-origin resource sharing,跨域资源共享)它的提出就是为了解决跨域请求的。
跨域资源共享(CORS)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
其实 Content-Type
字段的类型为 application/json
的请求就是上面所说的搭配某些 MIME
类型的 POST 请求,CROS(Cross-origin resource sharing,跨域资源共享)规定,Content-Type
不属于以下 MIME
类型的,都属于预检请求:
application/x-www-form-urlencoded
multipart/form-data
text/plain
所以 application/json
的请求会在正式通信之前,增加一次"预检"请求,这次"预检"请求会带上头部信息
OPTIONS /api/test HTTP/1.1
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
服务器回应时,返回的头部信息如果不包含 Access-Control-Allow-Headers: Content-Type 则表示不接受非默认的的 Content-Type。
通过识别 UA 实现不同浏览器(设备)访问不同页面
示例配置:
http {
...
upstream firefox {
server 172.31.57.133:80;
}
upstream chrome {
server 172.31.57.133:8080;
}
upstream iphone {
server 172.31.57.134:8080;
}
upstream android {
server 172.31.57.134:8081;
}
upstream default {
server 172.31.57.134:80;
}
...
}
server {
listen 80;
server_name www.domain.com;
location / {
if ($http_user_agent ~* "Safari"){
proxy_pass http://dynamic_pools;
}
if ($http_user_agent ~* "Firefox"){
proxy_pass http://static_pools;
}
if ($http_user_agent ~* "Chrome"){
proxy_pass http://chrome;
}
if ($http_user_agent ~* "iphone"){
proxy_pass http://iphone;
}
if ($http_user_agent ~* "android"){
proxy_pass http://and;
}
proxy_pass http://dynamic_pools;
include proxy.conf;
}
}
}
访问不同路径使用不同服务器
方式一
使用负载资源池
upstream static_pools {
server 10.0.0.9:80 weight=1;
}
upstream upload_pools {
server 10.0.0.10:80 weight=1;
}
upstream default_pools {
server 10.0.0.9:8080 weight=1;
}
server {
listen 80;
server_name www.domain.com;
#url: http://www.domain.com/
location / {
proxy_pass http://default_pools;
include proxy.conf;
}
#url: http://www.domain.com/static/
location /static/ {
proxy_pass http://static_pools;
include proxy.conf;
}
#url: http://www.domain.com/upload/
location /upload/ {
proxy_pass http://upload_pools;
include proxy.conf;
}
}
方式二
使用判断语句实现
if ($request_uri ~* "^/static/(.*)$")
{
proxy_pass http://static_pools/$1;
}
if ($request_uri ~* "^/upload/(.*)$")
{
proxy_pass http://upload_pools/$1;
}
location / {
proxy_pass http://default_pools;
include proxy.conf;
}
NGINX 缓存
缓存过期周期
语法:
proxy_cache_valid [code ...] time;
默认参数: —
字段位置: http, server, location
配置模板:
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
缓存的维度
语法:
proxy_cache_key string;
默认参数:proxy_cache_key $scheme$proxy_host$request_uri;
字段位置:http, server, location
配置模板:
proxy_cache_key "$host$request_uri $cookie_user";
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
举个例子
1. 环境准备
系统 | 角色 | 地址 |
---|---|---|
CentOS | Proxy | 192.168.31.152 |
CentOS | Web | 192.168.31.153 |
2. 节点准备
建立网页 Demo
# mkdir -p /code/web{1..3}
# for i in {1..3};do echo Code1-Url$i > /code/web1/url$i.html;done
# for i in {1..3};do echo Code2-Url$i > /code/web2/url$i.html;done
# for i in {1..3};do echo Code3-Url$i > /code/web3/url$i.html;done
写入配置文件
# cat >/etc/nginx/conf.d/web_node.conf <'EOF'
server {
listen 8081;
root /code/web1;
index index.html;
}
server {
listen 8082;
root /code/web2;
index index.html;
}
server {
listen 8083;
root /code/web3;
index index.html;
}
EOF
重启服务
sudo systemctl restart nginx
检查服务
sudo ss -lnt | grep 80
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 0.0.0.0:8081 *:*
LISTEN 0 100 0.0.0.0:8082 *:*
LISTEN 0 100 0.0.0.0:8083 *:*
配置缓存
sudo mkdir /code/cache
sudo vim /etc/nginx/conf.d/proxy_cache.conf
写入如下配置
upstream cache {
server 192.168.31.153:8081;
server 192.168.31.153:8082;
server 192.168.31.153:8083;
}
proxy_cache_path /soft/cache levels=1:2 keys_zone=code_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name 192.168.31.152;
location / {
proxy_pass http://cache;
proxy_cache code_cache;
proxy_cache_valid 200 304 12h;
proxy_cache_valid any 10m;
add_header Nginx-Cache "$upstream_cache_status";
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
include proxy_params;
}
}
参数 | 说明 |
---|---|
proxy_cache | 存放缓存临时文件 |
levels | 按照两层目录分级 |
keys_zone | 开辟空间名, 10m:开辟空间大小, 1m可存放8000key |
max_size | 控制最大大小, 超过后Nginx会启用淘汰规则 |
inactive | 一小时没有被访问缓存会被清理 |
use_temp_path | 临时文件, 会影响性能, 建议关闭 |
proxy_cache | 开启缓存 |
proxy_cache_valid | 状态码200/304的过期为12h, 其余状态码10分钟过期 |
proxy_cache_key | 缓存key |
add_header | 增加头信息, 观察客户端respoce是否命中 |
proxy_next_upstream | 出现502-504或错误, 会跳过此台服务器访问下台 |
缓存测试
[root@domain ~]# curl -s -I http://192.168.31.152/url3.html | grep "Nginx-Cache"
Nginx-Cache: MISS
[root@domain ~]# curl -s -I http://192.168.31.152/url3.html | grep "Nginx-Cache"
Nginx-Cache: HIT
缓存清理
- 可直接删除缓存目录
- 可以使用
ngx_cache_purge
模块(需重新编译)
指定页面不缓存,在 server 字段中添加即可。
upstream cache {
server 192.168.31.153:8081;
server 192.168.31.153:8082;
server 192.168.31.153:8083;
}
proxy_cache_path /soft/cache levels=1:2 keys_zone=code_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name 192.168.31.152;
if ($request_uri ~ ^/(url3|login|register|password)) { # 新增内容
set $cookie_nocache 1;
}
location / {
proxy_pass http://cache;
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment; # 新增内容
proxy_no_cache $http_pargma $http_authorization; # 新增内容
proxy_cache code_cache;
proxy_cache_valid 200 304 12h;
proxy_cache_valid any 10m;
add_header Nginx-Cache "$upstream_cache_status";
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
include proxy_params;
}
}
缓存日志修改默认日志格式
[root@domain pinghsu]# cat /etc/nginx/nginx.conf
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$http_user_agent' '$request_uri' '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"' '"$upstream_cache_status"';
附录
参考链接
- HTTP - 维基百科
- Nginx 和 Apache 各有什么优缺点? - 知乎
- NGINX 配置跨域请求 - segmentfault
- Installing NGINX Open Source - NGINX
- 查看缓存命中率 - 运维之路
- 官方文档(英文) - NGINX
- try_files 参数讲解 - 江哥架构师
本文由 柒 创作,采用 知识共享署名4.0
国际许可协议进行许可。
转载本站文章前请注明出处,文章作者保留所有权限。
最后编辑时间: 2024-01-09 17:18 PM
这个网页底下的效果是怎么实现的?求教
很好的教程,收藏了!