Nginx 简介
什么是 Nginx
Nginx 是异步框架的 Web 服务器
,也可以用作反向代理
,负载平衡器
和 HTTP 缓存
,Nginx 的编写有一个明确目标就是超越 Apache Web 服务器的性能。 Nginx 提供开箱即用的静态文件,使用的内存比 Apache 少得多,每秒可以处理大约四倍于 Apache 的请求。在高并发下 Nginx 能保持低资源低消耗高性能。还有高度模块化的设计,模块编写简单。配置文件简洁。
反向代理是代理服务器的一种。服务器根据客户端的请求,从其关系的一组或多组后端服务器(如 Web 服务器)上获取资源,然后再将这些资源返回给客户端,客户端只会得知反向代理的 IP 地址,而不知道在代理服务器后面的服务器簇的存在。
模块
Nginx 将各功能模块组织成一条链,当有请求到达的时候,请求依次经过这条链上的部分或者全部模块,进行处理。每个模块实现特定的功能。例如,实现对请求解压缩的模块,实现 SSI 的模块,实现与上游服务器进行通讯的模块,实现与 FastCGI 服务进行通讯的模块。
Nginx 的模块根据其功能基本上可以分为以下几种类型(摘自极客学院):
模块 | 描述 |
---|---|
event module | 搭建了独立于操作系统的事件处理机制的框架,及提供了各具体事件的处理。包括 ngx_events_module, ngx_event_core_module 和 ngx_epoll_module 等。Nginx 具体使用何种事件处理模块,这依赖于具体的操作系统和编译选项 |
phase handler | 此类型的模块也被直接称为 handler 模块。主要负责处理客户端请求并产生待响应内容,比如 ngx_http_static_module 模块,负责客户端的静态页面请求处理并将对应的磁盘文件准备为响应内容输出 |
output filter | 也称为 filter 模块,主要是负责对输出的内容进行处理,可以对输出进行修改。例如,可以实现对输出的所有 html 页面增加预定义的 footbar 一类的工作,或者对输出的图片的 URL 进行替换之类的工作 |
upstream | upstream 模块实现反向代理的功能,将真正的请求转发到后端服务器上,并从后端服务器上读取响应,发回客户端。upstream 模块是一种特殊的 handler,只不过响应内容不是真正由自己产生的,而是从后端服务器上读取的 |
load-balancer | 负载均衡模块,实现特定的算法,在众多的后端服务器中,选择一个服务器出来作为某个请求的转发服务器 |
配置指令
Nginx 的配置系统由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,全部位于 Nginx 安装目录下的 conf
目录下。nginx.conf
中的配置信息,根据其逻辑上的意义,对它们进行了分类,称之为配置指令上下文。不同的作用域含有一个或者多个配置项。当前 Nginx 支持的几个指令上下文:
指令 | 描述 |
---|---|
main | nginx 在运行时与具体业务功能(比如 http 服务或者 email 服务代理)无关的一些参数,比如工作进程数,运行的身份等 |
http | 与提供 http 服务相关的一些配置参数。例如:是否使用 keepalive、gzip 进行压缩等 |
server | http 服务上支持若干虚拟主机。每个虚拟主机一个对应的 server 配置项,配置项里面包含该虚拟主机相关的配置。在提供 mail 服务的代理时,也可以建立若干 server,每个 server 通过监听的地址来区分 |
location | http 服务中,某些特定的 URL 对应的一系列配置项 |
实现 email 相关的 SMTP/IMAP/POP3 代理时,共享的一些配置项(因为可能实现多个代理,工作在多个监听地址上) |
配置防盗链
一般情况下,为了防止图片链接被盗用,如果在白名单外内嵌该链接,则会失效。直接来看个例子,比如下面我们肯定会看到一个破图,它来自掘金网站,但是如果我们点击跳转试一下,可以发现它是可以访问的:
Failed to load resource: the server responded with a status of 403 ()
我们可以利用 valid_referers 来进行相关配置,参数如下,看个最简单的示例吧:
- none - 没有 referer 来源信息
- blocked - referer 不带协议
- ip
- server_name - 域名,支持正则及 *
nginx 会通过查看 referer 字段和 valid_referers 后面的 referer 列表参数进行匹配,如果至少匹配一个,
$invalid_referer
字段值就返回为 0,否则为 1。
server {
#listen 80;
server_name localhost di;
location / {
root /etc/nginx/conf.d;
index index.html index.htm;
}
location ~ .*.(jpg|gif|png) { # 表示对 jpg、gif、png 后缀的文件实行防盗链
valid_referers none blocked my_location; # 至少匹配一个则返回 0
if ($invalid_referer) { # 没匹配到则返回 1
return 403; # or rewrite
}
root /etc/nginx/conf.d;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
反向代理
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。举个配置的例子(摘自掘金):
// nginx.conf, 每次修改都要重启才能生效
user www www; // 指定 Nginx 工作进程运行的用户及用户组
worker_processes auto; // 工作进程数,和 CPU 核数相同
// 全局错误日志输出位置。日志级别有 debug、info、notice、warn、error、crit。debug 日志输出最详细
error_log /data/wwwlogs/nginx_error.log crit;
// 存储 Nginx 进程 id 的文件路径
pid /usr/local/nginx/logs/nginx.pid;
// 指定 Nginx 进程最多打开的文件描述符
worker_rlimit_nofile 51200;
events {
// 使用的 I/O 模型,可选项有:select、epoll、kqueue、poll、rtsig、/dev/poll。Linux 下首选 epoll,FreeBSD 下首选 kqueue
use epoll;
worker_connections 1024; // 每个进程允许的最大连接数
}
http {
charset utf-8;
include mime.types; // 包含其他配置文件,方便模块化配置,利于管理
default_type application/octet-stream; // 文件类型未定义时,默认使用二进制流的格式
client_header_buffer_size 32k; // 客户端请求头 buffer size 大小
large_client_header_buffers 4 32k; // 客户端请求中较大的消息头的缓存数量和大小
client_max_body_size 50m; // 客户端请求中 http body 的大小
sendfile on; // 设置为 on 表示启动高效传输文件的模式
tcp_nopush on; // sendfile 设置为 on 时才生效,用于防止网络阻塞
keepalive_timeout 60; // 客户端保持活动连接的时间,超时则关闭连接
// FastCGI 致力于减少网页服务器与 CGI 程序之间交互的开销,从而使服务器可以同时处理更多的网页请求
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_temp_file_write_size 256k;
// gzip 压缩
gzip on;
gzip_min_length 1k; // 数据大于这个值时才启用 gzip 压缩,数据大小通过读取 Content-Length 来获取
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2; // 压缩比,取值 1-9.1 是压缩比最低,速度快。9 压缩比最高,速度慢,耗 cpu 资源
// 需要采用 gzip 压缩的文件类型
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on; // 是否让前端的缓存服务器缓存压缩后的 gzip 文件
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
upstream firstdemo { // upstream name {} 负载均衡
ip_hash; // 记录首次访问的信息,之后再访问都是该服务器
server 39.106.145.33;
server 47.93.6.93;
}
server { // 反向代理
listen 8080;
server_name m1.domain.com; // 访问的域名,多个域名用空格分隔
index index.html index.htm index.php; // 默认的首页文件
root /data/www/default; // 网站根目录
location / {
proxy_pass http://firstdemo; // 项目的开发机地址
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 60;
proxy_read_timeout 600;
proxy_send_timeout 600;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { // HTTP 缓存
expires 30d;
}
location /nginx_status {} // 设置 Nginx 统计功能
stub_status on; // 启用
access_log off;
allow 192.168.1.0/24; // 允许访问统计页面的 ip 范围
}
}
}
// 包含 vhost 目录下所有 .conf 后缀的配置文件。通常包含的文件的内容是 server 块
include vhost/*.conf;
反向代理的优点如下:
- 提高了内部服务器的安全
- 加快了对内部服务器的访问速度
- 节约了有限的 IP 资源 - 校园网内部服务器除使用教育网地址外,也会采用公网的 IP 地址对外提供服务,公网分配的 IP 地址数目是有限的,如果每个服务器有分配 - 个公网地址,那是不可能的,通过反向代理技术很好的解决了 IP 地址不足的问题
正向代理
既然提到了反向代理,那一定有正向代理,是的没错,这里根据两者的不同分别再解释下:
- 反向代理(reverse proxy) - 隐藏了真实的服务端,客户端并不知道真正请求的是哪个服务端,即反向代理。Nginx 通过
proxy
模块实现反向代理功能 - 正向代理(forward proxy) - 隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都由代理服务器来完成,即正向代理。Nginx 本身只支持 http 的正向代理,可以通过
ngx_http_proxy_connect_module
模块支持 http、https 的正向代理。如 VPN
由于 Nginx 正向代理的功能指令较少,只需要进行简单的配置即可,需要置两个 server 节点,一个处理 HTTP 转发,另一个处理 HTTPS 转发:
server {
resolver 114.114.114.114; # 指定 DNS 服务器 IP 地址
listen 80;
location / {
proxy_pass http://$http_host$request_uri; # 设定代理服务器的协议和地址
proxy_set_header HOST $http_host;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
}
}
server {
resolver 114.114.114.114; # 指定 DNS 服务器 IP 地址
listen 443;
location / {
proxy_pass https://$host$request_uri; # 设定代理服务器的协议和地址
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
}
}
负载均衡
负载均衡(Load Balancing)的配置通常有两种方式:
1、加权轮询
配置项 | 描述 |
---|---|
down | 不参与到负载均衡中,一般用户排查故障时使用 |
weight | 轮询的权重,值越大,分配到的概率越大 |
backup | 备份集齐,其他服务器都不可用时才使用该服务器 |
max_fails | 允许请求失败的次数,默认值为 1 |
fail_timeout | max_fails 次失败之后,暂停服务的时间 |
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com weight=4;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server backup1.example.com backup;
server down.example.com down;
}
2、ip_hash - 根据 ip 算出 hash 值分配到不同服务器上,固定的 ip 会分配到固定的机器上。这种策略解决了网站 session 共享问题
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
缓存
Nginx 缓存,可以在一定程度上,减少源服务器的处理请求压力。因为静态文件中,很多都是不经常更新的。Nginx 使用 proxy_cache
将用户的请求缓存到本地一个目录。下一个相同请求可以直接调取缓存文件,就不用去请求服务器了。以下示例摘自 wall-wxk 博客:
http{
// http 层设置
proxy_connect_timeout 10; // 服务器连接的超时时间
proxy_read_timeout 180; // 连接成功后,等候后端服务器响应时间
proxy_send_timeout 5; // 后端服务器数据回传时间
proxy_buffer_size 16k; // 缓冲区的大小
proxy_buffers 4 32k; // 每个连接设置缓冲区的数量为 number,每块缓冲区的大小为 size
proxy_busy_buffers_size 96k; // 开启缓冲响应的功能以后,在没有读到全部响应的情况下,写缓冲到达一定大小时,Nginx 一定会向客户端发送响应,直到缓冲小于此值。
proxy_temp_file_write_size 96k; // 设置 Nginx 每次写数据到临时文件的大小限制
proxy_temp_path /tmp/temp_dir; // 从后端服务器接收的临时文件的存放路径
// 设置缓存的路径和其他参数。被缓存的数据如果在 inactive 参数(当前为 1 天)指定的时间内未被访问,就会被从缓存中移除
proxy_cache_path /tmp/cache levels=1:2 keys_zone=cache_one:100m inactive=1d max_size=10g;
server {
listen 80 default_server;
server_name localhost;
root /mnt/blog/;
location / {
}
#要缓存文件的后缀,可以在以下设置。
location ~ .*\.(gif|jpg|png|css|js)(.*) {
proxy_pass http://ip地址:90; // Nginx 缓存里拿不到资源,向该地址转发请求,拿到新的资源,并进行缓存
proxy_redirect off; // 设置后端服务器 Location 响应头和 Refresh 响应头的替换文本
proxy_set_header Host $host; // 允许重新定义或者添加发往后端服务器的请求头
proxy_cache cache_one; // 指定用于页面缓存的共享内存,对应 http 层设置的 keys_zone
proxy_cache_valid 200 302 24h; // 为不同的响应状态码设置不同的缓存时间
proxy_cache_valid 301 30d;
proxy_cache_valid any 5m;
expires 90d; // 缓存时间
// 如果缓存有效的话,那么静态资源返回的报头,一定会带上这个信息
add_header wall "hey!guys!give me a star."; // 添加响应头
}
}
// 无 Nginx 缓存的 blog 端口
server {
listen 90;
server_name localhost;
root /mnt/blog/;
location / {
}
}
}
proxy_pass
目前有两个模块都拥有 proxy_pass 指令:
ngx_stream_proxy_module
- 只能在 server 段使用, 只需要提供域名或 ip 地址和端口。可以理解为端口转发,可以是 tcp 或 udp 端口ngx_http_proxy_module
- 需要在 location 段、location 中的 if 段、limit_except 段中使用,处理需要提供域名或 ip 地址和端口外,还需要提供协议(http 或 https),还有一个可选的 uri 可以配置
server {
listen 53 udp;
proxy_responses 1;
proxy_timeout 20s;
proxy_pass dns.example.com:53;
}
server {
listen 80;
server_name www.test.com;
# 正常代理,不修改后端 url 的
location /some/path/ {
# 如果跨域资源也部署在同一台机器上,我们甚至可以 proxy 到 127.0.0.1
proxy_pass http://127.0.0.1:1234;
}
# 修改后端 url 地址的代理(本例后端地址中,最后带了一个斜线)
location /testb {
proxy_pass http://www.other.com:8801/;
}
# 使用 if in location
location /google {
if ( $geoip_country_code ~ (RU|CN) ) {
proxy_pass http://www.google.hk;
}
}
location /tate/ {
# 没有匹配 limit_except 的,代理到 unix:/tmp/backend.socket:/uri/
proxy_pass http://unix:/tmp/backend.socket:/uri/;;
# 匹配到请求方法为: PUT or DELETE, 代理到 9080
limit_except PUT DELETE {
proxy_pass http://127.0.0.1:9080;
}
}
}
常用命令
- stop — fast shutdown
- quit — graceful shutdown
- reload — reloading the configuration file
- reopen — reopening the log files
nginx -s reload
# 使用 -c 的参数指定 nginx.conf 文件的位置
nginx -c /usr/local/nginx/conf/nginx.conf -s reload
参考链接
- Nginx 官方文档
- Nginx 入门指南 - 极客学院
- 谁说前端不需要懂 - Nginx 反向代理与负载均衡 By chenhongdong
- 使用 Nginx 缓存服务器上的静态文件 By wall-wxk
- Nginx 系列:Nginx 反向缓存代理详解 By 小生博客
- Nginx 配置文件详解 By 君君要上天
- Nginx 之 proxy_pass 指令完全拆解 By 永福