【过年了,每天发一篇以前的存货,一共七篇。】
Let's Encrypt是去年底推出的一个免费SSL证书,且申请这个证书基本没有任何限制,只要你证明你是域名的所有者,你就可以为你的域名申请一个SSL证书。
我今天就来为我的 wiki.ioin.in 申请一个时髦的Let's Encrypt证书。
首先,我利用到的是acme-tiny,这是第三方人士开发的一个扩展。因为Let's Encrypt官方给出的方法比较麻烦,而acme-tiny这个小工具可以让用户敲几条命令即可生成好我们需要的证书。
下载acme-tiny: https://github.com/diafygi/acme-tiny
首先,生成一个用户私钥: account.key,acme-tiny通过这个证书来登录Let's Encrypt。再生成一个域名私钥,domain.key
openssl genrsa 4096 > account.key
openssl genrsa 4096 > domain.key
然后利用ACME协议,将domain.key生成domain.csr。如果你只有一个域名需要ssl,只需执行下面的语句:
openssl req -new -sha256 -key domain.key -subj "/CN=yoursite.com" > domain.csr
如果你有多个域名,比如www.xxx.com和xxx.com,你就执行下面的语句:
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:yoursite.com,DNS:www.yoursite.com")) > domain.csr
我的 wiki.ioin.in 是单域名证书,所以执行下面语句即可:
Let's Encrypt有多种方法来验证你是否是域名的所有人,而acme-tiny这个小工具用的是最简单的方法,也就是利用http文件验证。
简单来说,就是生成一个验证文件,放在http://example.com/.well-known/acme-challenge/
下,Let's Encrypt官方验证这个文件是否存在、内容是否正确。如果一切正确,说明域名是你所有。
所以我这里,新建了一个/home/www/challenges/目录,将它别名指向 /.well-known/acme-challenge/ 。这样,我在challenges目录里写入的文件,即可通过 http://xxxx.com/.well-known/acme-challenge/ 访问了。nginx配置如下:
然后,运行acme_tiny.py脚本:
python acme_tiny.py --account-key /etc/ssl/letsencrypt/account.key --csr /etc/ssl/letsencrypt/domain.csr --acme-dir /home/www/challenges/ > /etc/ssl/letsencrypt/signed.crt
其中,将--account-key的值改为你生成的account.key的路径;--csr的值改成你生成的domain.csr的路径;--acme-dir的值改为我要写入验证文件的文件夹。
最后成功生成signed.crt,这就是我的域名证书:
在nginx里,还需要将Let's Encrypt的中间证书放到自己的证书后面,构成一个证书链chained.pem:
wget -O - https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
另外,还需要生成一个较强的dh。(位数不要太多!我生成了一个4096位的dh,半个小时还没生成好)。关于dh的安全性,可以关注这个网站: https://weakdh.org ,这篇文章:https://weakdh.org/sysadmin.html
openssl dhparam -out dhparam.pem 2048
生成好以后,将以上生成的私钥、证书、dh等写入nginx的配置文件:
server
{
listen 80;
listen 443 ssl;
#listen [::]:80;
server_name wiki.ioin.in;
index index.html index.htm;
ssl on;
ssl_certificate /etc/ssl/letsencrypt/chained.pem;
ssl_certificate_key /etc/ssl/letsencrypt/domain.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DH$
ssl_session_cache shared:SSL:50m;
ssl_dhparam /etc/ssl/letsencrypt/dhparam.pem;
ssl_prefer_server_ciphers on;
...the rest of your config
}
重启nginx,一切万事大吉: https://wiki.ioin.in
另外,我们看证书的过期日期。算一下这个证书其实只有3个月,也就是一个季度。当证书快要过期的时候,我们还需要重新颁发一下证书。
重新颁发证书的过程就比较简单了,只需要重新执行acme_tiny.py即可。
我们可以将重新颁发的过程写在一个脚本里:
#!/usr/bin/sh
python /path/to/acme_tiny.py --account-key /path/to/account.key --csr /path/to/domain.csr --acme-dir /var/www/challenges/ > /tmp/signed.crt || exit
wget -O - https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > intermediate.pem
cat /tmp/signed.crt intermediate.pem > /path/to/chained.pem
service nginx reload
然后将这个脚本加入cron,每月执行一次:
#example line in your crontab (runs once per month)
0 0 1 * * /path/to/renew_cert.sh 2>> /var/log/acme_tiny.log
就不需要人工操作了~
最后,测试一下SSL质量: https://www.ssllabs.com/ssltest/