签发 Let's Encrypt ECC 证书


UPDATE: 请查看 acme.sh - 极力推荐的 Let's Encrypt 工具 这篇博文。

Let's Encrypt 证书申请实测 这篇博文里,我们签到了 RSA 2048 位证书。不过听闻 Let's Encrypt 从二月开始就支持签发 ECC 证书了,于是乎赶紧签一个。相比 RSA,ECC 证书在相似安全性的同时体积大幅减小。如果想要进一步了解的,Digicert 的 这篇文章 有一个大概的介绍,可以去阅读一下。


首先新建一个文件夹,装各种产出的东西。

mkdir keys
cd keys

配置账号私钥

签 ECC 证书的话,还是用 acme-tiny 好些。这次换了新的 VPS,也不想再去装官方那全家桶了。因为我上次已经用官方工具签过了证书,所以已经有自己的账号私钥了。官方客户端使用的是 JWK 格式,所以要转换一下账号私钥到 PEM 格式:

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

如果第一次签,直接 openssl genrsa 4096 > account.key 就好了,不需要转换。

创建 CSR

创建域名私钥,这个要保护好:

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

生成证书签名请求(CSR)文件,Common Name 要填写域名地址,其他的默认就好了:

openssl req -new -sha256 -key domain.key -out domain.csr

为 Nginx 添加验证

Let's Encrypt 会在域名下随机生成一个文件验证是否拥有域名。如果能够正常下载则验证通过。因此要配置文件服务器。
创建验证用的文件夹:

mkdir -p /var/www/challenges/

打开 Nginx 配置文件,添加如下字段:

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

    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    #...the rest of your config
}

获取证书

首先下载 acme-tiny

wget https://raw.githubusercontent.com/diafygi/acme-tiny/master/acme_tiny.py

然后就可以签证书啦

python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt

使用证书

首先先下载 Let's Encrypt 的中间证书,并和你的证书串到一起:

wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem

打开你的 Nginx 配置文件,把 ssl_certificatessl_certificate_key 指向的证书地址修改掉,比如说我的:

server {
    listen 443 ssl http2;
    server_name niconiconi.xyz;

    ssl_certificate /var/www/keys/niconiconi.xyz/chained.pem;
    ssl_certificate_key /var/www/keys/niconiconi.xyz/domain.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /var/www/keys/niconiconi.xyz/chained.pem;

    add_header Strict-Transport-Security "max-age=10886400; includeSubdomains; preload";

    ssl_ct on;
    ssl_ct_static_scts /var/www/scts;

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:2368;
    }
}

重启 Nginx:

sudo service nginx restart

好了,按理说应该可以用上新的证书了。比如这样的:

题外话

如果之前配置了 Certificate Transparency,更新证书就意味着要再获取一遍 SCT 文件。不过这并不麻烦,照着 这篇博文 做一遍就行了,两分钟搞定。