申请免费的https证书,Let's Encrypt

背景

近来,互联网由httphttps推进的步伐越来越快,除了各大浏览器之外,搜索引擎也特别的优待https,因此想着跟上步伐把自己的网站也弄成https

想要弄成httpsssl证书是个绕不过去的坎,各大CA机构的证书都价格不菲,要找个免费又受各大浏览器信任的证书着实不易。

本来考虑StartSSL是个不错的选择,但是最近StartSSL因为自身的不规范操作遭到了各大浏览器的封杀,只能抛弃。

通过筛选之后,发现Let's Encrypt是最好的选择,唯一的缺点是证书的有效期只有3个月,不过这可以通过自动更新来解决。以下摘自网上关于Let's Encrypt的介绍:

Let's Encrypt 是免费、自动化、开放的证书签发服务。它由 ISRG(Internet Security Research Group,互联网安全研究小组)提供服务,而 ISRG 是来自于美国加利福尼亚州的一个公益组织。Let's Encrypt 得到了 Mozilla、Cisco、Akamai、Electronic Frontier Foundation 和 Chrome 等众多公司和机构的支持,发展十分迅猛。

本人对于ssl证书Let's Encrypt并没有什么研究,试用了不少号称自动化申请的脚本,但都失败,本文是在踩过坑后最终成功的步骤记录。

基本照搬于此文:https://imququ.com/post/letsencrypt-certificate.html

前提及准备工作

以下的所有操作最好都是在实际绑定域名指向的服务器上进行,因为这期间会通过域名指向进行域名的所有权验证,以及以后的证书自动更新也都会进行验证,因此这是最直接方便的选择。

操作系统

操作系统为Linux,网上给的方案和脚本也都是针对Linux,本人用的CentOS

配置验证的http服务

本人使用nginx,以nginx为例,其它的原理都一样。

CA 在签发 DV(Domain Validation)证书时,需要验证域名所有权。Let's Encrypt 的验证方式是在你的服务器上生成一个随机的验证文件,在创建 CSR 时通过指定的域名进行访问,如果访问成功则表明你对这个域名有控制权。

具体访问的路径为:http://www.dexcoder.com/.well-known/acme-challenge/xxxxxxxxxx

最后的部分为随机生成的验证文件,因此需要把生成随机文件的目录映射成该路径:

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

    location ^~ /.well-known/acme-challenge/ {
            alias /opt/www/dexcoder/challenges/;
    }
    location / {
            return 301 https://$server_name$request_uri;
    }
}

创建帐号

新建一个ssl目录,之后所有的操作及生成的证书文件等都在该目录。

进入这个目录,创建一个 RSA 私钥用于 Let's Encrypt 识别你的身份:

openssl genrsa 4096 > account.key

创建 CSR 文件

接着就可以生成 CSR(Certificate Signing Request,证书签名请求)文件了。在这之前,还需要创建域名私钥(一定不要使用上面的账户私钥),根据证书不同类型,域名私钥也可以选择 RSA 和 ECC 两种不同类型。以下两种方式请根据实际情况二选一。

1)创建 RSA 私钥(兼容性好):

openssl genrsa 4096 > domain.key

2)创建 ECC 私钥(部分老旧操作系统、浏览器不支持。优点是证书体积小):

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

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

有了私钥文件,就可以生成 CSR 文件了。在 CSR 中推荐至少把域名带 www 和不带 www 的两种情况都加进去,其它子域可以根据需要添加(目前一张证书最多可以包含 100 个域名):

openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:dexcoder.com,DNS:www.dexcoder.com")) > domain.csr

执行这一步时,如果提示找不到 /etc/ssl/openssl.cnf 文件,请看看 /usr/local/openssl/ssl/openssl.cnf 是否存在。

我在执行这一步时以上两处都没有该文件,但已经安装了openssl照理说应该存在才对,使用find命令搜索:

[root@iZ28siayqz6Z ~]# find / -name openssl.cnf
/etc/pki/tls/openssl.cnf

终于发现 /etc/pki/tls/openssl.cnf ,如果还是不行,也可以使用交互方式创建 CSR(需要注意 Common Name 必须为你的域名):

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

获取网站证书

下载acme-tiny脚本:

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

执行脚本,指定账户私钥、CSR 以及验证目录(前面nginx配置的验证目录):

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

报出如下错误:

Traceback (most recent call last):
  File "acme_tiny.py", line 2, in <module>
    import argparse, subprocess, json, os, sys, base64, binascii, time, hashlib, re, copy, textwrap, logging
ImportError: No module named argparse

这是因为centOS本身的包都比较老旧,python还是2.6.x版本,acme-tiny脚本需要2.7以上版本才行。

下载2.7.8,解压并编译安装:

# wget http://python.org/ftp/python/2.7.8/Python-2.7.8.tgz
# tar xvf Python-2.7.8.tgz
# cd Python-2.7.8
# ./configure --prefix=/usr/local/python27
# make && make install  

这里安装到了/usr/local/python27目录,我并没有也不想改变系统默认的python版本,因此显示指定python版本执行:

/usr/local/python27/python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /opt/www/dexcoder/challenges/ > ./signed.crt

又报出:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/python27/lib/python2.7/urllib.py", line 86, in urlopen
    return opener.open(url)
  File "/usr/local/python27/lib/python2.7/urllib.py", line 204, in open
    return self.open_unknown(fullurl, data)
  File "/usr/local/python27/lib/python2.7/urllib.py", line 216, in open_unknown
    raise IOError, ('url error', 'unknown url type', type)
IOError: [Errno url error] unknown url type: 'https'

这是因为在编译安装python时系统中没有openssl库,安装:

sudo yum install openssl-devel

重新编译安装python:

./configure --prefix=/usr/local/python27
# make && make install 

再次执行脚本,成功。当前目录下生成一个 signed.crt,这就是申请好的证书文件。

如果你的域名在国外,DNS解析放在国内,这一步很可能会遇到类似这样的错误:

> ValueError: Wrote file to /home/xxx/www/challenges/oJbvpIhkwkBGBAQUklWJXyC8VbWAdQqlgpwUJkgC1Vg, but couldn't download http://www.yoursite.com/.well-known/acme-challenge/oJbvpIhkwkBGBAQUklWJXyC8VbWAdQqlgpwUJkgC1Vg

这是因为你的域名很可能在国外无法解析,可以找台国外 VPS 验证下。

搞定网站证书后,还要下载 Let's Encrypt 的中间证书。

在 Nginx 配置中,需要把中间证书和网站证书合在一起:

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

为了后续能顺利启用 OCSP Stapling,我们再把根证书和中间证书合在一起:

wget -O - https://letsencrypt.org/certs/isrgrootx1.pem > root.pem
cat intermediate.pem root.pem > full_chained.pem

最终,修改 Nginx 中有关证书的配置并 reload 服务即可:

ssl_certificate     /opt/www/dexcoder/ssl/chained.pem;
ssl_certificate_key /opt/www/dexcoder/ssl/domain.key;

配置nginx http 301跳转到https

其实前面验证服务中已经给出配置了:

location / {
        return 301 https://$server_name$request_uri;
}

证书自动更新脚本

Let's Encrypt 签发的证书只有 90 天有效期,推荐使用脚本定期更新。例如我就创建了一个 renew_cert.sh 并通过 chmod a+x renew_cert.sh 赋予执行权限。文件内容如下:

#!/bin/bash

cd /home/xxx/www/ssl/
python acme_tiny.py --account-key account.key --csr domain.csr --acme-dir /home/xxx/www/challenges/ > signed.crt || exit
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
service nginx reload

crontab 中使用绝对路径比较保险,crontab -e 加入以下内容:

0 0 1 * * /home/xxx/shell/renew_cert.sh >/dev/null 2>&1

这样以后证书每个月都会自动更新,一劳永逸。实际上,Let's Encrypt 官方将证书有效期定为 90 天一方面是为了更安全,更重要的是鼓励用户采用自动化部署方案。

最后

实测 Let's Encrypt 的证书在各大系统及浏览器中都没发现任何问题,兼容性还是很不错的。

本文标题:申请免费的https证书,Let's Encrypt
本文来自码农的士,转载请注明出处
交流QQ群:32261424
Previous:
没有了
Next:

发表评论

,将以游客形式发表

网友最新评论(0)