/ HTTP

[译] 如何在Ubuntu 16.04上部署支持HTTP / 2的Nginx

原文:How To Set Up Nginx with HTTP/2 Support on Ubuntu 16.04 | DigitalOcean
作者:Sergey Zhukaev


介绍

NGINX 是一个快速可靠的开源Web服务器。由于其内存占用空间小,可扩展性高,易于配置,并支持绝大多数协议,因此受到欢迎。
本教程将帮助您部署一个支持HTTP / 2 的快速,安全的 Nginx 服务器。

前提

在开始之前,我们需要几件事情:

HTTP 1.1和HTTP / 2之间的区别

HTTP / 2 是超文本传输​​协议的新版本,在 Web 上用于从服务器到浏览器传送页面。HTTP / 2 是近二十年来 HTTP 的第一个主要更新:HTTP1.1在1999年被引入公众,当时网页一般是一个带有内联CSS样式表的HTML文件。互联网自那以后发生了巨大的变化,现在我们面临着HTTP 1.1的局限性——该协议限制了大多数现代网站的潜在传输速度,因为它下载页面的过程是一个队列(下一部分开始下载前,前一部分必须下载完),一般现代网页需要大约100个请求下载(每个请求都是图片,js文件,css文件等等)。

HTTP / 2解决了这个问题,因为它带来了一些根本性的变化:

  • 所有请求都是并行下载的,而不是在队列中
  • HTTP头部被压缩
  • 页面作为二进制文件传输,而不是作为文本文件,这更高效
  • 即使没有用户的请求,服务器也可以“推送”数据,这样可以提高延迟较高用户的速度

尽管HTTP / 2不需要加密,但两款最受欢迎的浏览器(Chrome浏览器和Mozilla Firefox)的开发人员表示,为了安全起见,他们将仅为HTTPS 连接提供HTTP / 2支持。因此,如果您决定在服务器支持HTTP / 2,则必须使用HTTPS。

步骤1 - 安装最新版本的Nginx

在Nginx 1.9.5中加入了HTTP / 2协议的支持。幸运的是,Ubuntu 16.04中的默认镜像源包含的nginx版本高于此版本,因此我们不必添加第三方镜像源。
首先,在apt包系统中更新可用包的列表:

$ sudo apt-get update

然后,安装Nginx:

$ sudo apt-get install nginx

安装过程完成后,您可以键入以下内容检查Nginx的版本:

$ sudo nginx -v

输出应类似于以下内容:

// sudo nginx -v 输出结果
nginx version: nginx/1.10.0 (Ubuntu)

在接下来的几个步骤中,我们将修改Nginx配置文件。每个步骤都将更改Nginx配置选项。我们将一路测试配置文件的语法。最后,我们将验证Nginx是否支持HTTP / 2,并进行一些更改以优化性能。

步骤2 - 更改收听端口并启用HTTP / 2

我们的第一个更改是将监听端口80改为443。

打开配置文件:

$ sudo nano /etc/nginx/sites-available/default

默认情况下,Nginx设置为监听80端口,这是标准的HTTP端口:

// 在/etc/nginx/sites-available/default中
listen 80 default_server;
listen [::]:80 default_server;

你可以看到,我们有两个不同的listen变量。第一个是用于所有IPv4连接。第二个是用于IPv6连接。我们将为两者启用加密。

修改监听端口为HTTPS协议使用的443:

// 在/etc/nginx/sites-available/default中
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;

注意,除 ssl 之外,我们还加入 http2 。该变量告诉Nginx对支持HTTP2协议的浏览器启用HTTP / 2。

步骤3 - 更改服务器名称

我们使用server_name条目来指定哪个域名与配置文件相关联。找到server_name配置文件中的条目。

默认情况下,server_name设置为 _(下划线),这意味着配置文件负责所有传入的请求。更改 _ 为你的实际域名,如下所示:

server_name example.com;

保存配置文件并退出文本编辑器。。

每当您对Nginx配置文件进行更改时,应检查配置中是否存在语法错误,如下所示:

$ sudo nginx -t

如果语法无错误,你将看到以下输出:

// sudo nginx -t的输出
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

步骤4 - 添加SSL证书

接下来,您需要配置Nginx以使用您的SSL证书。如果您不知道什么是SSL证书,或者目前没有SSL证书,请按照本文“前提”部分中的其中一个教程进行操作。

创建一个目录以将您的SSL证书存储在Nginx配置目录中:

$ sudo mkdir /etc/nginx/ssl

将您的证书和私钥复制到此路径。我们还将重命名文件以显示它们所关联的域名。当您有多个域与此服务器关联时,将来将会派上用场。替换example.com为您的实际主机名:

$ sudo cp /path/to/your/certificate.crt /etc/nginx/ssl/example.com.crt
$ sudo cp /path/to/your/private.key /etc/nginx/ssl/example.com.key

现在,我们再次打开我们的配置文件,并配置SSL。

$ sudo nano /etc/nginx/sites-available/default

在server块内的新行上,定义证书的位置:

// 在/etc/nginx/sites-available/default中
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

保存文件,并退出文本编辑器。

步骤5 - 避免旧加密套件

HTTP / 2有一个巨大的黑名单包含旧的和不安全的密码,所以我们必须避免它们。加密套件是一堆加密算法,它们描述了传输数据的加密方式。
我们将使用一个非常受欢迎的密码集,其安全性被CloudFlare等互联网巨头批准。它不允许使用MD5加密(自1996年以来被标记为不安全,虽然存在这一事实,但目前为止它还在被使用)。

打开以下配置文件:

$ sudo nano /etc/nginx/nginx.conf

ssl_prefer_server_ciphers on;之后添加下面这行。

// 在/etc/nginx/nginx.conf中
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

保存文件,并退出文本编辑器。
再次检查配置语法错误:

$ sudo nginx -t

步骤6 - 增加密钥交换安全性

建立安全连接的第一步是在服务器和客户端之间交换私钥。问题是,这个时候,它们之间的连接没有加密 —— 这意味着传输的数据对任何第三方都是可见的。这就是为什么我们需要Diffie-Hellman-Merkle算法。关于它如何工作的技术细节是一个复杂的事情,无法简单解释,但如果您对细节感兴趣,则可以观看此YouTube视频
默认情况下,Nginx使用1028位DHE(短暂的Diffie-Hellman)密钥,这是相对容易解密的。为了提供最大的安全性,我们应该建立自己的,更安全的DHE密钥。
要做到这一点,请键入以下命令:

$ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

请记住,我们应该在与SSL证书相同的文件夹中生成DH参数。在本教程中,证书位于/etc/nginx/ssl/。原因是Nginx总是在证书文件夹中查找用户提供的DHE密钥,如果存在,则使用它。

在文件路径(在我们的例子中2048)之后的变量指定密钥的长度。2048位长度的密钥是足够安全的,由Mozilla基金会推荐,但如果您正在寻找更多的加密,则可以将其更改为4096

生成过程大约需要5分钟。
一旦完成,再次打开默认的Nginx配置文件:

$ sudo nano /etc/nginx/sites-available/default 

server 块内的新行中,设置自定义DHE密钥的路径:

// 在/etc/nginx/sites-available/default中
ssl_dhparam  /etc/nginx/ssl/dhparam.pem;

步骤7 - 将所有HTTP请求重定向到HTTPS

由于我们希望仅通过HTTPS提供内容,所以我们应该告诉Nginx如果服务器收到HTTP请求应该做什么。

在我们的文件底部,我们将创建一个新的server块,用于将所有HTTP请求重定向到HTTPS(请务必使用实际的域名替换服务器名称):

// 在/etc/nginx/sites-available/default中
server {
       listen         80;
       listen    [::]:80;
       server_name    example.com;
       return         301 https://$server_name$request_uri;
}

保存并退出配置文件。
检查语法错误的配置:

$ sudo nginx -t

步骤8 - 重新加载Nginx

这就是所有的Nginx配置更改。由于我们检查每个更改的语法错误,您应该准备好重新启动Nginx并测试更改。
总而言之,忽略注释掉的行,您的配置文件现在应该类似于:

// 在/etc/nginx/sites-available/default中
server {
        listen 443 ssl http2 default_server;
        listen [::]:443 ssl http2 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name example.com;

        location / {
                try_files $uri $uri/ =404;
        }

        ssl_certificate /etc/nginx/ssl/example.com.crt;
        ssl_certificate_key /etc/nginx/ssl/example.com.key;
        ssl_dhparam /etc/nginx/ssl/dhparam.pem;
}


server {
       listen         80;
       listen    [::]:80;
       server_name    example.com;
       return         301 https://$server_name$request_uri;
}

要更改生效,请重新启动Nginx服务器。

# sudo systemctl restart nginx

步骤9 - 验证变更

我们来检查一下我们的服务器是否正常运行。打开您的网络浏览器并导航到您的域(替换example.com为您的实际域名):

example.com

如果一切配置正确,您应该自动重定向到HTTPS。现在,我们来看看HTTP / 2是否正常工作:打开Chrome开发工具(View - > Developer - > Developer Tools)并重新加载页面(View - > Reload This Page)。然后导航到 Network 选项卡,指向从Name开始的表头所在行,右键单击它,然后选择 Protocol 选项。
现在您应该看到h2(代表HTTP / 2)的新列,表示您的网站提供HTTP / 2服务。

在这一点上,我们的服务器已经准备好通过HTTP / 2协议提供内容了,但是我们仍然需要为生产环境的服务器做一些准备。

步骤10 - 优化Nginx以获得最佳性能

首先,我们 nginx.conf 通过在控制台中键入以下内容来打开它们:
在此步骤中,我们将调整主Nginx配置文件,以获得最佳性能和安全性。

$ sudo nano /etc/nginx/nginx.conf

启用连接凭据缓存

与HTTP相比,HTTPS需要相对较长的时间来建立服务器和用户之间的初始连接。为了最小化页面加载速度的差异,我们将启用连接凭据的缓存。这意味着,不是在所请求的每个页面上创建一个新的会话,服务器将使用缓存版本的凭据。
要启用会话缓存,http 请在 nginx.conf 文件块的末尾添加这些行:

// 在/etc/nginx/nginx.conf中
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 1h;

ssl_session_cache 指定将包含会话信息的高速缓存的大小。1 MB可以存储大约4000个会话的信息。对于大多数用户来说,默认值为5 MB是足够的,但如果您预期流量很大,则可以相应地增加该值。
ssl_session_timeout 限制特定会话存储在缓存中的时间。该值不应该太大(超过一个小时),但是将值设置得太低也是没有意义的。

启用HTTP严格传输安全(HSTS)

即使我们已经将所有常规HTTP请求重定向到我们的Nginx配置文件中的HTTPS,我们还应该启用HSTS,以避免这些重定向操作。
如果浏览器找到HSTS头部,则在给定的时间段内不会再尝试通过常规HTTP连接到服务器。无论如何,它将只使用加密的HTTPS连接交换数据。这个头部还能保护我们免受协议降级攻击。

将以下行添加到nginx.conf:

// 在/etc/nginx/nginx.conf中
add_header Strict-Transport-Security "max-age=15768000" always;

max-age以秒为单位设定。15768000秒相当于6个月。
默认情况下,此头部不会添加到子域请求中。如果您有子域名并希望HSTS适用于所有这些域,则应在该行的末尾添加includeSubDomains变量,如下所示:

// 在/etc/nginx/nginx.conf中
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;

保存文件,并退出文本编辑器。
再次检查配置语法错误:

$ sudo nginx -t

最后,重新启动Nginx服务器以应用更改。

$ sudo systemctl restart nginx

结论

您的Nginx服务器现在提供HTTP / 2页面。如果您想测试SSL连接的强度,请访问 Qualys SSL实验室,并针对您的服务器运行测试。如果一切配置正确,您应该获得一个A +标记的安全。