树莓派添加免费HTTPS证书

已经在树莓派上搭建好了博客,接着就想着目前HTTPS在各大互联网站已经成为标配,在未来肯定是一种趋势,HTTPS的好处有很多,可以防止各种攻击劫持,运营商广告植入,客户传输信息泄露等问题。
通过Google查询发现了一个Let's Encrypt项目,它由互联网安全研究小组ISRG(Internet Security Research Group)提供服务,ISRG是来自美国加利福尼亚州的一个公益组织。Let's Encrypt 得到了 Mozilla、Cisco和 Chrome 等众多公司和机构的支持。
Let's Encrypt证书对中小网站来说免费且配置简单,唯一的问题就是每次申请只有90天的有效期,但可以通过脚本定期更新,配置好之后一劳永逸。通过Github发现又一个acme-tiny项目,它是一个Python脚本的工具可以协助完成证书的申请,简化申请流程。

1、创建账号

Let's Encrypt使用一个私钥来进行账号的创建与登陆,因此我们需要使用openssl创建一个account.key

openssl genrsa 4096 > account.key

生成的key格式需要转换,于是我又发现一个好的脚本

# 下载脚本
wget -O - "https://gist.githubusercontent.com/JonLundy/f25c99ee0770e19dc595/raw/6035c1c8938fae85810de6aad1ecf6e2db663e26/conv.py" > conv.py

# 把private key 拷贝到你的工作目录
cp /etc/letsencrypt/accounts/acme-v01.api.letsencrypt.org/directory/<id>/private_key.json private_key.json

# 创建一个DER编码的private key
openssl asn1parse -noout -out private_key.der -genconf <(python conv.py private_key.json)

# 转换成PEM格式
openssl rsa -in private_key.der -inform der > account.key

2、创建域名的CSR

Let's Encrypt使用的ACME协议需要一个CSR(CERTIFICATE SIGNING REQUEST)文件,可以使用它来重新申请HTTPS证书,接下来我们就可以创建域名CSR,在创建CSR之前,我们需要给我们的域名创建一个私钥(这个和上面的账户私钥无关)。

#创建普通域名私钥
openssl genrsa 4096 > domain.key

接下来,使用你的域名私钥创建CSR文件,这一步里面是可以增加最多100个需要加密的域名的,替换下面的chy.mobi即可(注意,稍后会说到,每个域名都会涉及到验证)

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

#多个域名(如果你有多个域名,比如:www.chy.mobi和chy.mobi,使用这种方式)
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:chy.mobi,DNS:chy.mobi")) > domain.csr

3、配置域名验证

CA 在签发 DV(Domain Validation)证书时,需要验证域名所有权。
Let's Encrypt 的方式是在你的服务器上生成一个随机验证文件,再通过创建 CSR 时指定的域名访问,如果可以访问则表明你对这个域名有控制权。 首先创建用于存放验证文件的目录,例如:

mkdir -p var/www/challenges

然后编辑 /etc/nginx/sites-enabled/default 配置HTTP服务,注意此处应使用80端口

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name chy.mobi www.chy.mobi;

        location /.well-known/acme-challenge/ {
                alias /home/pi/Websites/Chy/challenges/;
                try_files $uri =404;
        }

        location / {
                return 302 http://chengyong.im$request_uri;
                try_files $uri =404;
        }
}

这个验证服务以后更新证书还要用到,需要一直保留,不要在Nginx的配置中删除。

4、获取网站证书

先把 acme-tiny 脚本保存到之前的 ssl 目录:

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 /var/www/challenges/ > ./signed.crt

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

5、安装证书

证书生成后,就可以把它配置在web 服务器上了,需要注意的是,Nginx需要追加一个Let's Encrypt的中间证书,在 Nginx 配置中,需要把中间证书和网站证书合在一起:

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

最终,修改 Nginx 中有关证书的配置,下面是我的网站的完整的配置:

server {
        # SSL configuration
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;

        server_name chy.mobi;
        root /home/pi/Websites/Chy;

        ssl on;
        ssl_certificate /home/pi/SSL/chained.pem;
        ssl_certificate_key /home/pi/SSL/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:DHE$
        ssl_session_cache shared:SSL:50m;
        ssl_prefer_server_ciphers on;

        # Add index.php to the list if you are using PHP
        index index.php index.html index.htm index.nginx-debian.html;

        location / {
                if (-f $request_filename/index.html){
                        rewrite (.*) $1/index.html break;
                }
                if (-f $request_filename/index.php){
                        rewrite (.*) $1/index.php;
                }
                if (!-f $request_filename){
                        rewrite (.*) /index.php;
                }
        }

        location ~ .*\.php(\/.*)*$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                include fastcgi.conf;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #       deny all;
        #}
}


server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name chy.mobi www.chy.mobi;

        location /.well-known/acme-challenge/ {
                alias /home/pi/Websites/Chy/challenges/;
                try_files $uri =404;
        }

        location / {
                return 302 http://chengyong.im$request_uri;
                try_files $uri =404;
        }
}

至此,所有证书已经配置成功,reload服务即可生效。

6、定期手动更新

为了方便更新,把上面的步骤写成一个脚本 renew_cert.sh 保存到本地,每隔2个多月执行一次即可:

#!/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

下次直接执行以下命令即可:

sh renew_cert.sh

标签:HTTPS, Let's Encrypt, 证书, 免费证书