Skip to main content

8.web服务器

将NGINX配置为Web服务器,支持虚拟服务器多租户,URI和响应重写,变量和错误处理。

在高层次上,将NGINX 配置为Web服务器是定义它处理哪些URL以及如何处理这些URL上的资源的HTTP请求的问题。在较低级别,配置定义了一组虚拟服务器,用于控制对特定域或 IP 地址的请求的处理。有关配置文件的更多信息,请参阅创建 NGINX 配置文件。

HTTP 流量的每个虚拟服务器都定义了称为locations的特殊配置实例,这些实例控制特定 URI 集的处理。每个位置都定义了自己的方案,用于处理映射到此位置的请求。NGINX 提供对此过程的完全控制。每个位置都可以代理请求或返回文件。此外,还可以修改 URI,以便将请求重定向到另一个位置或虚拟服务器。此外,可以返回特定的错误代码,并且可以配置特定页面以对应于每个错误代码。

设置虚拟服务器

NGINX 配置文件必须包含至少一个服务器指令来定义虚拟服务器。当NGINX 处理请求时,它首先选择将为请求提供服务的虚拟服务器。

虚拟服务器由 http上下文中的 server指令定义,例如:

http {
server {
# Server configuration
}
}

可以在 http上下文中添加多个 server指令以定义多个虚拟服务器。

server配置块通常包括一个侦听指令,用于指定服务器侦请求的 IP 地址和端口(或 Unix 域套接字和路径)。接受 IPv4 和 IPv6 地址;将 IPv6 地址括在方括号中。

以下示例显示了侦听 IP 地址 127.0.0.1 和端口 8080 的服务器的配置:

server {
listen 127.0.0.1:8080;
# Additional server configuration
}

如果省略端口,则使用标准端口。同样,如果省略某个地址,服务器将侦听所有地址。如果根本不包含 listen该指令,则“标准”端口为 80/tcp ,“默认”端口为 8000/tcp ,具体取决于超级用户权限。

如果有多个服务器与请求的IP地址和端口匹配,NGINX 将根据 server块中的server_name指令测试请求的 Host标头字段。server_name参数可以是完整(精确)名称、通配符或正则表达式。通配符是一个字符串,在其开头、结尾或两者中都包含星号 (*);星号匹配任何字符序列。NGINX 使用Perl语法作为正则表达式;在它们前面加上波浪号 (~)。此示例说明了确切的名称。

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

如果 Host标头字段与服务器名称不匹配,NGINX 会将请求路由到请求到达的端口的默认服务器。默认服务器是 nginx.conf 文件中列出的第一个服务器,除非您在 listen指令中包含 default_server参数以显式指定服务器为默认服务器。

server {
listen 80 default_server;
#...
}

配置位置(Configuring Locations)

NGINX 可以将流量发送到不同的代理,或者根据请求URI提供不同的文件。这些块是使用放置在 server指令中的location指令定义的

例如,您可以定义三个 location块来指示虚拟服务器将一些请求发送到一个代理服务器,将其他请求发送到另一个代理服务器,并通过从本地文件系统传递文件来为其余请求提供服务。

location该指令有两种类型的参数: 前缀字符串 (路径名)和正则表达式。要使请求 URI 与前缀字符串匹配,它必须以前缀字符串开头。

以下具有路径名参数的示例位置匹配以 / some/path / 开头的请求 URI,例如 /some/path/document.html 。(它与 / my-site/some/ path 不匹配,因为 /some/path 不会出现在该 URI 的开头。

location /some/path/ {
#...
}

正则表达式前面带有波浪号 (~) 表示区分大小写的匹配,或波浪星号 (~*) 表示不区分大小写的匹配。以下示例匹配包含字符串的 URI,.html或**.htm**位于任何位置。

location ~ \.html? {
#...
}

NGINX位置优先级

为了找到最匹配URI的位置,NGINX 首先将URI与带有前缀字符串的位置进行比较。然后,它使用正则表达式搜索位置。

除非使用 ^~修饰符,否则正则表达式的优先级更高。在前缀字符串中,NGINX 选择最具体的一个(即最长和最完整的字符串)。选择处理请求的位置的确切逻辑如下:

  1. 针对所有前缀字符串测试 URI。
  2. =(等号)修饰符定义 URI 和 =前缀字符串的完全匹配。如果找到完全匹配项,搜索将停止。
  3. 如果 ^~(插入符号波浪号)修饰符在最长匹配的前缀字符串前面加上,则不检查正则表达式。
  4. 存储最长匹配的前缀字符串。(Store the longest matching prefix string)
  5. 针对正则表达式测试 URI。(Test the URI against regular expressions)
  6. 找到第一个匹配的正则表达式时停止处理,并使用相应的位置。
  7. 如果没有匹配的正则表达式,请使用与存储的前缀字符串对应的位置。(If no regular expression matches, use the location corresponding to the stored prefix string.)

=修饰符的典型用例是请求 / (正斜杠)。如果 / 的请求频繁,则指定 = /location指令的参数可加快处理速度,因为搜索匹配项在第一次比较后停止。

location = / {
#...
}

location上下文可以包含定义如何解析请求的指令 - 提供静态文件或将请求传递给代理服务器。在以下示例中,与第一个 location上下文匹配的请求将从 /data 目录提供文件,与第二个上下文匹配的请求将传递到承载 www.example.com** 域内容的**代理服务器。

server {
location /images/ {
root /data;
}

location / {
proxy_pass http://www.example.com;
}
}

root 指令指定要在其中搜索要服务的静态文件的文件系统路径。与位置关联的请求 URI 将追加到路径中,以获取要服务的静态文件的全名。在上面的示例中,为了响应对 /images/example.png 的请求,NGINX 提供了文件 / data/images/example.png

proxy_pass 指令将请求传递到使用配置的 URL 访问的代理服务器。然后,来自代理服务器的响应将传递回客户端。在上面的示例中,所有具有不以 /images/ 开头的 URI 的请求都将传递到代理服务器。

使用变量(Using Variables)

您可以使用配置文件中的变量让NGINX 根据定义的情况以不同的方式处理请求。变量是在运行时计算并用作指令参数的命名值。变量由其名称开头的 $(美元)符号表示。变量根据NGINX的状态定义信息,例如当前正在处理的请求的属性。

有许多预定义变量,例如核心 HTTP 变量,您可以使用 setmapgeo 指令定义自定义变量。大多数变量在运行时计算,并包含与特定请求相关的信息。例如,$remote_addr包含客户端 IP 地址 $uri并保存当前 URI 值。

返回特定状态代码(Returning Specific Status Codes)

某些网站 URI 要求立即返回包含特定错误或重定向代码的响应,例如,当页面被临时或永久移动时。最简单的方法是使用 return 指令。例如:

location /wrong/url {
return 404;
}

return的第一个参数是响应代码。可选的第二个参数可以是重定向的 URL(对于代码 301 302 303307)或要在响应正文中返回的文本。例如:

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

return该指令可以包含在 locationserver 上下文中。

重写请求中的 URI(Rewriting URIs in Requests)

通过使用重写(rewrite)指令,可以在请求处理期间多次修改请求 URI,该指令具有一个可选参数和两个必需参数。第一个(必需)参数是请求 URI 必须匹配的正则表达式。第二个参数是要替换匹配 URI 的 URI。可选的第三个参数是一个标志,可以停止处理进一步的 rewrite指令或发送重定向(代码 301302)。例如:

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

如此示例所示,第二个参数 users通过正则表达式的匹配进行捕获。

您可以在 serverlocation上下文中包含多个 rewrite指令。NGINX 按照指令出现的顺序逐个执行 rewrite指令。选择 server上下文时,上下文中的指令将执行一次。

NGINX处理一组重写指令后,它会根据新的URI选择一个 location上下文。如果所选位置包含 rewrite指令,则依次执行这些指令。如果 URI 与其中任何一个匹配,则在处理完所有定义的 rewrite指令后,将开始搜索新位置。

下面的示例演示 rewrite指令与 return指令的组合。

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

此示例配置区分两组 URI。 诸如 /download/some/media/ file 之类的 URI 将更改为 /download/ some/mp3/file.mp3 。由于 last该标志,后续指令(第二个 rewritereturn指令)被跳过,但NGINX 继续处理请求,该请求现在具有不同的URI。类似地,诸如 /download/ some/audio/ file 之类的 URI 被替换为 / download/some/mp3/file.ra 。如果URI与任一 rewrite指令都不匹配,NGINX 会将错误代码 403返回给客户端。

有两个参数会中断 rewrite指令的处理:

  • last– 停止在当前 serverlocation上下文中 rewrite执行指令,但 NGINX 会搜索与重写的 URI 匹配的位置,并应用新位置中的任何 rewrite指令(这意味着 URI 可以再次更改)。
  • break– 与 break 指令一样,停止在当前上下文中 rewrite处理指令,并取消搜索与新 URI 匹配的位置。不会执行新位置中的 rewrite指令。

重写 HTTP 响应(Rewriting HTTP Responses)

有时需要重写或更改 HTTP 响应中的内容,将一个字符串替换为另一个字符串。您可以使用 sub_filter 指令定义要应用的重写。该指令支持变量和替换链,使更复杂的更改成为可能。

例如,您可以更改引用代理以外的服务器的绝对链接:

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

另一个示例将方案从 http://更改为 https://,并将 localhost地址替换为请求标头字段中的主机名。sub_filter_once指令告诉NGINX在一个位置内连续应用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修改的响应部分。

处理错误

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

error_page 404 /404.html;

请注意,此指令并不意味着立即返回错误(return该指令可以这样做),而只是指定在错误发生时如何处理错误。错误代码可能来自代理服务器,也可能发生在NGINX Plus处理期间(例如,404是NGINX找不到客户端请求的文件时的结果)。

在下面的示例中,当 NGINX 找不到页面时,它会用 301代码代替 404代码,并将客户端重定向到 http:/example.com/new/path.html 。当客户端仍在尝试访问其旧 URI 的页面时,此配置非常有用。301该代码通知浏览器页面已永久移动,并且需要在返回时自动将旧地址替换为新地址。

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,该 URI 在重定向中传递。

例如,如果未找到 /images/some/file,则会将其替换为 / fetch/images/some/file ,并开始对位置进行新的搜索。因此,请求最终出现在第二个 location上下文中,并被代理http://backend/。

open_file_cache_errors 指令可防止在找不到文件时写入错误消息。这里没有必要这样做,因为丢失的文件得到了正确处理。

rewrite 规则中的 last、break、redirect、permanent

在Nginx的 rewrite指令中,lastbreakredirectpermanent是不同的标志,用于控制重写规则的执行流程和行为。

  • last
    • 使用 last标志会停止当前轮的处理,然后重新启动新的处理轮。这通常用于内部重定向。
    • 例如:rewrite ^/old-url$ /new-url last;
  • break
    • 使用 break标志会停止当前轮的处理,不会进行下一轮处理。可以用于终止所有后续的重写规则。
    • 例如:rewrite ^/break-url$ /final-url break;
  • redirect
    • 使用 redirect标志会发起一个临时重定向(HTTP 302)。
    • 例如:rewrite ^/redirect-url$ /target-url redirect;
  • permanent
    • 使用 permanent标志会发起一个永久重定向(HTTP 301)。
    • 例如:rewrite ^/permanent-url$ /target-url permanent;

示例:

server {
listen 80;
server_name example.com;

location / {
# 使用last进行内部重定向,重新启动新的处理轮
rewrite ^/old-url$ /new-url last;
rewrite ^/another-old-url$ /another-new-url last;

# 使用break停止当前处理轮,不进行下一轮处理
rewrite ^/break-url$ /final-url break;

# 使用redirect进行临时重定向(HTTP 302)
rewrite ^/temp-redirect-url$ /target-url redirect;

# 使用permanent进行永久重定向(HTTP 301)
rewrite ^/permanent-redirect-url$ /target-url permanent;
}

# 更多其他配置...
}
  • 如果请求URL匹配 /old-url/another-old-url,则会发起内部重定向,将请求重定向到 /new-url/another-new-url,并重新启动新的处理轮。
    • 具体来说,如果请求的 URL 匹配了 /old-url/another-old-url,那么 Nginx 会执行与新的 URI(即经过重定向后的 URI)匹配的位置块。
    • 这种机制允许在同一个请求中多次应用重写规则,因为处理轮数被重新启动。这对于在处理请求的不同阶段应用不同的重写规则非常有用。
  • 如果请求URL匹配 /break-url,则会停止当前处理轮,不进行下一轮处理。
  • 如果请求URL匹配 /temp-redirect-url,则会发起临时重定向(HTTP 302),将请求重定向到 /target-url
  • 如果请求URL匹配 /permanent-redirect-url,则会发起永久重定向(HTTP 301),将请求重定向到 /target-url