nginx
工程师们喜欢认为他们的决策是基于纯粹的逻辑和优点。但当然,每个人在编程语言、编辑器和其他技术方面都有偏见——这些偏见或许可以用技术术语来辩护,但往往更多的是一种情感上的争论,而不是技术上的争论。(当然,Emacs 除外,它显然是所有客观标准下最好的编辑器。)这种偏见的问题在于,它们可能导致人们做出感觉舒适但未必正确的选择和决定。
举个例子:我使用 Apache HTTP 服务器已经很多年了。事实上,你可以说我从 Apache 甚至不叫 “Apache” 的时候就开始使用它了——最初是 NCSA HTTP 服务器,然后是一些有进取心的开源开发者发布的补丁服务器,最后是 Apache 基金会支持的开源巨头,如今每个人都认识甚至依赖它——它所做的远不止生产 HTTP 服务器。
Apache 的天才之处在于它的模块化。你可以用最少的努力配置 Apache 以使用自定义的模块配置。如果你想要一个功能齐全的服务器,具有大量的调试和诊断功能,你可以做到。如果你想要在服务器内部嵌入 Perl 和 Tcl 等高级语言,以实现高速 Web 应用程序,你可以做到。如果你需要匹配、分析和重写 HTTP 事务的每个部分的能力,你可以使用 mod_rewrite
来做到。当然,也有第三方模块。
随着 Web 规模的扩大,以及 Web 站点被期望做越来越多的事情,情况变得更好了。可扩展性成为一个重要问题,而 Apache 通过(毫不奇怪)各种实现不同后端方案的模块来处理它。你可以拥有传统的进程混合,或者使用线程,或者两者结合使用。
除了灵活性之外,很明显 Apache httpd 维护良好、文档完善且稳定。安装容易,升级容易——真的,一切都很容易。
因此,Apache 一直是我在 HTTP 服务器方面的首选,这并不奇怪。然而,我总是在潜意识里知道,我真的应该花更多时间去研究其他选择。特别是,有一个替代方案脱颖而出——nginx。
Apache 主要设计为模块化,而 nginx 则设计为快速——非常快。此外,它的设计目的是在处理大量并发请求时保持快速。这归功于它的网络方法,这与 Apache 的方法截然相反。Apache httpd 为每个传入的 HTTP 连接分配一个新进程。因此,如果当前有 1,000 个同时连接到你的 Web 站点,那么你的计算机上将运行 1,000 个 Apache 进程。如果你使用多线程,你可以预期有 1,000 个独立的线程为这 1,000 个请求提供服务。
nginx 采取相反的方法,使用单个进程且不使用线程。这意味着在 nginx 中,这 1,000 个并发连接将由一个进程处理,轮流检查每个连接,看看是否有数据要发送或接收。这种设计网络软件的 “反应器” 模式最近变得流行起来,node.js 和 Python 3.5 的事件驱动添加都证明了人们对这种编写代码方式的兴趣。
所以,是的,nginx 很快。它甚至也是模块化的,尽管模块不能像 Apache 那样动态添加。相反,它们必须编译到 nginx 中才能使用。因此,从 nginx 中添加和删除功能,虽然当然是可能的,但不如 Apache 那样灵活,Apache 不需要重新编译。
在本文中,我将介绍 nginx 的基本安装和配置,以运行一个简单的 Web 应用程序。在此过程中,你将看到配置在风格和执行上与 Apache 有何不同,以及如果你要使用 nginx,你需要如何思考。
安装多年前,如果你想安装几乎任何开源软件,你需要下载一个 .tar.gz 文件,打开它,修改配置,编译它并安装它。当然,今天你可以在运行 Debian 或 Ubuntu 的 Linux 机器上使用简单的 apt-get
命令安装东西。例如,我可以按如下方式安装 nginx
apt-get install nginx
但是,等一下。如果 nginx 在我编译后不能修改,也许我应该检查一下如何修改从默认安装中获得的配置。当然,虽然你可以更改服务器配置,但你不能更改编译到服务器中的模块。因此,在安装 nginx 之前,确保正确的模块编译到 nginx 中非常重要。
在我用于测试的 Ubuntu 14.04 服务器上,运行 apt-cache search nginx
显示了以下选项
-
nginx-extras
-
nginx-full
-
nginx-light
哪一个适合你,或者你应该尝试其他的东西?当然,答案取决于你想做什么。
如果你想提供静态文件,这些中的任何一个都可以很好地完成任务。即使是 nginx-light,最小的一个,也内置了 SSL、gzip 和重写等功能。事实上,nginx-light 甚至包括 fastcgi,如果你想运行像 WordPress 这样的程序,你需要这个模块。
但是,假设你想使用 Phusion Passenger 插件部署 Ruby on Rails 应用程序。你应该安装哪个版本的 nginx 来运行它?答案很简单,“都不是”。为了安装 Passenger,nginx 需要重新编译。说来也怪,这并不像你想象的那么痛苦。然而,这确实意味着在你甚至可以决定如何安装 nginx 之前,你需要考虑你想用它做什么。
静态页面让我们从在 Ubuntu 下安装 nginx-lite 包开始探索 nginx,然后看看配置以及如何让一个基本的静态站点运行起来。
首先,我将安装 nginx-core 包
$ sudo apt-get install nginx-core
然后我可以使用相当标准的 shell 命令启动服务器
$ sudo service nginx start
稍等片刻,nginx 将启动,我可以输入以下命令来判断
$ sudo serviced nginx status
我得到了回应
nginx is running
如果我转到当前服务器的主页,我会被 “Welcome to nginx!” 欢迎。
但当然,我真的希望那里有我自己的内容。让我们看看配置文件,它在我的系统上是 /etc/nginx/nginx.conf,看看它的格式以及如何更改它以制作一些自定义的静态内容。
现在,如果你习惯了 Apache 配置文件,nginx 文件的风格会让你需要一些时间来适应。与 Apache 类似,每一行都包含一个名称-值样式的配置设置。与 Apache 不同的是,节是用花括号 ({ }) 分隔的,并且每一行都必须以分号 (;) 结尾。例如,我安装的默认 nginx 配置文件中的第一行是
user www-data;
这意味着 nginx 将以 www-data 用户身份运行,这在 Ubuntu(和 Debian)世界中非常标准。接下来是配置参数
worker_processes 4;
这描述了 nginx 在运行时应启动多少进程。但是,这似乎与我上面写的相矛盾,即 nginx 仅使用单个进程(并且该进程内没有线程)以获得额外的速度,不是吗?嗯,是的,也不是——想法是你可能希望服务器上的每个 CPU 核心都有一个 nginx 工作进程。在这台服务器上,我有四个核心,每个核心可以(并且应该)有一个 nginx 工作进程。你可以将其视为负载均衡器的单计算机版本,将负载分配到可用的 CPU 上。每个工作进程可以并且将处理大量的网络连接。
如果你的服务器将运行的不仅仅是 nginx——例如,如果你在同一台机器上运行数据库服务器——你可能希望减少这个数字,以便至少有一个核心始终可用于那些其他进程。
默认配置文件然后包含一个 “events” 部分
events {
worker_connections 768;
# multi_accept on;
}
在这里,我设置了 worker_connections
——意思是,每个工作进程可以同时处理多少个网络连接?在本例中,它设置为 768;我不确定这个数字来自哪里,但这意味着如果我的站点变得受欢迎,我可能会发现我的网络连接用完了。你很可能想要提高这个数字。
multi_accept
指令默认情况下被注释掉,但也默认设置为 “on”——这意味着 nginx 愿意接受到达的新连接,一次处理多个连接。我想不出有什么好的理由关闭它。
接下来是一个 “http” 部分,你不会惊讶地听到它与系统建立的 HTTP 连接有关。
这些配置指令中的大多数不会立即引起你的兴趣;正如你所看到的,nginx 的日志记录指令与 Apache 和其他服务器中的指令类似
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
站点的位置在哪里定义的?在 nginx 的情况下,它不是直接在 “http” 块内。相反,它位于另一个配置文件中——或者更准确地说,是服务器上配置的站点的配置文件集中
include /etc/nginx/sites-enabled/*;
因为我正在一台尚未用于其他用途的计算机上使用全新安装的 nginx,所以只配置了一个服务器。你可以很容易地想象这样一种情况,即一台计算机被配置为与数十甚至数百个不同的站点一起工作,每个站点都有自己的配置文件。然而,在这种情况下,我将只使用 “default” 服务器,此处定义为
/etc/nginx/sites-enabled/default
该文件以 “server” 部分开头,描述了 nginx 应该监听的单个端口。这意味着如果你想监听多个端口——例如,端口 80 用于 HTTP,端口 443 用于 HTTPS——你需要在单独的块中配置这些端口。这个 “server” 块以以下内容开头
listen 80 default_server;
这意味着它将监听端口 80,并且这是系统的默认服务器。考虑一台运行 nginx 的计算机,它使用虚拟主机托管了数十个站点。使用 default_server
,你可以告诉 nginx 哪个站点将接受未被另一个虚拟主机声明的名称的请求。
最后,这里有两行告诉 nginx 在哪里查找我的文件
root /usr/share/nginx/html;
index index.html index.htm;
root
指令告诉 nginx 在哪个目录中查找。index
指令指示如果有人请求目录——在本例中是简单的 URL “/”——应该提供哪个文件。
因此,我知道要修改我的(当前,默认)静态 Web 站点,我需要编辑文件 /usr/share/nginx/html/index.html。果然,如果我在服务器的文件系统中查看该位置,我会看到 “Welcome to nginx” 文件。通过更改该文件,我可以更改我的站点的外观。
使用 PHP但是,如果我想使用服务器端语言,我就倒霉了。按照当前的配置,nginx 不会让我使用 PHP 或任何其他语言。如果我只是将文件重命名为 index.php 并在其中添加一行 PHP 代码
<?php echo 'Hello World
'; ?>
那么充其量,我会将源文件下载到我的浏览器,而不会执行任何 PHP 代码。最坏的情况是,事情会直接失败。
所以,让我们弄清楚这一点。首先,如果我要使用 PHP,我需要在我的服务器上安装该语言。请注意,在 Ubuntu 中安装整个 php5 包然后尝试安装 Apache,这显然不是这里的目标!因此,我将只安装一些选定的软件包
$ sudo apt-get install php5-cli php5-fpm
什么是 php5-fpm?它是 “FastCGI” 的缩写,FastCGI 是多年前建立的标准,目的是减少 CGI(即外部)程序的开销,Web 服务器会运行这些程序以创建自定义的动态页面。与其为每个 HTTP 请求启动一次外部程序,不如只启动一次,每次 HTTP 请求传入时都执行已启动的程序。因此,我需要设置 PHP 以使用 FastCGI 协议。
这是通过服务器完成的,你需要安装和配置服务器。想法是 nginx 将收到对包含 PHP 的文件的请求;它将使用 FastCGI 调用 PHP,然后将程序的输出返回给用户的浏览器。
有几种方法可以设置 FastCGI 服务器。我使用了 UNIX 套接字,如果两个程序都在同一台服务器上,则允许它们进行通信。你可以改为使用网络套接字,在这种情况下,FastCGI 服务器可以存在于与 nginx 服务器不同的计算机上,但对于这里的示例来说,这有点过头了。
为了使其工作,我需要修改 PHP 的 FastCGI 实现的配置。我所做的更改是在文件 /etc/php5/fpm/pool.d/www.conf 中,该文件随我的 PHP 配置一起提供。在该文件中,有一行(被注释掉)带有 listen
值。我将其设置为使用 UNIX 套接字,如下所示
listen = /var/run/php5-fpm.sock
完成此操作后,我重新启动了 PHP 的 FastCGI 服务器
sudo service php5-fpm restart
这重新启动了 PHP 的兼容 FastCGI 的服务器,使 nginx 可以与服务器通信。
将 nginx 连接到 PHP有了这个基础,我只需要告诉 nginx 何时调用 FastCGI 服务器以及它如何联系该服务器。
首先,我更改了 index
行以查找文件 index.php,方法是替换之前的 index
行
location / {
index index.php;
}
现在,当 HTTP 请求进入目录时,它将提供 index.php。
接下来,我需要告诉 nginx 当它看到以 “.php” 后缀结尾的文件时使用 FastCGI
location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME
↪/usr/share/nginx/html$fastcgi_script_name;
}
这里最重要的两行是 fastcgi_pass
,它必须指向我创建的套接字文件,以及 fastcgi_param
,它指示 FastCGI 程序的位置。在上面的 fastcgi_param
指令中,我指示 /usr/share/nginx/html 中带有 “.php” 后缀的文件将在正确的位置执行。
另请注意 include
行,它将大量与 FastCGI 相关的指令导入到系统中。如果你愿意,可以查看它,但我使用 FastCGI 多年了,并且倾向于将许多配置选项视为接近黑魔法的东西。
现在你已经看到你可以使用 PHP 配置 nginx,你可以朝几个方向发展。首先,你不仅可以使用 PHP 创建简单的 “hello, world” 程序,还可以运行真正的应用程序,例如基于 WordPress 的应用程序(WordPress 是用 PHP 编写的)。下个月,我将描述如何将 nginx 连接到 WordPress 以获得稳健且高速的解决方案。
但是,nginx 也可以与其他语言一起使用,而不仅仅是 PHP。我在过去讨论过的 Phusion Passenger 不仅可以与 Apache 一起使用,还可以与 nginx 一起使用。唯一的问题是,由于在添加或删除(或更新)模块时必须重新编译 nginx,因此安装可能有点棘手。
底线是 nginx,虽然像我这样的老 Apache 用户需要一些时间来适应,但事实证明它很灵活、文档完善,并且(当然)在处理 Web 流量方面非常高效。如果你正在设置一个新的 Web 服务器,并且认为你可能需要从系统中挤出更多的 “能量”,那么绝对值得研究一下 nginx。
资源nginx 是一个流行的服务器,因此,有很多关于它的信息来源。最好的来源之一是由成立以开发和支持 nginx 的公司运营的 官方网站。从该网站,你可以阅读大量高质量的文档,包括一个包含许多用户提交的建议的 Wiki。