简介
TLS,即传输层安全协议,及其前身SSL,即安全套接字层,是用于将普通流量包装在受保护的加密包装中的网络协议。
使用这项技术,服务器可以在服务器和客户端之间安全地发送流量,而不会被外部方拦截。证书系统还帮助用户验证他们正在连接的站点的身份。
在本指南中,我们将向您展示如何在 Ubuntu 16.04 服务器上为 Nginx web 服务器设置自签名 SSL 证书。
先决条件
在开始之前,您应该已经配置了一个具有sudo权限的非根用户。您可以按照我们的 Ubuntu 16.04 初始服务器设置指南来了解如何设置此类用户帐户。
您还需要已安装 Nginx web 服务器。如果您想在服务器上安装完整的 LEMP(Linux、Nginx、MySQL、PHP)堆栈,可以按照我们的 Ubuntu 16.04 上设置 LEMP 的指南进行操作。
如果您只想要 Nginx web 服务器,可以按照我们的 Ubuntu 16.04 上安装 Nginx 的指南进行操作。
完成先决条件后,请继续以下操作。
步骤 1:创建 SSL 证书
TLS/SSL 通过使用公共证书和私钥的组合来工作。SSL 密钥在服务器上保密。它用于加密发送给客户端的内容。SSL 证书与请求内容的任何人公开共享。它可用于解密由相关 SSL 密钥签名的内容。
我们可以使用 OpenSSL 一次性创建自签名密钥和证书对:
1
|
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt
|
您将被要求回答一系列问题。在我们讨论这些问题之前,让我们看看我们正在发出的命令中发生了什么:
- openssl:这是用于创建和管理 OpenSSL 证书、密钥和其他文件的基本命令行工具。
- req:此子命令指定我们要使用 X.509 证书签名请求(CSR)管理。“X.509” 是 SSL 和 TLS 遵循的用于其密钥和证书管理的公钥基础设施标准。我们要创建一个新的 X.509 证书,因此我们正在使用此子命令。
- -x509:这通过告诉实用程序我们要创建自签名证书,而不是生成证书签名请求,进一步修改了前一个子命令。
- -nodes:这告诉 OpenSSL 跳过使用密码短语保护我们的证书的选项。我们需要 Nginx 能够在服务器启动时无需用户干预地读取文件。密码短语会阻止这种情况发生,因为我们每次重新启动后都需要输入密码。
- -days 365:此选项设置证书被视为有效的时间长度。我们在这里设置为一年。
- -newkey rsa:2048:这指定我们要同时生成新证书和新密钥。我们没有在之前的步骤中创建用于签署证书的密钥,因此我们需要同时创建它和证书。rsa:2048 部分告诉它生成一个长度为 2048 位的 RSA 密钥。
- -keyout:此行告诉 OpenSSL 在哪里放置我们正在创建的生成私钥文件。
- -out:这告诉 OpenSSL 在哪里放置我们正在创建的证书。
正如我们上面所述,这些选项将创建一个密钥文件和一个证书。我们将被要求关于我们的服务器的一些问题,以便将信息正确嵌入证书中。
适当填写提示。最重要的一行是请求“通用名称(例如服务器 FQDN 或您的名称)”。您需要输入与您的服务器关联的域名或更可能是您服务器的公共 IP 地址。
提示的全部内容将类似于以下内容:
1
2
3
4
5
6
7
|
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:New York City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Bouncy Castles, Inc.
Organizational Unit Name (eg, section) []:Ministry of Water Slides
Common Name (e.g. server FQDN or YOUR name) []:server_IP_address
Email Address []:admin@your_domain.com
|
您创建的两个文件将放置在/etc/ssl目录的适当子目录中。
当我们使用 OpenSSL 时,我们还应该创建一个强大的 Diffie-Hellman 组,用于与客户端协商完美前向保密。
我们可以通过输入以下内容来实现:
1
|
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
|
这可能需要几分钟的时间,但完成后,您将在/etc/ssl/certs/dhparam.pem上拥有一个强大的 DH 组,我们可以在我们的配置中使用。
步骤 2:配置 Nginx 使用 SSL
我们已经在 /etc/ssl 目录下创建了我们的密钥和证书文件。现在我们只需要修改我们的 Nginx 配置以利用这些文件。
我们将对我们的配置进行一些调整。
- 我们将创建一个包含 SSL 密钥和证书文件位置的配置片段。
- 我们将创建一个包含强大 SSL 设置的配置片段,这些设置可以在将来与任何证书一起使用。
- 我们将调整我们的 Nginx 服务器块以处理 SSL 请求,并使用上述两个片段。
这种配置 Nginx 的方法将允许我们保持清晰的服务器块,并将常见的配置段放入可重用的模块中。
创建指向 SSL 密钥和证书的配置片段
首先,让我们在 /etc/nginx/snippets 目录下创建一个新的 Nginx 配置片段。
为了正确区分该文件的目的,让我们将其命名为 self-signed.conf:
1
|
sudo nano /etc/nginx/snippets/self-signed.conf
|
在这个文件中,我们只需要将 ssl_certificate 指令设置为我们的证书文件,将 ssl_certificate_key 设置为相关的密钥。在我们的情况下,这将如下所示:
1
2
|
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
|
当您添加了这些行后,保存并关闭文件。
创建包含强加密设置的配置片段
接下来,我们将创建另一个片段,用于定义一些 SSL 设置。这将使用强大的 SSL 密码套件并启用一些高级功能,有助于保持我们的服务器安全。
我们将设置的参数可以在将来的 Nginx 配置中重复使用,因此我们将给文件一个通用的名称:
1
|
sudo nano /etc/nginx/snippets/ssl-params.conf
|
为了安全地设置 Nginx SSL,我们将使用 Remy van Elst 在 Cipherli.st 网站上的建议。该网站旨在为流行软件提供易于消化的加密设置。您可以在这里阅读更多关于他在 Nginx 选择方面的决定。
对于我们的目的,我们可以完全复制所提供的设置。我们只需要做一些小的修改。
首先,我们将添加我们首选的上游请求的 DNS 解析器。在本指南中,我们将使用 Google 的解析器。我们还将设置 ssl_dhparam 设置,指向我们之前生成的 Diffie-Hellman 文件。
最后,您应该花一点时间了解 HTTP 严格传输安全性(HSTS),特别是关于“preload”功能。预加载 HSTS 提供了增强的安全性,但如果意外启用或错误启用可能会产生深远的后果。在本指南中,我们不会预加载这些设置,但如果您确信理解了其影响,可以进行修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 来自 https://cipherli.st/
# 和 https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# 暂时禁用预加载 HSTS。如果您理解其影响,可以使用包含“preload”指令的已注释的头行。
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
因为我们使用的是自签名证书,所以 SSL stapling 将不会被使用。Nginx 将简单地输出警告,为我们的自签名证书禁用 stapling,并继续正常运行。
完成后保存并关闭文件。
调整 Nginx 配置以使用 SSL
现在我们有了我们的片段,我们可以调整我们的 Nginx 配置以启用 SSL。
在本指南中,我们假设您正在使用 /etc/nginx/sites-available 目录中的 default 服务器块文件。如果您使用不同的服务器块文件,请在下面的命令中替换其名称。
在继续之前,让我们先备份当前的服务器块文件:
1
|
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak
|
现在,打开服务器块文件进行调整:
1
|
sudo nano /etc/nginx/sites-available/default
|
在文件中,您的服务器块可能开始如下所示:
1
2
3
4
5
6
7
8
9
10
|
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
. . .
|
我们将修改此配置,以便将未加密的 HTTP 请求自动重定向到加密的 HTTPS。这为我们的站点提供了最佳安全性。如果您希望允许 HTTP 和 HTTPS 流量,请使用以下备用配置。
我们将把配置分成两个单独的块。在两个第一条 listen 指令之后,我们将添加一个 server_name 指令,设置为您的服务器域名或更可能的 IP 地址。然后,我们将设置一个重定向到我们将要创建的第二个服务器块。之后,我们将关闭这个简短的块:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server_domain_or_IP;
return 302 https://$server_name$request_uri;
}
# SSL configuration
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
. . .
|
接下来,我们需要在下面直接开始一个新的服务器块,以包含剩余的配置。我们可以取消注释使用端口 443 的两个 listen 指令。我们可以在这些行中添加 http2 以在此块中启用 HTTP/2。之后,我们只需要包含我们设置的两个片段文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server_domain_or_IP;
return 302 https://$server_name$request_uri;
}
server {
# SSL configuration
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
. . .
|
完成后保存并关闭文件。
(备用配置)允许 HTTP 和 HTTPS 流量
如果您希望或需要允许加密和非加密内容,您将需要稍微不同地配置 Nginx。一般来说,如果可以避免,这通常是不建议的,但在某些情况下可能是必要的。基本上,我们将两个单独的服务器块压缩成一个块,并删除重定向:
1
2
3
4
5
6
7
8
9
10
11
|
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name server_domain_or_IP;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
. . .
|
完成后保存并关闭文件。
步骤 3:调整防火墙
如果您已经启用了 ufw 防火墙,如先决指南中推荐的那样,您需要调整设置以允许 SSL 流量。幸运的是,Nginx 在安装时会向 ufw 注册一些配置文件。
我们可以通过输入以下命令来查看可用的配置文件:
您应该会看到以下类似的列表:
1
2
3
4
5
|
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
|
您可以通过输入以下命令来查看当前设置:
它可能看起来像这样,意味着只有 HTTP 流量被允许访问 Web 服务器:
1
2
3
4
5
6
7
8
|
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx HTTP ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx HTTP (v6) ALLOW Anywhere (v6)
|
为了额外允许 HTTPS 流量,我们可以允许 “Nginx Full” 配置文件,然后删除多余的 “Nginx HTTP” 配置文件允许:
1
2
|
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
|
现在您的状态应该是这样的:
1
2
3
4
5
6
7
8
|
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx Full ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
|
步骤 4:启用 Nginx 中的更改
现在我们已经做出了更改并调整了防火墙,我们可以重新启动 Nginx 来实施我们的新更改。
首先,我们应该检查我们的文件中是否有语法错误。我们可以通过输入以下命令来执行此操作:
如果一切顺利,您将会得到以下类似的结果:
1
2
3
|
nginx: [warn] "ssl_stapling" ignored, issuer certificate not found
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
请注意开头的警告。如前所述,由于我们的自签名证书无法使用 SSL stapling,因此此特定设置会产生警告。这是预期的,我们的服务器仍然可以正确加密连接。
如果您的输出与上述相匹配,则您的配置文件没有语法错误。我们可以安全地重新启动 Nginx 来实施我们的更改:
1
|
sudo systemctl restart nginx
|
步骤 5:测试加密
现在,我们准备测试我们的 SSL 服务器。
打开您的 Web 浏览器,然后在地址栏中输入 https://,后面跟上您服务器的域名或 IP:
1
|
https://server_domain_or_IP
|
由于我们创建的证书未经您浏览器信任的证书颁发机构签名,您可能会看到以下类似的警告:
!Nginx self-signed cert warning
这是预期的和正常的。我们只关心证书的加密方面,而不是主机真实性的第三方验证。点击 “高级”,然后点击提供的链接以继续访问您的主机:
!Nginx self-signed override
您应该会进入您的站点。如果您查看浏览器地址栏,您会看到一个带有 “x” 的锁。在这种情况下,这只是意味着无法验证证书。它仍然在加密您的连接。
如果您配置了 Nginx 两个服务器块,自动将 HTTP 内容重定向到 HTTPS,您还可以检查重定向是否正常工作:
1
|
http://server_domain_or_IP
|
如果结果显示相同的图标,这意味着您的重定向已经正确工作。
步骤 6:更改为永久重定向
如果您的重定向工作正常,并且您确定只想允许加密流量,您应该修改 Nginx 配置以使重定向变为永久性。
再次打开您的服务器块配置文件:
1
|
sudo nano /etc/nginx/sites-available/default
|
找到 return 302 并将其更改为 return 301:
1
2
3
4
5
6
|
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server_domain_or_IP;
return 301 https://$server_name$request_uri;
}
|
保存并关闭文件。
检查您的配置是否存在语法错误:
当您准备好时,重新启动 Nginx 以使重定向变为永久性:
1
|
sudo systemctl restart nginx
|
结论
您已经配置了 Nginx 服务器以使用强加密来处理客户端连接。这将允许您安全地提供请求,并防止外部方读取您的流量。