启用 Let's Encrypt 证书

Let's Encrypt 由 ISRG(Internet Security Research Group,互联网安全研究小组)提供了免费、自动化、开放的证书签发服务,虽然证书只有 90 天有效期,但可以通过定时脚本更新,这里参照 imququ 的文章记录了在 CentOS 7 X64 上使用 acme-tiny 申请、配置以及定时更新证书的方法。

安装 openssl


yum install openssl-devel

创建帐号私钥


先创建一个目录 cert 用于存放各种临时文件,然后创建一个 RSA 私钥用于 Let's Encrypt 识别你的身份:

openssl genrsa 4096 > account.key

如果已经有 Let's Encrypt 账号了,那么需要把 JWK 格式的私钥转化为 acme-tiny 使用的 PEM 格式,这里使用了 JonLundy 的脚本

wget -O -  "https://gist.githubusercontent.com/JonLundy/f25c99ee0770e19dc595/raw/6035c1c8938fae85810de6aad1ecf6e2db663e26/conv.py" > conv.py

cp /etc/letsencrypt/accounts/acme-v01.api.letsencrypt.org/directory/<id>/private_key.json private_key.json

openssl asn1parse -noout -out private_key.der -genconf <(python conv.py private_key.json)

openssl rsa -in private_key.der -inform der > account.key

创建 CSR(Certificate Signing Request,证书签名请求)文件


创建一个域名私钥(一定不要使用上面的账户私钥):

openssl genrsa 4096 > domain.key

如果要签发 ECC 证书,请使用以下任一命令生成 domain.key:

openssl ecparam -genkey -name secp256r1 | openssl ec -out domain.key

openssl ecparam -genkey -name secp384r1 | openssl ec -out domain.key

关于 ECC 证书的介绍请参考 imququ 的文章,然后生成 CSR 文件:

#单个域名
openssl req -new -sha256 -key domain.key -subj "/CN=yoursite.com" > domain.csr

#多个域名,目前一张证书最多可以包含 100 个域名,推荐至少把带 www 和不带 www 的域名加入
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/pki/tls/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:airycanon.me,DNS:www.airycanon.me")) > domain.csr

这里需要注意不同 Linux 发行版下 openssl 配置文件的路径,例如我用的 CentOS 是 /etc/pki/tls/openssl.cnf,而有些发行版是 /etc/ssl/openssl.cnf

配置验证服务


Let's Encrypt 在签发证书时,需要验证域名所有权,具体做法是在你的服务器上生成一个随机验证文件,再通过创建 CSR 时指定的域名访问,如果可以访问则表明你对这个域名有控制权。

首先创建用于存放验证文件的目录:

mkdir /usr/share/nginx/html/cert/

然后配置一个 Nginx HTTP 服务:

server {
    server_name www.airycanon.me airycanon.me;

    location ^~ /.well-known/acme-challenge/ {
        alias /usr/share/nginx/html/cert/;
        try_files $uri =404;
    }

    location / {
        rewrite ^/(.*)$ https://airycanon.me/$1 permanent;
    }
}

这个验证服务以后更新证书还要用到,需要一直保留。

获取网站证书


#下载 acme-tiny 脚本
wget https://raw.githubusercontent.com/diafygi/acme-tiny/master/acme_tiny.py

#用上面的账户私钥、CSR 以及验证目录,执行脚本:
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /usr/share/nginx/html/cert/ > ./signed.crt

如果一切正常,当前目录下就会生成一个 signed.crt,这就是申请好的证书文件。

在配置 HTTPS 证书时,既不要漏掉中间证书,也不要包含根证书,因此在 Nginx 配置中,需要把中间证书和网站证书合在一起:

# 获取中间证书
wget -O - https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > intermediate.pem
# 合并中间证书和网站证书
cat signed.crt intermediate.pem > chained.pem

在需要启用证书的 Nginx 配置中加入如下两项:

ssl_certificate     ~/cert/chained.pem;
ssl_certificate_key ~/cert/domain.key;

最后重新加载 Nginx 配置即可:

systemctl reload nginx

配置自动更新


前面提到 Let’s Encrypt 签发的证书只有 90 天有效期,但可以把上面操作写到脚本中:

#!/bin/bash

cd /usr/share/nginx/cert
python acme_tiny.py --account-key account.key --csr domain.csr --acme-dir /usr/share/nginx/html/cert/ > signed.crt || exit
wget -O - https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
systemctl reload nginx

然后加入 crontab 定时更新:

0 0 1 * * /usr/share/nginx/cert/update.sh >/dev/null 2>&1