使用acme.sh签发Wildcard ECC+RSA双证书

前两天收到 Let’s Encrypt 发来的邮件,说现在的证书的验证方式是 TLS-SNI-01 ,即将结束支持。趁着这个机会,顺便把之前一直攒着的想换外卡和想换ECC的两个小坑填了。

第一个要解决的问题是 Nginx。Nginx在Ubuntu 16.04源里的最近版本是v1.10.4,并不支持写多个 tls_certificate 命令,这样就没法配置双证书。因此解决方案是

sudo apt-add-repository ppa:nginx/stable
sudo apt update
sudo apt remove nginx nginx-core nginx-common
sudo apt install nginx

最后一步会询问你是否覆盖配置文件,默认填 N 就好了。

第二步是安装 acme.sh 。这里我先吐槽一下, Certbot 是真的难用。

# Root shell
curl https://get.acme.sh | sh
# or you can use wget if you prefer
# wget -O -  https://get.acme.sh | sh
source .bashrc

然后就可以签发证书了。

讲一下证书验证( ACME challenge )吧。签发一个证书之前需要验证该域名属于你。Let’s Encrypt目前支持这么几种验证方式:在DNS里加入TXT记录;通过http(s)访问某子目录进行验证;通过SNI进行验证(即将废弃);通过ALPN进行验证;等。我个人使用的是 Aliyun 来进行DNS管理的,恰好acme.sh提供了阿里云的dns api,可以方便很多操作。需要现在阿里的控制台里面签一个AccessKey出来;如果使用RAM权限控制,需要给出DNS的读写权限。

export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"

acme.sh --issue --dns dns_ali -d example.com -d *.example.com
# You need to wait 120s for the TXT record to take effect

注意,只签 *.example.com 是不行的,会导致根域名无法访问。

这里签发了一张RSA的证书。如果要签ECC的,需要额外执行一步

acme.sh --issue --dns dns_ali -d example.com -d *.example.com --keylength ec-384
# OR:
acme.sh --issue --dns dns_ali -d example.com -d *.example.com --keylength ec-256

签发完了之后,证书会存在 ~/.acme.sh/ 中,这是一个临时目录,可能会随着 acme.sh 的更新而变化,不应该用来直接引用,所以要安装证书到特定位置。

acme.sh --install-cert -d example.com \
--key-file       /etc/letsencrypt/keys/rsa.key.pem  \
--fullchain-file /etc/letsencrypt/keys/rsa.cert.pem \
--reloadcmd     "service nginx force-reload"
acme.sh --install-cert -d example.com --ecc \
--key-file       /etc/letsencrypt/keys/ecc.key.pem  \
--fullchain-file /etc/letsencrypt/keys/ecc.cert.pem \
--reloadcmd     "service nginx force-reload"

之后将以下代码加入到 nginx 配置文件即可。

ssl_certificate /etc/letsencrypt/keys/ecc.cert.pem;
ssl_certificate_key /etc/letsencrypt/keys/ecc.key.pem;

ssl_certificate /etc/letsencrypt/keys/rsa.cert.pem;
ssl_certificate_key /etc/letsencrypt/keys/rsa.key.pem;

另外,为了拿到 A+ ,还有一个加密算法优先级的问题;本站自用的:

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";