Nginx配置Web服务器详解

Nginx配置Web服务器详解

Nginx配置Web服务器详解

nginx简介

nginx是一个HTTP和反向代理服务器、邮件代理服务器和通用TCP/UDP代理服务器,最初由俄国人Igor Sysoev(伊戈尔·西索夫)编写。nginx读作[engine x],当然好像更多人直接读[‘endʒɪx]。

nginx配置文件

查看nginx有哪些模块(包含内置模块)

一般网上查的都是让你用nginx -V(注意V大写)来查看它的编译参数,进而可以看到编译了哪些模块,但实际上这个方法只能让你看到显示指定的模块(如未启用的内置模块或第三方模块),但真正的内置模块,用nginx -V是看不到的,用以下命令能看到nginx有哪些模块(包含内置)

strings /usr/local/nginx/sbin/nginx | grep _module | grep -v configure | sort

查看nginx配置文件位置的方法

要配置http服务器,首先我们要找到配置文件,那nginx配置文件在哪呢?
编译nginx的时候,有一个参数叫--conf-path,如果指定了这个参数,则nginx的配置文件就在这个指定的路径中,如果未指定--conf-path,那么nginx的配置文件会在--prefix指定的路径下的config/nginx.conf,比如--prefix=/usr/local/nginx,那么nginx的配置文件在/usr/local/nginx/config/nginx.conf

可能你早已忘了编译参数,或者你的nginx是用yum/apt-get/brew安装的,那怎么知道nginx有没有配置--conf-path,怎么知道--prefix路径在哪呢?执行以下命令即可显示(注意V大写,小写v是查看nginx版本):

sudo nginx -V

其实,最简单的获取nginx配置文件路径的方法是:

sudo nginx -t

该命令用于测试nginx配置文件语法是否有语法错误,如果没有语法,则会显示出配置文件路径,并且提示syntax is ok, test is successful:

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

比如我的nginx配置文件目录在:

/usr/local/openresty/nginx/conf

我的conf目录配置文件:

├── fastcgi.conf
├── fastcgi.conf.default
├── fastcgi_params
├── fastcgi_params.default
├── koi-utf
├── koi-win
├── mime.types
├── mime.types.default
├── nginx.conf
├── nginx.conf.default
├── scgi_params
├── scgi_params.default
├── uwsgi_params
├── uwsgi_params.default
├── vhost
│   ├── test.xiebruce.top.conf
│   └── www.xiebruce.top.conf
└── win-utf

.default结尾的是默认文件,这些文件不参与配置,只是为了防止你改错了改乱了又不知道怎么改回来原来结构的情况下,可以使用默认文件恢复,比如nginx.conf.default,在刚开始时候它的内容与nginx.conf完全一致,但是你后来可能把nginx.conf改了很多,如果你想参考它最初的配置,查看nginx.conf.default文件即可,其他的.default文件亦是如此。

config目录配置文件解释

fastcgi_params:fastcgi_params是fastcgi的参数,比如php-fpm就是一个fastcgi,当你在nginx里使用fastcgi_pass把.php文件交给php-fpm处理的时候,同时要把fastcgi_params参数传过去,php的$_SERVER超全局数组中的各种元素,正是来自fastcgi_params中定义的变量,举个例子,在fastcgi_params中有一个选项叫:

fastcgi_param  REMOTE_ADDR        $remote_addr;

看到REMOTE_ADDR是不是很熟悉?没错,php中用来获取客户端ip的$_SERVER['REMOTE_ADDR']变量,正是来自上面这句命令,fastcgi_param表示定义一个fastcgi参数,REMOTE_ADDR就是参数名,$remote_addr是参数值,$remote_addr是一个nginx内置变量,由于客户端(浏览器)请求的是nginx配置的http服务器,nginx自然知道客户端的ip的,并且还把该ip存储到$remote_addr变量中以供后续使用,nginx有很多内置变量,具体可以去nginx官网的http模块,并搜索Embedded Variables,如下图:

Xnip2019-01-10_17-02-04.jpg

fastcgi.conf:该文件与fastcgi_params几乎相同,这两个文件其实是nginx不同发展阶段的产物,最开始是用的fastcgi_params,后来又添加了fastcgi.conf,至于这两个是什么关系?请看以下两篇文章:
1. 关于nginx与php fastcgi配置中的SCRIPT_FILENAME
2. fastcgi_params versus fastcgi.conf – nginx config history

scgi_params & uwsgi_params:与fastcgi是同一类型的文件,由于php只需要用到fastcgi,所以这两个文件一般不需要使用。

koi-utf & koi-win:用于支持俄语等斯拉夫语系语言的编码映射文件(因为nginx是俄罗斯人写的),这个一般人用不到。

win-utf:也是编码映射文件,用于解决windows乱码问题的,win可能用的到,但由于我手头没有win,所以对这个文件不是很清楚。

mime.types:定义nginx支持的mime文件格式,主要用于定义不同扩展名(后缀)对应的mime类型。像text/htmlimage/jpeg这些就叫mime类型,而htmljpgjpeg就是文件扩展名:

types {
    text/html                                        html htm shtml;
    text/css                                         css;
    text/xml                                         xml;
    image/gif                                        gif;
    image/jpeg                                       jpeg jpg;
    application/javascript                           js;
    application/atom+xml                             atom;
    application/rss+xml                              rss;
}

vhost:这是我自己创建的目录,用于存储虚拟主机的配置文件,为了方便管理,一个虚拟主机用一个配置文件,像我这里就有两个虚拟主机,这个配置文件最终会被包含到nginx.conf文件中。

nginx.conf:这是主配置文件,nginx也只认这一个文件,前面的配置文件,如果用到了,都需要在nginx.conf里用include指令包含进来。

总结:一般来说我们能用到的配置文件其实只有:

fastcgi.conf 或 fastcgi_params
mime.types
nginx.conf
vhost/*

fastcgi.conf和fastcgi_params是相同功能的,用了其中一个就不需要用另一个,vhost下的配置为自定义的配置,nginx.conf为主配置文件并且该配置文件也是可以自己重写的,不用动的配置文件,只有mime.types及fastcgi.conf或fastcgi_params。

配置HTTP服务器

一个HTTP服务器,可包含多个虚拟主机,虚拟主机英文叫virtual host(简称vhost),为什么叫虚拟主机呢?因为用一台服务器可以搭建多个网站,比如:www.aaa.com、www.bbb.com、www.ccc.com,一台服务器虚拟三个主机,各自互不影响,但这三个主机又不是真实的,而是在一台物理主机上虚拟出来的,所以叫虚拟主机。

配置server块

配置http服务器的配置结构(即http模块里可包含多个server)

http {
    #虚拟主机1(即vhost1,网站1)
    server {
        # Server1 configuration
    }
    #虚拟主机2(即vhost2,网站2)
    server {
        # Server2 configuration
    }
}

在 server 的配置块中,通常包含 listen 指令指定要监听的 IP 地址和端口号 (或者unix socket路径)。IPv4 和 IPv6 地址都可以。

server {
    listen 127.0.0.1:8080; # 监听本机发出的,连到 8080 端口的请求
    # The rest of server configuration
}

参数省略端口号时,使用标准80端口。省略地址时,监听所有地址。如果整个listen指令都省略了,根据超级用户的权限不同,标准端口是80/tcp,默认端口是8000/tcp。
如果有几个虚拟服务器同时匹配到请求的IP地址和端口号,Nginx会用HTTP头中的域名(Host头)匹配服务器配置块中的server_name指令。server_name指令的参数可以是完整域名,通配符*或正则表达式。

# 这是最常用的写法,即只写监听的端口,不写ip
server {
    listen      80;
    # 可以有多个域名(空格隔开)
    server_name example.org www.example.org;
    ...
}

如果匹配Host头的服务器名有多个,Nginx会按以下顺序搜索并使用第一个匹配到的服务器:

  • 1、精确名称搜索,比如 www.baidu.com。
  • 2、以通配符*开头的最长匹配项,比如*.baidu.com
  • 3、以通配符*结尾的最长匹配项,比如mail.*
  • 4、第一个匹配到的正则表达式。
  • 5、当请求的域名匹配上server_name中的某个域名时,$server_name变量的值永远是第一个域名,所以不能用它用作判断,你应该用$host变量来判断,这是nginx的一个坑。

如果Host头字段匹配不到任何服务器,Nginx会把请求路由到默认服务器。默认服务器可以通过在listen指令后用default_server参数来声明,如果没有声明则配置文件中的第一个服务器就成为默认服务器。

server {
    listen      80 default_server;
    ...
}

另一种默认服务器常用的写法是:

server {
    listen      80;
    server_name _;
    ...
}

没错,就是定义下划线_为域名,这样也不用写default_server来指定了,因为不会有人拿下划线来做域名,所以只要我们保证这个域名所有其他域名的最前面,那么访问其他域名不存在时,自然就会走这个默认的“下划线”域名。而保证它在其他配置的最前面也很简单,只要把它写在nginx.conf文件里include vhost/*.conf语句的前面,这样它肯定就是第一个域名。

配置location

为了找出最匹配URI的location,Nginx会先比较前缀字符串(路径名),再比较正则表达式。
正则表达式的优先级较高,除非使用^〜修饰符(非正则匹配,具体请看location指令的规则)。在前缀字符串中,Nginx 选择最特定的字符串(即最长和最完整的字符串)。 下面给出了选择处理请求的位置的确切逻辑:

  1. 用所有的前缀字符串测试URI;
  2. 等号=定义了前缀字符串和URI的精确匹配关系,如果找到了这个精确匹配,则停止查找;
  3. 如果^~修饰符预先匹配到最长的前缀字符串,则不检查正则表达式;
  4. 存储最长的匹配前缀字符串;
  5. 用正则表达式测试URI;
  6. 匹配到第一个正则表达式后停止查找,使用对应的location;
  7. 如果没有匹配到正则表达式,则使用之前存储的前缀字符串对应的location。

等号=最常见的用途就是/(forward slash,正斜杠)。如果对/的请求很多,可以把= /指定为location的参数来提高响应速度,因为在第一次比较之后就停止搜索匹配。

location = / {
    ...
}

具体请查看location指令的使用

root指令和proxy_pass指令

location上下文中可以定义处理请求(提供静态文件或转发请求给被代理的服务器)的指令:

server {
    # 响应静态文件
    location /images/ {
        root /data;
    }
    # 转发请求到 http://www.example.com
    location / {
        proxy_pass http://www.example.com;
    }
}

root指令
root指令指定静态文件在文件系统中的路径。请求的URI中,和location相关的部分会和root指定的路径组合成完整的目录名和文件名,从而获取到静态文件。例如,上面的例子中对/images/example.png的请求,会对应文件/data/images/example.png
另有与root指令类似功能的alias指令,可查看:Nginx – alias与root的区别

proxy_pass指令
proxy_pass指令将请求转发给和URL相关联的被代理的服务器,然后把被代理的服务器的响应转发给客户端。上面的例子中,所有URI不以/images/开头的请求,都会被转发给被代理的服务器。

使用内置变量

可以通过在配置文件中使用变量,实现不同的情况下用不同的方式处理请求。变量是在运行时计算的有名字的值,用作指令的参数。Nginx中的变量用美元符号$开头。变量根据Nginx的状态定义信息,例如当前正在处理的请求的属性。

Nginx中有一系列的预定义的变量,比如core HTTP变量。还可以通过set、map和geo指令来自定义变量。多数变量在运行时才计算值,并包含针对特定请求的信息。例如,$remote_addr包含客户端的IP地址信息,$uri包含当前的URI值,具体有什么变量请查看config目录配置文件解释

return 指令

有的网页的URI需要立刻返回包含指定错误码或跳转码的响应,比如页面被暂时或永久移动。实现这个目的的最简单方法是使用return指令。

location /wrong/url {
    return 404;
}

return指令的第一个参数是响应码,第二个参数可选,可以是重定向的URL(用于响应码 301,302,303,307)或响应体中的文本:

location /permanently/moved/url {
    return 301 http://www.example.com/moved/here;
}

location和server上下文中都可以使用return指令。

rewrite指令

通过rewrite指令,在请求的处理过程中可以多次改写请求的URI。
rewrite指令有3个参数:第一个参数是用于匹配URI的正则表达式,第二个参数是用于替代匹配到的URI的新URI,第三个参数可选,是一个标志,有两种值lastbreak,它们的区别请看下例:

location /test1.txt/ {
    rewrite /test1.txt/  /test2.txt break;
}

location ~ test2.txt {
    return 508;
}

假设现在我们的请求为www.xxx.com/test1.txt,则第一个location会被匹配上并进入,然后里面的rewrite指令会被运行,请求会被rewrite替换为www.xxx.com/test2.txt,因为使用的是break标志,所以会停止匹配下面的location,由于www.xxx.com/test2.txt这个文件不存在,所以会直接显示404。

而如果使用last的话,会继续搜索下面是否有符合条件(符合重写后的/test2.txt请求)的location。此时,/test2.txt刚好与前面已经改变过的location的条件对应上了(请求已经变成了/test2.txt),进入花括号{}里面的代码执行,这里会返回508(这个码是自己随便写的)。

重写 HTTP 响应

sub_filter指令可以定义如何重写或改变HTTP响应的内容,将一个字符串替换为另一个字符串。这个指令支持变量和链式改变,从而可以实现复杂操作。
示例:

location / {
    sub_filter      /blog/ /blog-staging/;
    sub_filter_once off;
}

可以改变HTTP协议,将http:// 改为https://,也可以把请求头字段中的localhost 改为主机名。sub_filter_once指令控制Nginx是否在一个location内连续应用sub_filter指令。

location / {
    sub_filter     'href="http://127.0.0.1:8080/'    'href="https://$host/';
    sub_filter     'img src="http://127.0.0.1:8080/' 'img src="https://$host/';
    sub_filter_once on;
}

请注意,sub_filter替换最多只会发生一次。如果已使用sub_filter修改的响应部分再次被另一个sub_filter匹配,是不会再次被替换的。

处理错误

error_page指令可以配置Nginx返回自定义页面以及错误代码,在响应中替换不同的错误代码,或将浏览器重定向到指定URI。
以下示例中,error_page指令指定要返回404错误页面(/404.html)。

error_page 404 /404.html;

注意error_page指令并不会立刻返回错误(只有return指令才会立刻返回),只是表明如果发生错误时如何处理。错误代码可以来自一个被代理的服务器或在Nginx处理过程中发生(比如Nginx找不到客户端指定的页面时会404)。

下面例子中,当Nginx找不到页面,会把404代码改为301,并把客户端重定向到 http:/example.com/new/path.html。

location /old/path.html {
    error_page 404 =301 http:/example.com/new/path.html;
}

下面的配置会在文件找不到时把请求转发到后端。由于在error_page指令的等号后没有指定状态码,因此对客户端的响应的状态码由代理服务器返回(不一定是404)。

server {
    ...
    location /images/ {
        # Set the root directory to search for the file
        root /data/www;

        # Disable logging of errors related to file existence
        open_file_cache_errors off;

        # Make an internal redirect if the file is not found
        error_page 404 = /fetch$uri;
    }

    location /fetch/ {
        proxy_pass http://backend/;
    }
}

error_page指令指示 Nginx 在文件找不到时做内部跳转。error_page指令的最后一个参数中可以使用$uri变量,代表当前的请求中的URI,该请求将在重定向中传递。
例如,如果文件/images/some/file找不到,会被替换为/fetch/images/some/file并从第一个location开始再次查找。最终,匹配第二个location上下文并跳转到代理服务器。
open_file_cache_errors指令可防止在找不到文件时写入错误消息。这里因为找不到文件时立刻处理了,所以没有必要使用。

参考:Nginx 基本功能 – 将 Nginx 配置为 Web 服务器(HTTP Server)

打赏

订阅评论
提醒
guest

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

Nginx配置Web服务器详解