美文网首页
将 nginx 配置为一个 web 服务器

将 nginx 配置为一个 web 服务器

作者: C86guli | 来源:发表于2016-07-10 12:01 被阅读3029次

    编译自:
    nginx-web-server

    目录

    • 建立虚拟服务器
    • 配置 location
    • 使用变量
    • 返回指定的状态码
    • URI 重写
    • 对 HTTP Response 进行重写
    • 处理错误

    这里有一个视频,有兴趣可以看看:nginx 安装与调优,其中讲述了以下主题:

    • nginx 怎样使你的应用能更快响应、具有更好的伸缩性、更快、更安全?
    • 如何安装 nginx
    • 为 nginx 调整操作系统参数

    从高层次来说,配置 nginx 为一个 web 服务器,主要是定义:

    • 对哪些 URL 进行处理
    • 如何处理对于这些 URL 的 HTTP 请求

    从较低层次来说,主要是定义一组 虚拟服务器 ,让这些 虚拟服务器 去处理对于 特定域名IP地址 的请求。

    更多关于如何配置 nginx 的信息,可参考 Creating NGINX Plus Configuration Files

    每个 虚拟服务器 都定义了 location 区块,location 区块定义了对于指定的一组 URI 是如何进行处理的。

    在 location 中可作如下定义:

    • 转发请求到后端服务器(也就是将此 nginx 服务器作为代理),或者返回一个文件;
    • 对 URI 进行重写,将请求重定向至其它的 location 或者其它虚拟服务器;
    • 返回指定的 error code,并且可以为每个 error code 配置一个指定的 error page。

    建立虚拟服务器


    在 nginx 配置文件中,必须包含至少一个 server 指令,server 指令定义了一个虚拟服务器。当一个请求到来时,nginx 首先要决定选择哪一个虚拟服务器处理该请求。

    server 指令在 http context 中进行定义,例如:

    http {
        server {
            # Server configuration
        }
    }
    

    http context 中,可添加多个 server 指令以定义多个虚拟服务器。

    server 区块中,一般会包含一个 listen 指令。listen 指令是用于定义该虚拟服务器监听于哪个 IP地址端口(或者定义一个 Unix socket 文件及路径)。IP地址可为 IPv4 或 IPv6 地址;IPv6 地址应放入方括号中。

    以下是一个例子,该服务器监听于 127.0.0.1 和 8080 端口:

    server {
        listen 127.0.0.1:8080;
        # The rest of server configuration
    }
    

    如果不指定端口地址,将使用标准的端口地址,即 80 端口。如果不指定 IP 地址,将监听于所有 IP 地址之上。如果 server 区块中没有包含 listen 指令,根据超级用户的权限,将使用 标准的 80/tcp 端口或者 默认的 8000/tcp 端口。

    如果同时有多个 虚拟主机 匹配了请求的IP地址和端口,nginx 将测试请求的 Host 首部字段,将它与 server 区块中的 server_name 指令的配置进行对比。server_name 指令的值有三种:准确的主机名通配主机名正则表达式主机名。通配主机名在其起始、或末尾有一个 * 符号,或者起始和末尾都有一个 * 符号,* 可匹配任意长度的字符串;nginx 的正则表达式兼容 Perl 的正则语法,在正则表达式之前需有~前缀。

    以下是关于 准确的主机名 的例子:

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

    如果有多个 server_name 指定的主机名与请求首部的 Host 字段匹配,nginx 按如下的优先次序选择,当找到第一个能匹配的 server name 就终止查找:

    1. 准确的主机名
    2. 以 “*” 起始的最长的通配主机名,比如 *.example.org
    3. 以 “*” 结尾的最长的通配主机名,比如 mail.*
    4. 第一个匹配的正则表达式(按照配置文件中的顺序)

    如果没有找到与 Host 字段匹配的 server name,nginx 将把请求路由到该端口地址的 默认的虚拟主机。 如果没有特别指定,默认的虚拟主机 就是 nginx.conf 文件中的第一个定义的 虚拟主机。也可以使用 listen 指令的 default_server 参数显式地指定一个虚拟主机为 默认的虚拟主机

    server {
        listen      80 default_server;
        ...
    }
    

    配置 location


    nginx 可基于请求的 URI,将访问流量转发给不同的后端服务器,或者将不同的文件提供给客户端。这个功能由 location 指令定义,location 指令在 server 区块中定义。

    举个例子,你可以定义三个 location 区块,将一些请求转发给一个后端服务器,将另一些请求转发给另一个不同的后端服务器,余下的请求从本地的文件系统中提供客户端所请求的文件。

    当一个请求交给了某个虚拟主机之后,nginx 将请求的 URI 与该虚拟主机内所有的 location 指令的定义进行对比,然后将请求映射到匹配的 location 之中。

    在每个 location 区块中,一般可以放置更多的 location 指令(有少数例外),用于进一步对请求进行分组处理。

    Note: 在本文中,location 这个词只表示一个单独的 location 上下文。

    location 指令可定义两种参数:

    • 前缀字符串(路径名)
    • 正则表达式

    如果一个请求的 URI 以某个 前缀字符串 为起始,则与该 location 匹配。

    下面举一个 前缀字符串 的例子,在下面的例子中,该 location 的参数为 /some/path/ ,它能匹配类似于 URI 为 /some/path/document.html 的请求:

    location /some/path/ {
        ...
    }
    

    正则表达式必须带有前缀 ~~*(忽略大小写)。在下面的例子中,该 location 可匹配包含 .html 或者 .htm 的请求:

    location ~ \.html? {
        ...
    }
    

    为了找到某个 URI 的最佳匹配,nginx 首先比较 URI 和 前缀字符串,然后比较 URI 和 正则表达式。

    正则表达式拥有更高的优先级,除非正则表达式使用了 ^~ 修饰符。

    在所有匹配的 前缀字符串 中,nginx 选择其中最长及最完整的前缀字符串所对应的 location。

    下面是准确的查找 loction 的过程:

    1. 将 URI 与所有的 前缀字符串 进行比较
    2. 修饰符 = 表示 URI 与 前缀字符串 必须精确匹配。如果能够精确匹配,则结束查找
    3. 如果在匹配的最长的 前缀字符串 前添加了 ^~ 修饰符,则不会再检查正则表达式
    4. 保存匹配的最长的 前缀字符串
    5. 测试 URI 和 正则表达式的匹配情况
    6. 一旦找到匹配的正则表达式,则终止查找,并使用对应的 location
    7. 如果没有匹配的正则表达式,使用保存匹配的最长的 前缀字符串

    如果对于 / 的请求很频繁,可为 location / 添加 = 修饰符,这样可以加速处理过程,因为一次匹配查找即可结束:

    location = / {
        ...
    }
    

    在 location 区块中,可匹配将请求转发给后端服务器。在下面的例子中,对于匹配第二个 location 的请求,将被转发给 www.example.com

    server {
        location /images/ {
            root /data;
        }
    
        location / {
            proxy_pass http://www.example.com;
        }
    }
    

    root 指令指定了提供静态文件的本地路径。如果请求的 URI 匹配第一个 location,将 URI 追加到 /data 之后即可得到文件的访问路径:/data/URI。比如请求的 URI 为 /images/example.png,nginx 将 /data/images/example.png 文件返回给客户端。

    proxy_pass 指令用于将请求转发给后端服务器,参数值即为后端服务器的访问路径 URL。从后端服务器取回响应之后,nginx 再转发给客户端。在上面的例子中,所有不以 /images/ 起始的 URI,对应的请求将被转发给后端服务器。

    使用变量


    nginx.conf 中可使用变量。变量的值在运行时进行计算,可作为指令的参数使用。引用变量,使用 $ 符号,比如 $remote_addr。变量的定义信息依赖于 nginx 当前的状态,比如当前被处理的请求的属性等。

    有许多变量是预定义的,比如 core HTTP 定义的变量;另外你也可以自定义变量,使用 setmap,或 geo 指令进行自定义。

    大多数变量的值是在运行时计算出来的,其中包含特定请求的信息。比如 $remote_addr 包含客户端的 IP地址 信息,而 $uri 包含当前的 URI 值。

    返回指定的状态码


    在有些情况下,比如当一个页面已经被临时或永久地移动到其他位置,访问这种 web 站点的 URI 时需要立即返回一个错误码或者重定向码。最容易的方法是使用 return 指令:

    location /wrong/url {
        return 404;
    }
    

    return 指令的第一个参数是响应状态码。第二参数是可选的,可以是一个重定向的 URL(for codes 301, 302, 303, and 307),或者是放入响应 body 的一段文本。比如:

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

    return 指令可放入 location 和 server 上下文中。

    URI 重写


    在处理请求的过程中,使用 rewrite 指令可对 URI 进行多次修改。

    rewrite 指令的语法为:

    rewrite regex replacement [flag]

    regex 是用于匹配 URI 的正则表达式,replacement 参数用于替换匹配的 URI。flag 参数是可选的,可用于终止进一步的 rewrite 指令操作,或者发送重定向(301 或 302)给客户端,例如:

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

    server 上下文和 location 上下文中,都可包含多个 rewrite 指令。nginx 按照 rewrite 指令出现的顺序依次进行处理。当一个 server 上下文被选择用于处理请求时,在 server 上下文中的 rewirte 指令被执行一次。

    当 nginx 对一组 rewrite 指令进行处理之后,它根据新的 URI 选择匹配的 location 上下文。如果在选择的 location 中也包含 rewrite 指令,它们将被依次执行。如果 URI 匹配其中任意一个,当所有定义的 rewrite 指令被处理之后,开始对新的 URI 进行查找。

    如下例子中,rewrite 指令和 return 指令联合使用:

    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。因为该 rewrite 指令添加了 last flag,它将跳过后面的指令(第二个 rewrite 指令和 return 指令)。然后 nginx 开始处理新的 URI。

    • 类似于 /download/some/audio/file 的 URI 请求被替换为 /download/some/mp3/file.ra。因为该 rewrite 指令添加了 last flag,它将跳过后面的指令(return 指令)。

    • 如果 URI 不匹配 location 中的任何一个 rewrite 指令,nginx 返回 403 状态码给客户端。

    rewrite 指令有两个参数可以终止 rewrite 指令集的处理:

    • last - 停止当前 server 或 location 上下文中的 rewrite 指令集的执行,nginx 对修改后的 URI 进行匹配查找。如果新匹配的 location 中包含 rewrite 指令,URI 有可能被再次修改。

    • break - 如同 break 指令,终止当前上下文中的 rewrite 指令集的执行,nginx 对修改后的 URI 进行匹配查找,在新匹配的 location 中如果包含 rewrite 指令,它们不会被执行。

    对 HTTP Response 进行重写


    有时你需要对 HTTP 响应报文的内容进行重写或修改。你可以使用 sub_filter 指令来定义重写操作。该指令支持变量和链式替换,可作复杂的修改:

    举个例子,你可以对指向一个服务器的绝对链接进行修改:

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

    另一个例子,修改 http://https:// ,并且将 localhost 地址修改为请求首部中的 host 字段的值。sub_filter_once 指令告诉 nginx 是否对所有匹配的字符串重复地执行替换操作,还是只在第一次遇到匹配的字符串时,执行一次替换操作(只替换一次)。sub_filter_once 默认为 on,表示只在第一次遇到匹配的字符串时,替换一次:

    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 也匹配该部分时,不会再进行修改。

    处理错误


    使用 error_page 指令,你可以配置 nginx :

    • 返回一个 error code 以及一个自定制的页面;
    • 在响应报文中,替换一个不同的 error code
    • 发送重定向指令给浏览器,指向不同的 URI

    在下面的例子中,error_page 指令指定了 /404.html 页面,这个页面在返回 404 code 时会一并返回给客户端:

    error_page 404 /404.html;
    

    要注意的是,这个指令不是立即返回该错误给客户端(这是 return 指令做的事),这只是定义了如果处理该错误。该 error code 可来自于一个后端服务器,或者在 nginx 做一些处理时出现(例如,当 nginx 不能找到请求的文件时,将返回 404 错误)。

    下面的例子中,当 nginx 找不到请求的页面时,它将 code 404 替换为了 code 301,并将返回一个重定向给客户端:http:/example.com/new/path.html

    这个配置是很有用的,当客户端尝试以一个老旧的 URI 请求页面时,可返回重定向指令,令其访问在新路径下的文件。

    code 301 告诉浏览器,该页面已经被永久地转移到了其他地方,它需要将返回的新的地址替换原来的老的地址:

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

    下面的例子中,当请求 /images/ 路径下的文件发生文件未找到的错误时,通过内部重定向转发到后端服务器。因为在 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 ,当发生 file not found 错误时,做一个内部的重定向。$uri 变量的值为当前请求的 URI,在重定向中被转发给了后端服务器。

    例如,如果 /images/some/file 未找到,它被替换为 /fetch/images/some/file,对这个新 URI,nginx 会查找与其匹配的 location,这里就是 location /fetch/,然后就被转发给后端服务器了。
    (可参考 反向代理

    当发送 file not found 错误时,open_file_cache_errors 指令在这里用于防止记录错误日志。因为请求已经被转发给后端,所以不应该记录错误日志。


    版权信息
    *本文编译自 nginx.com

    相关文章

      网友评论

          本文标题:将 nginx 配置为一个 web 服务器

          本文链接:https://www.haomeiwen.com/subject/gcjdjttx.html