使用Nginx配置一个Web服务器(HTTP Server)

使用Nginx配置一个Web服务器(HTTP Server)

nginx简介

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

nginx配置文件

查看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文件格式,http与content_type扩展名对应关系,熟悉http的童鞋肯定知道,http传递的实体是需要标记一下内容的类型的,比如你是html网页content-type: text/html; charset=UTF-8,还是图片content-type: image/gif等等。

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)
    server {
        # Server1 configuration
    }
    #虚拟主机2(即vhost2)
    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 指令的参数可以是完整域名,通配符*或正则表达式。

server {
    listen      80;
    server_name example.org www.example.org;
    ...
}

如果匹配 Host 头的服务器名有多个,Nginx 会按以下顺序搜索并使用第一个匹配到的服务器:
精确名称搜索,比如 www.baidu.com。
以通配符*开头的最长匹配项,比如*.baidu.com
以通配符*结尾的最长匹配项,比如mail.*
第一个匹配到的正则表达式。

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

server {
    listen      80 default_server;
    ...
}

配置location

为了找出最匹配 URI 的 location,Nginx 会先比较前缀字符串(路径名),再比较正则表达式。
正则表达式的优先级较高,除非使用 ^〜 修饰符。在前缀字符串中,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。

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

使用内置变量

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

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

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,第三个参数可选,是一个标志,可以停止处理其他重写指令或发送重定向(代码301或302)。

location /users/ {
    rewrite ^/users/(.*)$ /show?user=$1 break;
}

在 server 和 location 上下文中可以使用多个 rewrite 指令,Nginx 会按照先后顺序依次执行。在 server 上下文中的 rewrite 指令会在上下文被选中时执行一次。
Nginx 在处理完一系列的 rewrite 指令后,会根据新的 URI 选择一个 location 上下文。如果选中的 location 包含 rewrite 指令,会依次执行。
rewrite 指令示例:

server {
    ...
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last;
    return  403;
    ...
}

这个例子会区分两组 URI:/download/some/media/file 这样的 URI 会被变为 /download/some/mp3/file.mp3。因为第三个参数使用了 last 标志,后续指令(第二个重写和返回指令)被跳过,但 Nginx 继续处理请求(该请求现在已经具有不同的 URI)。如果 URI 不匹配 rewrite 指令,Nginx 会向客户端返回 403 错误代码。
有两个参数可以中断 rewrite 指令:

  • last – 在当前的 server 或 location 上下文中中断 rewrite 指令的执行。此时 Nginx 会查找要重写 URI 的 location,并且应用新 location 中的任何 rewrite 指令(意味着 URI 可以再次更改)。
  • break – 跟 break 指令类似,在当前的上下文中停止 rewrite 指令,停止查找匹配新的 URI 的 location。新的 location 中的 rewrite 指令不会执行。

重写 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)

打赏

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of

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

使用Nginx配置一个Web服务器(HTTP Server)