Nginx最细讲解(一)

Nginx基础介绍

Nginx服务器以性能强劲功能丰富著称。

  • 性能上:Nginx服务器为事件驱动模型。如果你熟悉Node.js应该很清楚,该模型的特征是有一个主循环不停运行,当有异步事件需要处理时在当前主循环进程里执行处理逻辑。相比多进程/多线程模型节省了大量资源。
  • 功能上:它既可以做HTTP服务器,也可以做反向代理。具体地,它主要支持fastCGISSLVirtual HostRewriteHttp Basic AuthGzipProxy等等。

安装

详细安装教程,官方只给了源码编译安装手册。其实yumapt-gethome brew等包管理工具都早已支持安装。我本机是mac因此用brew安装:

brew install nginx。

启停

Nginx启动后会创建一个master进程和多个worker进程。master进程主要工作时管理worker进程,另一方面接收外部的信号来执行指定的操作。Nginx启停需要配置文件,我的配置文件位于/usr/local/etc/nginx/nginx.conf

  • 启动 nginx -c /usr/local/etc/nginx/nginx.conf &
  • 停止 nginx -c /usr/local/etc/nginx/nginx.conf -s stop
  • 平滑停止 nginx -c /usr/local/etc/nginx/nginx.conf -s quit
  • 平滑重启 nginx -c /usr/local/etc/nginx/nginx.conf -s reload
  • 平滑升级 nginx -c /usr/local/etc/nginx/nginx.conf -s reopen

配置

当你想要Nginx为你提供某个功能的时候,你只需要往配置文件里配指令和参数即可。换句话讲,玩Nginx就是玩个配置!
这篇主要还是梳理配置文件的整体结构。(由于Nginx功能实在太多,因此只会梳理一些核心功能~

一、整体结构

... # 全局块

events { # events块
  ...
}

http { # http块
  ... # http全局块
  
  server { # server块
    ... # server全局块

    location <pattern> { # location块
      ...
    }
  }
}
  • 全局块 影响Nginx整体运行的配置指令。一般有用户/组的设置、worker进程数量、pid文件位置、日志路径和类型等。
  • events块 影响外部对Nginx服务器的网络连接指令。一般有是否开启接收连接序列化、是否一次接收多个链接和选取哪种事件驱动(select / poll / epoll / rtsig /kqueue / devpoll / eventport)和worker进程最大连接数等。
  • http全局块 mime-type定义、日志定义、是否开启sendfile、连接超时时间和单连接请求数上限等。
  • server全局块 主要配置要监听的端口和虚拟主机的域名或ip:port配置。
  • location块 该块包含最重要都指令,uri匹配、rewrite、缓存和反向代理等都在这里实现。

二、配置样例:

配置样例放入了最常用的指令、参数和注解,值得详细读一下。

# user  nobody nobody; # Nginx进程以nobody用户和nobody组启动。
worker_processes  2; # 可以配auto,一般配成cpu核数的1倍或2倍。
error_log  /usr/local/var/log/nginx/error.log;
# error_log  /usr/local/var/log/nginx/info.log  info; # 等级有debug, info, notice, warn, error, crit, alert和emerg.
pid  /usr/local/var/run/nginx.pid;

events {
  use epoll;
  worker_connections 65535; # 单个worker进程同时开启的总连接数上限。
  accept_mutex  on; # on|off 新连接到来时序列化分配给worker进程避免争抢,解决“惊群”问题。
  multi_accept  off; # on|off 每个worker进程是否一次只能接收一个新到达的连接。
}

http {
  include  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  /usr/local/var/log/nginx/access.log  main; # 设置access日志

  tcp_nodelay on; # on|off 默认on 禁用Nagle算法,让数据发送无延迟。
  sendfile  off; # on|off 默认off 内核空间拷贝至内核空间,无需途径用户空间,增加效率。
  sendfile_max_chunk  128k; # 每次调用sendfile()传输的数据量上限
  tcp_nopush off; # on|off 默认off 配合sendfile使用,并且和tcp_nodelay互斥!

  keepalive_timeout  60 50; # 保持连接60秒,响应客户端头部为50秒
  keepalive_requests  100; # 默认100 每个连接最多处理多少次请求

  server {
    listen  80;
    # 域名或IP 
    # 支持通配符*.teddywen.com、www.teddywen.*
    # 支持正则 ~^(mail.+).teddywen.com$ 匹配后还能提取括号内容到变量 set $sub = $1;
    server_name  localhost;

    location / {
      root  /usr/local/var/www; # 查找资源的根目录
      index  index.html index.htm; # 当访问的uri以路径结尾,则依次尝试该路径下的index.html、index.htm文件
    }

    error_page  500 502 503 504 /50x.html; # 当访问响应为这些错误码时,将uri转发至/50x.html,接着会被 location = /50x.html {...} 块接管处理。
    location  = /50x.html {
      root  /usr/local/var/www;
    }
  }
}

核心块和指令

有些指令很常用很重要,但使用起来不那么简单,有些细节惨杂其中。

location块

location块是Nginx的核心,其语法表达式为:

location [ = | ~ | ~* | ^~ ] uri { ... }

举例最直观:

location / { #expr1
  return 200 "/";
}
location /foo { #expr2
  return 200 "/foo";
}
location /foo/bar { #expr3
  return 200 "/foo/bar";
}
location ~* /(.*)/(.*)$ { #expr4
  set $foo = $1; # 正则支持提取符号(),第一位()提取出来的是"foo"
  set $bar = $2; # 第二位()提取出来的是"bar"
  return 200 "/foo/bar[regex]";
}

假设发送一个GET请求:http://localhost/foo/bar,Nginx的处理机制是:

  1. 匹配所有非正则uri,将匹配度最高的块记下来。(这里是expr3
  2. 匹配所有正则uri,一旦匹配到就立即执行该块。反之则执行步骤1中匹配度最高的块。

这里GET请求会返回:/foo/bar[regex],原因是符合expr4中的正则表达式。
加入不符合expr4,那么GET请求会返回:/foo/bar。因为它是匹配度最高的。

location块有四种uri匹配方式。

  1. 严格匹配(符号=):后面跟着的uri必须为非正则表达式。该符号的作用是,当请求路径严格和uri相等,则直接用该块处理请求,而不会去执行步骤2,即匹配所有正则uri
  2. 正则匹配(符号~):顾名思义后面跟着的uri必须用正则表达式。
  3. 正则匹配不区分大小写(符号~*)。
  4. 符号^~:后面跟着的uri必须为非正则表达式。该符号的作用是:当执行步骤1(匹配所有非正则uri,将匹配度最高的块记下来)时,如果该匹配度最高的块用了^~符号,那么就不执行步骤2,直接用该块。我们还是拿上面的例子:
    假设发送一个GET请求:http://localhost/foo/bar,如果我们在expr3加了^~
location /foo { #expr2
  return 200 "/foo";
}
location ^~ /foo/bar { #expr3
  return 200 "/foo/bar";
}
location ~* /(.*)/(.*)$ { #expr4
  set $foo = $1; # 正则支持提取符号(),第一位()提取出来的是"foo"
  set $bar = $2; # 第二位()提取出来的是"bar"
  return 200 "/foo/bar[regex]";
}

请求会返回"/foo/bar"。因为满足了:匹配度最高的块用了^~符号,因此直接用该块处理响应,不去执行步骤2的正则uri匹配了。
反之,如果我们在expr2加了^~

location ^~ /foo { #expr2
  return 200 "/foo";
}
location /foo/bar { #expr3
  return 200 "/foo/bar";
}
location ~* /(.*)/(.*)$ { #expr4
  set $foo = $1; # 正则支持提取符号(),第一位()提取出来的是"foo"
  set $bar = $2; # 第二位()提取出来的是"bar"
  return 200 "/foo/bar[regex]";
}

请求会返回"/foo/bar[regex]"。因为匹配度最高的块是/foo/bar,不是/foo。

root指令

设置服务器端资源根目录

root path;

假设发送一个GET请求:http://localhost/foo/bar.html

location / {
  root /data/www/;
}
location /foo/ {
  root /var/www/;
}

结合上一节学到的理论,Nginx会使用第二个块处理请求。注意!!!Nginx的文件搜寻路径不是/var/www/bar.html,而是/var/www/foo/bar.html。因为root设置的是根目录,请求url的path会完整保留,结合根目录拼出一个完整的搜寻路径。即:$root + $url-full-path

alias指令

alias path;

alias指令对于root指令是一种灵活补充。alias指令可以改变访问的uri,让Nginx去读和uri无关的目录。例:

location /foo/ {
  root  /var/www/music;
}

假设在/var/www/music目录下有些许mp3文件(goodbye.mp3hello.mp3等等),此时我想让用户访问 http://localhost/foo/goodbye.mp3来获取/var/www/music目录下的goodbye.mp3文件。用root指令是办不到的,因为结合上节的知识点最终Nginx会去找/var/www/music/foo/goodbye.mp3,关键问题就是请求中的uri无法修改,此时alias指令登场啦!!!

location /foo/ {
  alias  /var/www/music/; # 末尾的斜杠一定要加!!!
}
location ~ ^/bar/(.+)$ {
  alias  /var/www/doc/$1; # 正则uri的情况一定要记得加提取值!!!这里是 $1
}

alias指令会将/foo/完整地替换成/var/www/music/,达到修改uri的目的,最终找到/var/www/music/goodbye.mp3文件。

index指令

index file ...;

作用一、当用户以路径的形式访问服务器时可以自动找到入口文件。

location /foo/ {
  root  /var/www;
  index  index.html  index.htm  index.txt;
}

访问 http://localhost/foo/ 时自动在/var/www/foo/目录下依次寻找index.html、index.html和index.txt文件,一旦找到就立即响应给客户端。

作用二、用正则提取功能针对不同的路径。

location ^/foo/(.+)/bar/$ {
  root  /var/www;
  index  index.$1.html index.html  index.htm  index.txt;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容