CentOS7免费SSL证书及自动展期
This post shows you how to obtain a wildcard SSL certificate for free (which values at least $50) from Let’s Encrypt on CentOS 7.x Linux, and get it setup to renew by itself with an automated script.
至于什么是SSL证书,有什么用,这里不赘述了。大致上,一个泛域名(通配符)DV证书,价值怎么也在CNY 2000/年开外,注意是按年缴费;企业型(OV)证书则更贵,年费肯定不下万。因此别嫌命令行操作不好搞,有免费午餐已然相当给力,还要啥自行车。
按规矩,周知一下,证书发行方是Let’s Encrypt。之所以能送免(bai)费(piao)证书,据说主要是全自动。证书生成、发放、展期等操作,都经shell脚本完全自动化 —— 无人工就成本低,蛮好理解;至于抢了那几家拦路收费的生意,咱也捧个人场,起码希望他们能一直坚持做下去。
证书自动获取
来一台阿里云上的CentOS7,以非root(但具备sudo权限)用户连接,先下载certbot-auto脚本,并授以执行权限。
1 2 3 4 5 6 7 8 9 10 11 |
[py27@fisher-test ~]$ wget https://dl.eff.org/certbot-auto --2020-06-11 22:57:34-- https://dl.eff.org/certbot-auto 正在解析主机 dl.eff.org (dl.eff.org)... 151.101.228.201, 2a04:4e42:1a::201 正在连接 dl.eff.org ... 已连接。 已发出HTTP 请求,正在等待回应... 200 OK 长度:79897 (78K) [application/octet-stream] 正在保存至: “certbot-auto” 100%[===============================>] 79,897 5.73KB/s 用时13s 2020-06-11 22:57:50 (6.03 KB/s) - 已保存 “certbot-auto” [79897/79897]) |
然后以手工完成“挑战”(challenge)的方式,获取泛域名(通配符)DV证书,其中挑战选择DNS,也即按脚本要求,手工在域名解析中增加TXT记录 —— 以此证明此域名归属于申请者。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
[py27@fisher-test ~]$ ./certbot-auto certonly -d *.fisher.cn --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory Requesting to rerun ./certbot-auto with root privileges... ./certbot-auto has insecure permissions! To learn how to fix them, visit https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/ Saving debug log to /var/log/letsencrypt/letsencrypt.log(这里存放获取证书全过程日志供参考) Plugins selected: Authenticator manual, Installer None Obtaining a new certificate Performing the following challenges: dns-01 challenge for fisher.cn - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NOTE: The IP of this machine will be publicly logged as having requested this certificate. If you're running certbot in manual mode on a machine that is not your server, please ensure you're okay with that. Are you OK with your IP being logged?(作为申请数字证书的要求,是否可以记录本机IP) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please deploy a DNS TXT record under the name _acme-challenge.fisher.cn with the following value:(在域名中增加TXT解析,以完成“挑战”) MomldPnAKL4I8bL8FiwmqvJJdE7E97RH-ARf7PZgw88 Before continuing, verify the record is deployed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Press Enter to Continue(此处暂停,登你的DNS,设置解析;搞定后此处回车)【注:过后可删除】 Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at:(证书获取成功,存放位置如下) /etc/letsencrypt/live/fisher.cn/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/fisher.cn/privkey.pem Your cert will expire on 2020-09-11. To obtain a new or tweaked(证书过期时间,及更新方法) version of this certificate in the future, simply run certbot-auto again. To non-interactively renew *all* of your certificates, run "certbot-auto renew" - 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 |
那么证书如何将http通信升级为https,不同的后端有不同的代码实现方式。但就目前主流做法,大家倾向于让https通信脱离开发范畴,直接配置在httpd中,比如nginx config(或者apache之类均可):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
[py27@fisher-test ~]$ cat /etc/nginx/conf.d/test_server.conf server { listen 80; server_name test.fisher.cn; return 301 https://$server_name$request_uri; #监听80端口,有请求则无条件301跳转到443端口 } server { listen 443 ssl; server_name test.fisher.cn; charset utf-8; client_max_body_size 20M; sendfile on; keepalive_timeout 60; keepalive_requests 20; large_client_header_buffers 8 32k; send_timeout 20; # letsencrypt生成的文件 ssl_certificate /etc/letsencrypt/live/fisher.cn/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/fisher.cn/privkey.pem; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets on; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 一般推荐使用的ssl_ciphers值: https://wiki.mozilla.org/Security/Server_Side_TLS ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK'; ssl_prefer_server_ciphers on; location / { # 你真正的后端服务 # Bla bla } } |
证书自动展期
想必刚才你留意到了,锃光瓦亮的免费证书到手,https可以正常工作。然而证书有效期只有三个月,那到期后怎么玩呢?将原证书文件移除,然后重新申请?
其实不必,初次申请证书我们已经填写了必要的信息,续期时大可依例而为。唯一的问题是,域名TXT记录还是需要手工添加,未免过于繁琐 —— 那么域名解析记录如何实现自动增删呢?
现在就需要国人ywdblog开发的,对接let’s encrypt钩子的,自动增删DNS解析的python脚本。
有人可能会问,你自己github repo里那套阿里云ddns脚本不是改改就能用么?其实不然,ywdblog老兄的repo虽然提供的是类似功能,但胜在不依赖任何第三方包,也就是部署相比我那套更容易。现成的python 2.7环境,clone结束即运行,没有任何拖泥带水,在下何苦Reinventing the wheel呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[py27@fisher-test ~]$ git clone https://github.com/ywdblog/certbot-letencrypt-wildcardcertificates-alydns-au [py27@fisher-test ~]$ cat /home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh #!/bin/bash #ywdblog@gmail.com 欢迎关注我的书《深入浅出HTTPS:从原理到实战》 ###### 根据自己的情况修改 Begin ############## #PHP 命令行路径,如果有需要可以修改 phpcmd="/usr/bin/php" #Python 命令行路径,如果有需要可以修改 pythoncmd="/usr/bin/python" #填写阿里云的AccessKey ID及AccessKey Secret #如何申请见https://help.aliyun.com/knowledge_detail/38738.html #建议使用RAM账户,避免因KEY权限过大造成数据安全风险 ALY_KEY=“KKKKKKkkkkkkkKKK" ALY_TOKEN=“tttTTTTTTTttttttTTTT" ……(以下省略) |
然后……就没有然后了,离证书过期20天以内就可以运行续期命令,来自动完成DNS解析变更,从而获得新的SSL数字证书。
此外,在第一次申请证书完成后,建议把 certbot-auto 移动到 /etc/letsencrypt/,当然这一步是可选的。
- renew代表是续期,而不是新申请,那么用户身份信息,及上次执行成功后所用配置会自动获得。
- –preferred-challenges dns指希望使用dns来完成“挑战”。感兴趣其他挑战形式的,参考let’s encrypt官方文档。
- –deploy-hook “/bin/systemctl restart nginx” 如果成功续期,则重启nginx服务。
- –manual-auth-hook “/home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly add” 收到DNS挑战时,使用auth钩子启动第三方脚本来完成挑战。
- –manual-cleanup-hook “/home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly clean” 完成DNS挑战后,使用cleanup钩子清理挑战。
- 如果还不到续期时间窗口,而想要测试续期,可以加上–dry-run来模拟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
[py27@fisher-test ~]$ /etc/letsencrypt/certbot-auto renew --manual --preferred-challenges dns --deploy-hook "/bin/systemctl restart nginx" --manual-auth-hook "/home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly add" --manual-cleanup-hook "/home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly clean" Requesting to rerun /etc/letsencrypt/certbot-auto with root privileges... [sudo] py27 的密码: /etc/letsencrypt/certbot-auto has insecure permissions! To learn how to fix them, visit https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/ Upgrading certbot-auto 1.3.0 to 1.5.0... Replacing certbot-auto... Creating virtual environment... Installing Python packages... Installation succeeded. Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/fisher.cn.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OCSP check failed for /etc/letsencrypt/archive/fisher.cn/cert1.pem (are we offline?) Traceback (most recent call last):(如果遇到这个错误,可以忽略,不影响证书续期) File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot/ocsp.py", line 187, in _check_ocsp_cryptography timeout=timeout) File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/requests/api.py", line 116, in post return request('post', url, data=data, json=json, **kwargs) File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/requests/api.py", line 60, in request return session.request(method=method, url=url, **kwargs) File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/requests/sessions.py", line 533, in request resp = self.send(prep, **send_kwargs) File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/requests/sessions.py", line 646, in send r = adapter.send(request, **kwargs) File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/requests/adapters.py", line 504, in send raise ConnectTimeout(e, request=request) ConnectTimeout: HTTPConnectionPool(host='ocsp.int-x3.letsencrypt.org', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x7fded95609d0>, 'Connection to ocsp.int-x3.letsencrypt.org timed out. (connect timeout=10)')) Cert is due for renewal, auto-renewing... Plugins selected: Authenticator manual, Installer None Renewing an existing certificate Performing the following challenges: dns-01 challenge for fisher.cn Running manual-auth-hook command: /home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly add Waiting for verification... Cleaning up challenges Running manual-cleanup-hook command: /home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly clean Running deploy-hook command: /bin/systemctl restart nginx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - new certificate deployed without reload, fullchain is /etc/letsencrypt/live/fisher.cn/fullchain.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/fisher.cn/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
现在证书就续期成功了,可以检查一下自动DNS解析脚本留下的操作日志。
也可以看下更新后的证书详细信息。
后记
还有几件琐事,
- 至于有打算做成免人工全自动定时展期的情况,利用linux crontab就好,这里不多BB了。
- 泛域名(通配符)证书通常是多站共用,至于自动续期后如何同步到其他服务器,这个可以见仁见智,比如定时rsync,比如共享存储,都是手段,随便怎么玩。
- 希望大家都能珍惜免费版泛域名证书,and enjoy your secured https web services。
文章的脚注信息由WordPress的wp-posturl插件自动生成
暂无评论
引用