Centos7+nginx使用Certbot脚本给Typecho和Gogs安装Let's Encrypt的TLS证书（超详细版本）
前言https在这个时代普遍性就不说了，最关键的是只要不乱装证书，带上这个可以让中间设备都无法获取通讯信息，对于网络会被审查的环境其实还是比较有用的。之前的SSL服务商基本证书价格都恐怖的吓人，哪怕我的blog访问数再多2个0我也完全不会考虑加证书，现在因为Let's Encrypt的出现，一下子就让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 certbot3.初次是用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当然要有，要是不同意人家怎么可能给用[scode type="red"]可能出现的问题注意如果这一步出现ImportError: cannot import name UnrewindableBodyError，说明urllib3库有问题了，需要重装。pip uninstall urllib3pip install urllib3[/scode]如果遇到这个问题的你使用的是阿里系主机[scode type="yellow"]但是，如果你用的是阿里云的机器提供的Ubuntu或者CentOS镜像，那求求你就就别用Certbot了，直接换。因为不明原因，阿里的这两个镜像在涉及Certbot的时候总是会出现问题，换acme.sh吧[/scode]emmm,附上一点额外的东西吧当然虽然我嘴上说着换工具，但是内心还是偏向Let's Encrypt推荐的Certbot...所以我就就这这个坑直接跳进去了Orz所以来说说阿里系遇到这种问题的解决方法，错误方案和中间过程因为尝试次数过多就不记录了，直接记解决方法...上面我已经使用pip uninstall urllib3把urllib3卸载掉了，重新安装的时候发现还是不行...所以干脆彻底了一点...把另两个也卸了...pip uninstall requestspip 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[scode type="yellow"]这里先提醒一下用面板的小伙伴们，宝塔我没试，appnode千万不要在里面直接可视化的手动选择导入然后开启...因为开启之后会发现虽然目前可以正常访问，打开配置原文却会看到证书路径被改动了，复制了一份到他们自己的路径下，然后进行的导入Orz，这样自动续期了也不会有什么作用...因为还是要手动导入（其实appnode之前是有自动使用Let's Encrypt签发证书并且自动更新和导入的功能的，但是因为Let's Encrypt去掉了他们之前使用的自动验证方式，所以暂时不能用了。appnode表示正在修复，不过...截止到发文已经咕咕咕了好几个月了...你们自己看着来）[/scode]①确定自己的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)检测[scode type="share"]如果无法访问，先去检测自己的服务器防火墙是否放行了443端口，然后就是如果是阿里等厂商的服务器，再看一下是不是厂商还额外套了一层防火墙，那个也要放行[/scode]④关于HTTP跳转HTTPS尽管有了HTTPS，还是因为用户习惯等各种原因有时会访问80端口的HTTP，这时候最好不要关闭80，而是做一个http跳转https的配置两种方法，第一种是在只开着443的时候，默认80会返回状态码497497 - 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安全 - 安全用其余的域名访问不但不会显示没有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 renewcertbot 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.txt8.强制更新证书对于某些不喜欢节能设定的人，或者是意外情况必须要更新证书时，可以用下面这条命令certbot renew --force-renewal不过注意频率，Let's Encrypt是有配额限定的，超过移动频率会被封IP或着这个域名，不再发证书，详细配额见下方官网链接https://letsencrypt.org/docs/rate-limits/