介绍
Nginx是一个高性能的Web服务器,负责处理互联网上一些最大网站的负载。 它特别好地处理许多并发连接,并且在服务静态内容方面表现优异。
虽然许多用户都知道Nginx的功能,但是新用户经常被Nginx配置文件中的一些约定所困惑。 在本指南中,我们将重点讨论Nginx配置文件的基本结构以及如何设计文件的一些指导。
了解Nginx配置上下文
本指南将介绍在Nginx主配置文件中找到的基本结构。 此文件的位置将根据您在计算机上安装软件的方式而有所不同。 对于许多发行,该文件将位于/etc/nginx/nginx.conf
。 如果它不存在在那里,它也可以是在/usr/local/nginx/conf/nginx.conf
或/usr/local/etc/nginx/nginx.conf
。
一看主配置文件时,你应该注意到的第一件事情是,它出现在一个树状结构,通过组括号定义来组织(看起来像{
和}
)。 在Nginx中,这些括号定义的区域称为“上下文”,因为它们包含根据其关注区域分离的配置详细信息。 基本上,这些部门提供了组织结构以及一些条件逻辑来决定是否应用配置。
因为上下文可以在另一个内部分层,Nginx提供了一定程度的指令继承。 作为一般规则,如果指令在多个嵌套作用域中有效,则较宽上下文中的声明将作为默认值传递给任何子上下文。 子节点上下文可以随意覆盖这些值。 值得注意的是,一个覆盖任何数组类型的指令将取代以往的价值,而不是追加到它。
指令只能在其设计的上下文中使用。 Nginx将在读取配置文件时出错,该配置文件包含在错误上下文中声明的指令。 该Nginx的文档包含了哪些环境中的每个指令是有效信息,所以它是一个很好的参考,如果您不确定。
下面,我们将讨论在使用Nginx时可能遇到的最常见的上下文。
核心上下文
我们将讨论的第一组上下文是Nginx利用的核心上下文,以便创建分层树和分离离散配置块的问题。 这些是构成Nginx配置的主要结构的上下文。
主要上下文
最一般的上下文是“主”或“全局”上下文。 它是唯一的上下文,不包含在典型的上下文块中,如下所示:
# The main context is here, outside any other contexts
. . .
context {
. . .
}
任何完全在这些块之外存在的指令被认为存在于“主”上下文中。 请记住,如果您的Nginx配置是以模块化方式设置的,一些文件将包含看起来存在于括号上下文之外的指令,但是当配置被拼接在一起时,这些指令将包括在这样的上下文中。
主上下文表示Nginx配置的最广泛的环境。 它用于配置在基本级别影响整个应用程序的详细信息。 而在本节中的指令影响下上下文中,许多的这些不被继承 ,因为它们不能在较低级别被覆盖。
在主上下文中配置的一些常见细节是运行工作进程的用户和组,工作程序的数量和保存主进程的PID的文件。 你甚至可以定义一些东西,比如工作者的CPU亲和性和工作者进程的“可靠性”。 整个应用程序的默认错误文件可以在此级别设置(这可以在更具体的上下文中覆盖)。
事件上下文
“事件”上下文包含在“主”上下文中。 它用于设置影响Nginx如何处理一般级别连接的全局选项。 在Nginx配置中只能定义一个事件上下文。
这个上下文在配置文件中看起来像这样,在任何其他括号上下文之外:
# main context
events {
# events context
. . .
}
Nginx使用基于事件的连接处理模型,因此在此上下文中定义的指令确定工作进程应如何处理连接。 主要是,这里找到的指令用于选择要使用的连接处理技术,或者修改这些方法的实现方式。
通常,基于平台可用的最有效的选择来自动选择连接处理方法。 对于Linux系统,该epoll
方法通常是最好的选择。
可以配置的其他项目是每个工作者可以处理的连接数,一个工作者一次只取一个连接,或者在通知关于挂起的连接之后取得所有挂起的连接,以及工作者是否将轮流响应事件。
HTTP上下文
当将Nginx配置为Web服务器或反向代理时,“http”上下文将占用大部分配置。 此上下文将包含定义程序如何处理HTTP或HTTPS连接所需的所有指令和其他上下文。
http上下文是事件上下文的兄弟,因此它们应该并排列出,而不是嵌套列出。 他们都是主要语境的孩子:
# main context
events {
# events context
. . .
}
http {
# main context
. . .
}
虽然较低的上下文更具体地说明如何处理请求,但是此级别的指令控制其中定义的每个虚拟服务器的默认值。 大量的指令在这个上下文中是可配置的,这取决于你希望继承的功能。
一些你可能会遇到控制访问和错误日志的默认位置(该指令access_log
和error_log
),配置文件操作(异步I / O aio
, sendfile
和directio
),并配置出现错误时服务器的状态( error_page
)。 其他指令配置压缩( gzip
和gzip_disable
),微调TCP保活设置( keepalive_disable
, keepalive_requests
和keepalive_timeout
),而Nginx的会跟着尝试优化包和系统调用的规则( sendfile
, tcp_nodelay
和tcp_nopush
) 。 附加指令配置应用程序级的文档根目录和索引文件( root
和index
),并设置了用于存储不同类型的数据的各种哈希表( *_hash_bucket_size
和*_hash_max_size
为server_names
, types
和variables
)。
服务器上下文
“服务器”上下文是“HTTP”范围内声明。 这是我们嵌套的,括号内的上下文的第一个例子。 它也是允许多个声明的第一个上下文。
服务器上下文的一般格式可能如下所示。 请记住,这些驻留在http上下文中:
# main context
http {
# http context
server {
# first server context
}
server {
# second server context
}
}
允许服务器上下文的多个声明的原因是每个实例定义了处理客户端请求的特定虚拟服务器。 您可以拥有所需数量的服务器块,每个服务器块都可以处理特定的连接子集。
由于多个服务器块的可能性和可能性,这种上下文类型也是第一个Nginx必须使用选择算法来做出决定。 每个客户端请求将根据在单个服务器上下文中定义的配置进行处理,因此Nginx必须基于请求的细节来决定哪个服务器上下文是最合适的。 决定服务器块是否将用于回答请求的指令是:
- 听 :IP地址/端口组合,这个服务器模块的设计做出回应。 如果客户端发出与这些值匹配的请求,则可能会选择此块来处理连接。
- 服务器名 :这个指令是用来选择处理的服务器模块的其他组件。 如果有多个具有相同特异性的listen命令的服务器块可以处理请求,Nginx将解析请求的“主机”头,并匹配该指令。
此上下文中的伪指令可以覆盖可能在http上下文中定义的许多指令,包括日志记录,文档根目录,压缩等。除了从http上下文中获取的指令之外,我们还可以将文件配置为尝试响应请求( try_files
),发行重定向和重写( return
和rewrite
),并设置任意变量( set
)。
位置上下文
你将定期处理的下一个上下文是位置上下文。 位置上下文与服务器上下文共享许多关系质量。 例如,可以定义多个位置上下文,每个位置用于处理某种类型的客户端请求,并且通过选择算法通过将位置定义与客户端请求匹配来选择每个位置。
而确定是否选择一个服务器块中的指令都在服务器环境中定义的,即在一个位置的处理请求的能力决定了组件位于位置定义 (在打开的位置块线)。
一般语法如下所示:
location match_modifier location_match {
. . .
}
位置块存在于服务器上下文中,与服务器块不同,它们可以嵌套在一起。 这可以用于创建更一般的位置上下文以捕获流量的某个子集,然后基于更具体的标准以及其中的附加上下文来进一步处理它:
# main context
server {
# server context
location /match/criteria {
# first location context
}
location /other/criteria {
# second location context
location nested_match {
# first nested location
}
location other_nested {
# second nested location
}
}
}
当基于所请求的IP地址/端口组合和“主机”报头中的主机名来选择服务器上下文时,位置块通过查看请求URI进一步划分服务器块内的请求处理。 请求URI是请求的域名或IP地址/端口组合之后的部分。
因此,如果客户端请求http://www.example.com/blog
端口80上时, http
, www.example.com
,端口80将所有被用来确定要选择的服务器块。 被选择的服务器之后,将/blog
部(请求URI),将针对所定义的位置的评估,以确定其进一步上下文应该被用来响应该请求。
您在位置上下文中可能看到的许多指令也可在父级别使用。 在这个级别的新指令,让您的文档根目录(境外到达的地点alias
),标注的位置,因为只有内部访问( internal
)和代理到其他服务器或位置(使用HTTP,FastCGI的,SCGI,和uwsgi代理)。
其他上下文
虽然上面的例子表示你将会遇到的Nginx的基本上下文,其他上下文也存在。 下面的上下文是分开的,因为它们依赖于更多的可选模块,它们仅在某些情况下使用,或者它们用于大多数人不会使用的功能。
我们不会讨论,虽然每个可用的上下文。 以下上下文将不会被深入讨论:
-
split_clients
:这个上下文配置服务器通过与基于百分比变量标记他们接收到的类别分割的客户端。 这些可以用于通过向不同主机提供不同的内容来进行A / B测试。 -
perl / perl_set
:这些上下文配置Perl的处理程序出现在的位置这将只用于用Perl处理。 -
map
:该上下文用于设置根据另一个变量的值的变量的值。 它提供了一个变量的值的映射,以确定应该设置第二个变量。 -
geo
:像上述背景下,这种情况下被用来指定一个映射。 但是,此映射专门用于对客户端IP地址进行分类。 它根据连接的IP地址设置变量的值。 -
types
:这个上下文再次用于映射。 此上下文用于将MIME类型映射到应与其关联的文件扩展名。 这通常是通过其来源到主文件中提供了Nginx的nginx.conf
配置文件。 -
charset_map
:这是一个映射上下文的另一个例子。 此上下文用于将转换表从一个字符集映射到另一个字符集。 在上下文头中,列出了两个集合,并且在正文中,发生映射。
下面的上下文不像我们到目前为止讨论的那些常见的,但是仍然非常有用的知道。
上游上下文
上游上下文用于定义和配置“上游”服务器。 基本上,这个上下文定义了一个命名的服务器池,Nginx可以代理请求。 在配置各种类型的代理时,可能会使用此上下文。
上游上下文应该放在http上下文中,在任何特定的服务器上下文之外。 一般形式看起来像这样:
# main context
http {
# http context
upstream upstream_name {
# upstream context
server proxy_server1;
server proxy_server2;
. . .
}
server {
# server context
}
}
然后可以通过服务器或位置块内的名称来引用上游上下文,以将某种类型的请求传递到已经定义的服务器池。 然后,上游将使用算法(默认情况下循环)来确定请求的具体服务器。 这个上下文给我们的Nginx的代理请求时做一些负载平衡的能力。
邮件上下文
虽然Nginx最常用作Web或反向代理服务器,但它也可以用作高性能邮件代理服务器。 用于此类指令的上下文适当地称为“邮件”。 邮件上下文在“主”或“全局”上下文(在http上下文之外)中定义。
邮件上下文的主要功能是提供用于在服务器上配置邮件代理解决方案的区域。 Nginx具有将认证请求重定向到外部认证服务器的能力。 然后,它可以提供对POP3和IMAP邮件服务器的访问,以便提供实际的邮件数据。 如果需要,还可以将邮件上下文配置为连接到SMTP中继主机。
一般来说,邮件上下文看起来像这样:
# main context
events {
# events context
}
mail {
# mail context
}
If上下文
可以建立“if”上下文以提供其中定义的指令的条件处理。 像传统编程中的if语句一样,如果给定的测试返回“true”,Nginx中的if指令将执行包含的指令。
Nginx中的if上下文由重写模块提供,这是此上下文的主要预期用途。 因为Nginx的将测试请求的条件与许多其他目的制指令,如果不应该被用于大多数形式条件执行。 这是Nginx的社区创建了一个名为页面这样一个重要的注意事项,如果是邪恶的 。
问题基本上是Nginx处理顺序可能经常导致意想不到的结果,似乎颠覆if块的意义。 被认为是可靠安全的这些环境内使用的唯一指令是return
和rewrite
指令(这种情况下是为创建的)。 另一件事使用时,如果背景是,它呈现一个要牢记try_files
在相同的情况下无用指令。
通常,if将被用于确定是否需要重写或返回。 这些通常存在于位置块中,所以常见的形式将如下所示:
# main context
http {
# http context
server {
# server context
location location_match {
# location context
if (test_condition) {
# if context
}
}
}
}
Limit_except上下文
该limit_except
上下文是用来限制一个位置上下文内使用的某些HTTP方法。 例如,如果只有特定的客户应获得的帖子内容,但每个人都应该有阅读内容的能力,你可以使用一个limit_except
块来定义这一要求。
上面的例子看起来像这样:
. . .
# server or location context
location /restricted-write {
# location context
limit_except GET HEAD {
# limit_except context
allow 192.168.1.1/24;
deny all;
}
}
这将应用上下文中的指令(为了限制访问)遇到,除了那些在上下文头中列出的任何HTTP方法的时候。 上述实施例的结果是,任何客户机可以使用GET和HEAD动词,但只从未来的客户192.168.1.1/24
的子网被允许使用其他方法。
关于上下文的一般规则
现在,您已经了解了在探索Nginx配置时可能会遇到的常见上下文,我们可以讨论一些在处理Nginx上下文时要使用的最佳实践。
在可用的最高上下文中应用指令
许多指令在多个上下文中有效。 例如,有相当多的指令可以放置在http,服务器或位置上下文中。 这使我们能够灵活地设置这些指令。
然而,作为一般规则,通常最好在适用的最高上下文中声明指令,并在必要时在较低的上下文中覆盖它们。 这是可能的,因为Nginx实现的继承模型。 使用这个策略有很多理由。
首先,在高级别声明允许你避免兄弟上下文之间不必要的重复。 例如,在下面的示例中,每个位置都声明了相同的文档根目录:
http {
server {
location / {
root /var/www/html;
. . .
}
location /another {
root /var/www/html;
. . .
}
}
}
您可以将根移动到服务器块,甚至移动到http块,如下所示:
http {
root /var/www/html;
server {
location / {
. . .
}
location /another {
. . .
}
}
}
大多数时候,服务器级别将是最合适的,但是在更高级别上声明具有其优点。 这不仅允许您在较少的位置设置指令,还允许您将默认值级联到所有子元素,从而防止通过在较低级别上遗漏指令而导致错误的情况。 这可能是长配置的主要问题。 在更高级别上声明为您提供一个合理的默认。
使用多个同级上下文而不是处理的逻辑
当你想根据在客户端请求中找到的一些信息来处理请求时,用户经常跳到“if”上下文来尝试对处理进行条件化。 这里有一些问题,我们在前面简要介绍过。
第一个是“if”指令经常返回不符合管理员期望的结果。 虽然处理将总是导致相同的结果给定相同的输入,Nginx解释环境的方式可以大大不同,可以假设没有重测试。
第二个原因是,已经有优化的,专用的指令用于许多这些目的。 Nginx已经参与了一个记录良好的选择算法,比如选择服务器块和位置块。 因此,如果可能,最好尝试将您的不同配置移动到自己的块中,以便此算法可以处理选择过程逻辑。
例如,不是依赖于重写来获得用户提供的请求到你想要使用的格式,你应该尝试为请求设置两个块,其中一个代表所需的方法,另一个捕获凌乱的请求和重定向(并可能重写)他们到你正确的块。
结果通常更容易阅读,还具有更高性能的附加好处。 正确的请求不经过任何额外的处理,并且在许多情况下,不正确的请求可以通过重定向而不是重写来获得,应当以较低的开销执行。
结论
到这一点,你应该很好地掌握Nginx最常见的上下文和指令,创建定义它们的块。
经常检查Nginx的文档有关哪些环境指令可以放置在并评估最有效的位置信息。 在创建配置时注意不仅会增加可维护性,而且还会提高性能。