在 Ubuntu 18.04 上使用 Let's Encrypt 来保护 Nginx

Let’s Encrypt 是由 Internet Security Research Group (ISRG) 开发的免费开放证书。今天几乎所有浏览器都信任 Let’s Encrypt 颁发的证书。

在本教程中,我们将提供有关如何使用 Ubuntu 18.04 上的 certbot 工具使用 Let’s Encrypt 来保护您的 Nginx 的分步说明。

先决条件

在继续本教程之前,请确保您已满足以下先决条件:

  • 您有一个指向公共服务器 IP 的域名。在本教程中我们将使用 example.com
  • 您按照以前的教程安装了 Nginx
  • 您有一个适用于您的网站的服务器块。您可以按照说明了解如何创建一个 Nginx 服务器块

安装 Certbot

Certbot 是一个功能齐全且易于使用的工具,可以自动完成获取和更新 Let’s Encrypt SSL 证书和配置 Web 服务器以使用证书的任务。 certbot 包包含在 Ubuntu 的自有存储库中。

更新软件包列表并安装 certbot 软件包:

sudo apt update
sudo apt install certbot

生成强 Dh (Diffie-Hellman)组

Diffie-Hellman 密钥交换(DH)是一种在不安全的通信信道上安全地交换密码密钥的方法。我们将生成一组新的 2048 位 DH 参数以加强安全性:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

如果您愿意,可以将大小更改为 4096 位,但在这种情况下,生成可能需要超过 30 分钟,具体取决于各自的系统。

获取 Let’s Encrypt SSL 证书

我们将使用 Webroot 插件来为域名获取 SSL 证书,该插件通过在目录 ${ webroot-path }/.well-known/acme-challenge 中创建临时文件来验证域名。 Let’s Encrypt 服务器向临时文件发出 HTTP 请求,以验证请求的域名是不是运行 certbot 的服务器。

为了使它更简单,我们将把所有对 .well-known/acme-challenge 的 HTTP 请求都映射到单独的目录 /var/lib/letsencrypt

以下命令将创建目录并使让 Nginx 服务器对该目录有写入权限。

mkdir -p /var/lib/letsencrypt/.well-known
chgrp www-data /var/lib/letsencrypt
chmod g+s /var/lib/letsencrypt

为避免重复代码,请创建以下两个片段,我们将在所有 Nginx 服务器块文件中包含这些片段。

打开文本编辑器并创建第一个片段 /etc/nginx/snippets/letsencrypt.conf

sudo nano /etc/nginx/snippets/letsencrypt.conf

文件的内容如下:

location ^~ /.well-known/acme-challenge/ {
allow all;
root /var/lib/letsencrypt/;
default_type "text/plain";
try_files $uri =404;
}

创建第二个代码段 /etc/nginx/snippets/ssl.conf ,其中包括 Mozilla 推荐的配置,启用了 OCSP 装订, HTTP Strict Transport Security(HSTS), 并强制使用少数的几个安全的 HTTP 标头。

sudo nano /etc/nginx/snippets/ssl.conf
ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 30s;

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;

创建片段后,打开域服务器块并包含 letsencrypt.conf 如下所示的片段:

sudo nano /etc/nginx/sites-available/example.com

/etc/nginx/sites-available/example.com

server {
listen 80;
server_name example.com www.example.com;

include snippets/letsencrypt.conf;
}

要启用新的服务器块文件,我们需要创建从文件到 sites-enabled 目录的符号链接,以便 Nginx 能读取到:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

重新启动 Nginx 服务以使更改生效:

sudo systemctl restart nginx

您现在可以使用 webroot 插件运行 Certbot 并通过发出以下命令获取 SSL 证书文件:

sudo certbot certonly --agree-tos --email [email protected] --webroot -w /var/lib/letsencrypt/ -d example.com -d www.example.com

如果成功获得 SSL 证书, certbot 将打印以下消息:

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.com/privkey.pem
Your cert will expire on 2018-07-28. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

现在您已拥有证书文件,您可以按如下方式编辑域名服务器块文件 /etc/nginx/sites-available/example.com

sudo nano /etc/nginx/sites-available/example.com
server {
listen 80;
server_name www.example.com example.com;

include snippets/letsencrypt.conf;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name www.example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
include snippets/ssl.conf;
include snippets/letsencrypt.conf;

return 301 https://example.com$request_uri;
}

server {
listen 443 ssl http2;
server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
include snippets/ssl.conf;
include snippets/letsencrypt.conf;

# . . . other code
}

通过上面的配置,我们强制访问域名使用 HTTPS, 并从 www 重定向到非 www 版本。

重新加载 Nginx 服务以使更改生效:

sudo systemctl reload nginx

自动续订 Let’s Encrypt SSL 证书

我们的加密证书有效期为 90 天。要在证书过期之前自动续订证书, certbot 包会创建一个 cronjob ,每天运行两次,并在到期前 30 天自动续订任何证书。

由于我们在续订证书后使用 certbot webroot 插件,因此我们还必须重新加载 nginx 服务。附加 --renew-hook "systemctl reload nginx"/etc/cron.d/certbot 文件,如下所示:

sudo nano /etc/cron.d/certbot

/etc/cron.d/certbot

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"

要测试续订过程,您可以运行 certbot 时带上参数 --dry-run

sudo certbot renew --dry-run

如果没有错误,则表示续订过程成功。

结论

在本教程中,您使用了 Let’s Encrypt 客户端 certbot 来申请下载域名的 SSL 证书。您还创建了 Nginx 代码片段以避免重复代码并为 Nginx 配置了证书。在本教程结束时,您还设置了一个用于自动续订证书的 cronjob 。

如果您想了解有关如何使用 Certbot 的更多信息,阅读他们的文档是一个不错的起点。