前言

SSL证书在这个时代普遍性就不说了,最关键的是只要不乱装证书,带上这个可以让中间设备都无法获取通讯信息,对于网络会被审查的环境其实还是比较有用的。
之前的SSL服务商基本证书价格都恐怖的吓人,哪怕我的blog访问数再多2个0我也完全不会考虑加证书,现在因为Let's Encrypt的出现,一下子就让https变得非常亲民,所以当然要来鼓捣一下~
HTTP与HTTPS

主要内容

本文主要介绍在CentOS7下是用Certbot进行证书申请,安装以及自动续期的过程。因为这方面的教程很多,所以不会特别详细,给自己做个记录。在Typecho上面套SSL的教程也不少,所以也不细说了,会稍微说下我自用的Gogs版本控制平台如何套SSL(主要是自动续期,Let's Encrypt似乎不支持靠更改DNS解析的txt解析来进行自动续期,这里来说下Gogs怎么办),然后就是阿里系的机器用自带的镜像无法运行Certbot该怎么办

正文

前提条件

已经在服务器上部署好了网站,nginx等,并且能够通过80端口对网站进行正常访问,能够使用SSH工具连接服务器执行命令

1.安装EPEL源

对于部分CentOS系统来说,直接在bash里面使用yum安装cetbot是找不到的,所以要先装这么一个东西——EPEL (Extra Packages for Enterprise Linux)是一个基于Fedora的项目,为“红帽系”的操作系统提供额外的软件包,适用于RHEL、CentOS和Scientific Linux。可以简单的认为就是自动配置yum的软件仓库用的...当然可以手动配置不装这个,不过没找到教程所以没试,并且有现成的当然更好,命令只有这一行
sudo yum install -y epel-release
执行就好

2.安装Certbot

有了仓库,装Certbot,同样一行搞定
sudo yum install -y certbot

3.初次是用Certbot申请证书

命令如下
certbot certonly --webroot -w /opt/www/demo.mydomain.com -d demo.mydomain.com -m myname@gmail.com --agree-tos
关于这条命令的解释是
certbot certonly --webroot -w [Web站点目录] -d [站点域名] -m [联系人email地址] --agree-tos
站点目录,站点域名按照自己实际情况来,不要直接抄上去,email的话可以考虑填写真的,因为他们会在证书即将过期之前发信到这个邮箱进行通知。不过如果接下来的自动续期可以配置成功其实倒也没太大关系了~
最后那个agree-tos当然要有,要是不同意人家怎么可能给用

可能出现的问题
注意如果这一步出现ImportError: cannot import name UnrewindableBodyError,说明urllib3库有问题了,需要重装。
pip uninstall urllib3
pip install urllib3

如果遇到这个问题的你使用的是阿里系主机

但是,如果你用的是阿里云的机器提供的Ubuntu或者CentOS镜像,那求求你就就别用Certbot了,直接换。因为不明原因,阿里的这两个镜像在涉及Certbot的时候总是会出现问题,换acme.sh吧

emmm,附上一点额外的东西吧
当然虽然我嘴上说着换工具,但是内心还是偏向Let's Encrypt推荐的Certbot...所以我就就这这个坑直接跳进去了Orz
所以来说说阿里系遇到这种问题的解决方法,错误方案和中间过程因为尝试次数过多就不记录了,直接记解决方法...
上面我已经使用
pip uninstall urllib3
urllib3卸载掉了,重新安装的时候发现还是不行...所以干脆彻底了一点...把另两个也卸了...
pip uninstall requests
pip uninstall chardet
然后再用这条命令装回来
pip install --upgrade --force-reinstall 'requests==2.6.0' urllib3
安装发现报错

又给卸载了...既然这样,那就重来一遍改下命令直接忽视报错吧
pip install --upgrade --force-reinstall --ignore-installed 'requests==2.6.0' urllib3
这下安装完就可以啦,然后回去certbot那行命令应该就没什么问题啦

4.继续第3步

如果没什么问题返回应该是、

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: 

大概就是要不要往你的邮箱里发点推送邮件用的,随意选择即可,选择之后,非常智能化的会自动验证,然后生成证书(比windows上我用的那个软件好多了,虽然那个提供多种验证方式,可是...对于英语水平不高的我一点也不友好...这个至少能直接都看懂)

    Obtaining a new certificate
Resetting dropped connection: acme-v02.api.letsencrypt.org
Performing the following challenges:
http-01 challenge for blog.winer.website
    Using the webroot path /data/php73mysql56/sites/blog.winer.website/www for all unmatched domains.
    Waiting for verification...
    Cleaning up challenges
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/dome.mydomain.com/fullchain.pem
 Your key file has been saved at: /etc/letsencrypt/live/dome.mydomain.com/privkey.pem
 Your cert will expire on 2020-04-10. To obtain a new or tweaked
 version of this certificate in the future, simply run certbot
 again. To non-interactively renew *all* of your certificates, run
 "certbot renew"
 - Your account credentials have been saved in your Certbot
 configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:
     Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
     Donating to EFF:                    https://eff.org/donate-le

生成的证书等文件存储路径是/etc/letsencrypt/live/dome.mydomain.com/fullchain.pem
/etc/letsencrypt/live/dome.mydomain.com/privkey.pem
建议不要移动这两个证书位置,在修改nginx配置文件的时候直接指向这个路径就可以了,因为这里certbot是把证书统一进行管理的,看到其它一些大佬说会自动留存每次更新申请的证书,类似于版本控制的感觉,可以随时恢复到申请的任何一个证书,因为我这是第一次申请,暂时没遇到证书续期的事情,所以不太清楚不过个人也不建议改

关于gogs的申请方式

其实说白了certbot就是在网站根目录路径放置一个文件进行验证的,自动放文件自动验证和移除。要想给gogs装,无非就是要找到它的根目录究竟在哪里。
这个最开始我也是陷入误区了,看gogs的介绍文档里有放robots.txt文件的位置git.youdomain.com/custom/,以为就是放到这里,结果怎么都不对...
后来看文件夹名字,又实验才知道...其实是public文件夹
git.youdomain.com/public/
然后改下上面的命令就可以了,还是自动验证,搞定

5.配置nginx

这里先提醒一下用面板的小伙伴们,宝塔我没试,appnode千万不要在里面直接可视化的手动选择导入然后开启...
因为开启之后会发现虽然目前可以正常访问,打开配置原文却会看到证书路径被改动了,复制了一份到他们自己的路径下,然后进行的导入Orz,这样自动续期了也不会有什么作用...因为还是要手动导入
(其实appnode之前是有自动使用Let's Encrypt签发证书并且自动更新和导入的功能的,但是因为Let's Encrypt去掉了他们之前使用的自动验证方式,所以暂时不能用了。appnode表示正在修复,不过...截止到发文已经咕咕咕了好几个月了...你们自己看着来)

①确定自己的nginx地址

如果知道的话直接跳过,不知道的话用下面这个行命令来确定(特别是面板用户...)
whereis nginx
确定路径之后,配置文件是下面一个叫做nginx.conf的,打开编辑

②修改nginx配置增加https

找到自己的配置文件后在其中的server{}里面首先加上
listen 443 ssl http2;
开启对443端口的监听并选择使用的协议...

在下面再加上这一大段

    ssl_certificate            /etc/letsencrypt/live/demo.yodomain.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/demo.yodomain.com/privkey.pem;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers                ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache          shared:SSL:5m;
    ssl_session_timeout        5m;

只需要把ssl_certificate和ssl_certificate_key这两行的值改成自己生成的证书以及密钥文件就可以了~其他的都没什么必要去改~

③重启或重载nginx服务

修改过配置文件必需重启nginx服务或者让nginx重载配置文件从才能生效
命令分别是

service nginx restart
service nginx reload

两个任选一个执行就ok,然后最基础的配置SSL就结束了,可以直接使用https访问自己的网站,或者使用下面这个网址来检测自己的网站安全状态
ATS(App Transport Security)检测检测")
其实这个网站是用于检测更加严格的https的,不是所有带着https的网站安全性就足够高,某些网站比如苹果在调用的时候,要求HTTPS使用的TLS协议版本在1.2及以上,被称为App Transport Security(ATS)检测

④关于HTTP跳转HTTPS

尽管有了HTTPS,还是因为用户习惯等各种原因有时会访问80端口的HTTP,这时候最好不要关闭80,而是做一个http跳转https的配置
两种方法,第一种是在只开着443的时候,默认80会返回状态码497
497 - normal request was sent to HTTPS
这对普通用户明显不友好,所以在nginx配置文件里面对于497错误返回的页面进行重写,加上下面这个,但凡遇到497全部返回https的页面

error_page 497  https://$host$uri?$args;

第二种是同时开放80和443,允许两个协议同时使用,但是所有请求80端口的都会在nginx里不经过错误页面直接重写到443,下面这么写,但是不要去掉listen 80;

if ($scheme = http) {
        return  301 https://$host$request_uri;
    }

记得做完也要重载或者重启nginx服务才行。

⑤关于一个网站使用多个域名时的SSL配置

如果有多个域名同时解析了一个网站,仅仅按照上面的方式进行配置时会出现一个问题:仅申请的那个域名在访问的时候显示的https安全 Lock - 安全
用其余的域名访问不但不会显示没有https时候的查看网站信息 - 信息或不安全
并且会变成这个 危险 - 不安全或危险
点开那个提示就能看到这样的原因,浏览器发现证书签发的域名和实际访问的域名并不一样,所以它认为,尽管你访问的网站是新域名的那个,但是却被原来的那个域名劫持和篡改了内容,并且签发了自己的证书...当然会提示不安全。
尽管我们自己知道,那个域名指向的其实也是这个网站,可是对于大多数人来说这样是不行的...所以,要为另一个同样指向该网站的域名申请自己的证书,并且需要nginx根据情况返回对应证书才行。
申请方式没什么太大区别,还是那个命令,换成新域名去申请就可以了。配置nginx的时候,配置文件里要把一个段落分成两个
比如原先是这个样子

server {
    listen                     80;
    listen                     443 ssl http2;
    server_name                demo1.youdomain.com;
    server_name                demo2.youdomain.com;
    charset                    utf-8;
    ssl_certificate            /etc/letsencrypt/live/demo1.youdomain.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/demo1.youdomain.com/privkey.pem;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache          shared:SSL:5m;
    ssl_session_timeout        5m;

    keepalive_timeout          75s;
    keepalive_requests         100;

    if ($scheme = http) {
        return  301 https://$host$request_uri;
    }

    location / {
        index  index.html index.htm index.php;
    }
}

要是申请了两个证书要改成这样

server {
    listen                     80;
    listen                     443 ssl http2;
    server_name                demo1.youdomain.com;
    charset                    utf-8;
    ssl_certificate            /etc/letsencrypt/live/demo1.youdomain.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/demo1.youdomain.com/privkey.pem;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache          shared:SSL:5m;
    ssl_session_timeout        5m;

    keepalive_timeout          75s;
    keepalive_requests         100;

    if ($scheme = http) {
        return  301 https://$host$request_uri;
    }

    location / {
        index  index.html index.htm index.php;
    }
}


server {
    listen                     80;
    listen                     443 ssl http2;
    server_name                demo2.youdomain.com;
    charset                    utf-8;
    ssl_certificate            /etc/letsencrypt/live/demo2.youdomain.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/demo2.youdomain.com/privkey.pem;
    ssl_prefer_server_ciphers  on;
    ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache          shared:SSL:5m;
    ssl_session_timeout        5m;

    keepalive_timeout          75s;
    keepalive_requests         100;

    if ($scheme = http) {
        return  301 https://$host$request_uri;
    }

    location / {
        index  index.html index.htm index.php;
    }
}

以此类推,申请了几个证书复制几次改下请求域名和证书位置就可以了。然后保存,重载。

6.测试证书续期

尽管Let's Encrypt免费给大家提供证书,可是缺点就是他们的证书有效期只有3个月,每次都进行手动申请实在是太麻烦了。
不过certbot为大家提供了自动续期的方案。首先先来执行下面的命令模拟一下申请证书续期的情况
certbot renew --dry-run
等待这条指令结束,会看到它自动模拟更新了所有的证书,模拟结果会在屏幕上显示

** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/demo1.yodomain.com/fullchain.pem (success)
  /etc/letsencrypt/live/demo2.yodomain.com/fullchain.pem (success)
  /etc/letsencrypt/live/demo3.yodomain.com/fullchain.pem (success)
  /etc/letsencrypt/live/demo4.yodomain.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.

根据结果可以看到模拟续期成功了。另外说一下,在正式进行证书续期的时候,使用的命令是下面两个里的任意一个
certbot renew
certbot renew --quiet
因为,certbot为了节能~会自动检测证书的有效性,会跳过没有被吊销并且剩余有效期大于30证书,不进行更新。上面的命令是为了怕出问题做的测试,有点强制的意思在里面。(不过哪怕你想强制更新也不要用那个命令,尽管它强制申请了,但还是不会保存,下面会说该怎么办)

7.添加定时任务自动续期

成功之后把证书续期和重载nginx的命令加到cron里面去。
先是都知道的
crontab -e
然后按照你想要的频率添加进去,比如下面就是每周一的1:30自动进行证书更新,然后再同理加个重载即可
30 1 * * 1 certbot renew --quiet
不过建议用每周固定的那天或着每月固定的哪天这种方式添加,不要添加成隔多少天更新一次的那种。因为那样的话,服务器一关机重启,crontab的计数会重新开始,隔的周期太长会错过更新证书失效。

如果你嫌麻烦可以直接抄走我下面这条,意思是每周一凌晨2点30检查一次证书更新,删除上次日志,并且把更新记录写成新的日志存储,再重载服务有错误同样记录在日志里

30 2 * * 1 rm -f /etc/letsencrypt/renewal_log.txt && echo "$(date)" >> /etc/letsencrypt/renewal_log.txt && certbot renew >> /etc/letsencrypt/renewal_log.txt && service nginx restart >> /etc/letsencrypt/renewal_log.txt

添加完毕后...可以crontab -l查看下已有任务。

如果不放心cron有没有执行,可以写个每分钟输出一次时间的任务试试看,记得删除就好
*/1 * * * * echo "$(date)" >>/var/log/datecron.txt

8.强制更新证书

对于某些不喜欢节能设定的人,或者是意外情况必须要更新证书时,可以用下面这条命令
certbot renew --force-renewal
不过注意频率,Let's Encrypt是有配额限定的,超过移动频率会被封IP或着这个域名,不再发证书,详细配额见下方官网链接
https://letsencrypt.org/docs/rate-limits/

Last modification:January 13th, 2020 at 01:06 pm