去年入手了一个群晖的 NAS DS716+II,这玩意儿可以说是垂涎了好久,最后忍不住诱惑,终于是入手了。选了716+II这个盘位少但价格不便宜的家 伙说白了就是为了一件事——docker。有了docker,可以说就有了无限的可能性,可以随便折腾,不用担心犯错误 把NAS的主系统给搞乱了。
不过今天这篇文章我不打算介绍NAS,也不打算说怎么在上边用docker,我只想说说在这个上边怎么使用Let’s Encrypt的证书,以及怎么自动更新 证书。
[2018.05] 这篇文章提供的方案已经过时,请参考我的另一篇文章:群晖 Let’s Encrypt 泛域名证书自动更新
如果说你幸福的生活在一个运营商没有封80端口的国度,那么这篇文章你就不必往下看了,因为群晖的证书管理本身就内置了Let’s Encrypt的证书管理方式。我之所以写这篇文章,是因为我家的网络是没有开放80端口的,所以群晖自带的管理工具永远都是告诉你“无法连接到 Let's Encrypt。请确认域名有效。”
好在Let’s Encrypt提供了acme协议的认证方式,可以在没有80端口的情形下来签发和更新证书。
感谢伟大的Git Hub以及无私的开发者们,所有的工具基本上都已经被开发了出来。
Neilpang/acme.sh 这个项目基本上就是我们用到的所有的工具了。
如果你是一个动手能力强的人,那么我在告诉你一下群晖的证书的保存位置/usr/syno/etc/certif icate/
的话,余下的工作你就应该可以自己搞定了。
下面就开始介绍具体的步骤:
1. 下载并安装acme.sh
1 2 3 4
ssh -p your_port your_name@your_hostcurl https://get.acme.sh | sh
2. 修改配置文件 ,填入你在指定域名提供商的授权token
1 2 3 4 5 6 7 8
cd ~/.acme.sh/dnsapivi dns_ali.sh
不同的提供商的token的形式和配置方式可能会有不同,需要你到域名管理的后台自己去获取。
3. 准备用于存放安装后的证书的目录
1 2 3 4 5 6 7
mkdir cert_save_pathcd cert_save_pathmkdir sub1.example.commkdir sub2.example.com
4. 生成证书
1 2 3 4 5
source ~/.acme.sh/acme.sh.envacme.sh --issue --dns dns_ali -d sub1.example.com acme.sh --issue --dns dns_ali -d sub2.example.com
5. 安装证书
1 2 3 4 5 6 7 8 9
acme.sh --installcert -d sub1.example.com --certpath /cert_save_path/sub1.example.com/cert.pem --key-file /cert_save_path/sub1.example.com/privkey.pem --fullchain-file /cert_save_path/sub1.example.com/fullchain.pem acme.sh --installcert -d sub2.example.com --certpath /cert_save_path/sub2.example.com/cert.pem --key-file /cert_save_path/sub2.example.com/privkey.pem --fullchain-file /cert_save_path/sub2.example.com/fullchain.pem
其实这里的安装是指的acme将获取的证书安装到之前建立好的目录,并没有安装到NAS自己的证书管理下边。
6. NAS证书安装
控制面板 -> 安全性 -> 证书 -> 新增 -> 添加新证书 -> 导入证书(描述那里填完整的子域名) -> 导入证书文件(私钥为privkey 证书为cert.pem 中间证书为fullchain.pem)
这一步将我们从Let’s Encrypt获取的证书安装到了NAS,我们发现有效期是三个月,如果你能够接受三个月走一遍上边的流程,那么到这里就可以结束了,如果想把这个过程自动化起来,请接着看下边的流程。
7. 证书更新命令
因为Let’s Encrypt的证书的有效期只有三个月,所有我们必须至少每三个月执行一次更性操作,以防止证书过期。
1 2 3 4 5 6 7 8 9 10
acme.sh/acme.sh --renew --force --dns dns_ali -d sub1.example.com acme.sh/acme.sh --installcert -d sub1.example.com --certpath /cert_save_path/sub1.example.com/cert.pem --key-file /cert_save_path/sub1.example.com/privkey.pem --fullchain-file /cert_save_path/sub1.example.com/fullchain.pem acme.sh/acme.sh --renew --force --dns dns_ali -d sub2.example.com acme.sh/acme.sh --installcert -d sub2.example.com --certpath /cert_save_path/sub2.example.com/cert.pem --key-file /cert_save_path/sub2.example.com/privkey.pem --fullchain-file /cert_save_path/sub2.example.com/fullchain.pem
执行上边的命令,会从Let’s Encrypt更新证书,并安装到指定的位置。
8. 拷贝证书脚本
这一步我认为一定是有其他方法来做的,但是因为搞不明白群晖NAS的证书存放逻辑,暂时就想了这么一个折中的办法。
通过观察可以发现,所有证书相关的配置都是在路径/usr/syno/etc/certificate
下的,证书存放的具体位置是/usr/syno/etc/certificate/_archive
,该目录下的内容形如:
1
2zFLdC DEFAULT dXWIy3 h94Uuq IhSb6T INFO kGn0Zn uTv2EL vY1OEs WE3xYE
其中INFO的内容是一个JSON文件,记录了每个证书的存放位置和应用的范围,DEFAULT记录了哪一个是默认的证书,其他的目录则是存放一个一个的子域名的证书。
通过观察INFO的内容我们可以发现目录名和域名的对应关系,我编写了一个python脚本来分析这个对应关系以及将前文的证书拷贝到对应的位置,脚本名称为update.py.
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
import jsonimport osimport shutilSRC_BASE_PATH = '/cert_save_path' DES_BASE_PATH = '/usr/syno/etc/certificate' ARC_BASE_PATH = '/usr/syno/etc/certificate/_archive' keys = {} cfg_str = open ('/usr/syno/etc/certificate/_archive/INFO' ).read() cfg = json.loads(cfg_str) for k in cfg: for service in cfg[k]['services' ]: name = service['display_name' ] if name.find ('up4dev.com' ) 0 : continue keys[k] = {'name' : name, 'arc_path' : '%s/%s' %(ARC_BASE_PATH, k), 'des_path' : [], 'src_path' : '%s/%s' %(SRC_BASE_PATH, name)} for k in cfg: for service in cfg[k]['services' ]: des_path = '%s/%s/%s' %(DES_BASE_PATH, service['subscriber' ], service['service' ]) if os.path.exists(des_path): keys[k]['des_path' ].append(des_path) for key in keys: print keys[key] shutil.copy2(keys[key]['src_path' ] + '/cert.pem' , keys[key]['arc_path' ] + '/cert.pem' ) shutil.copy2(keys[key]['src_path' ] + '/privkey.pem' , keys[key]['arc_path' ] + '/privkey.pem' ) shutil.copy2(keys[key]['src_path' ] + '/fullchain.pem' , keys[key]['arc_path' ] + '/fullchain.pem' ) for des in keys[key]['des_path' ]: shutil.copy2(keys[key]['arc_path' ] + '/cert.pem' , des + '/cert.pem' ) shutil.copy2(keys[key]['arc_path' ] + '/privkey.pem' , des + '/privkey.pem' ) shutil.copy2(keys[key]['arc_path' ] + '/fullchain.pem' , des + '/fullchain.pem' )
9. 重启web服务
1 2
/usr/syno/etc/rc.sysv/nginx.sh reload
10. 自动化脚本
我们将8,9,10三个步骤的操作串起来,做成一个自动化脚本,保存为auto_update.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
acme.sh/acme.sh --renew --force --dns dns_ali -d sub1.example.com acme.sh/acme.sh --installcert -d sub1.example.com --certpath /cert_save_path/sub1.example.com/cert.pem --key-file /cert_save_path/sub1.example.com/privkey.pem --fullchain-file /cert_save_path/sub1.example.com/fullchain.pem acme.sh/acme.sh --renew --force --dns dns_ali -d sub2.example.com acme.sh/acme.sh --installcert -d sub2.example.com --certpath /cert_save_path/sub2.example.com/cert.pem --key-file /cert_save_path/sub2.example.com/privkey.pem --fullchain-file /cert_save_path/sub2.example.com/fullchain.pem python update.py /usr/syno/etc/rc.sysv/nginx.sh reload
11. 设置定时任务
控制面板 -> 任务计划 -> 新增 -> 计划的任务 -> 用户定义的脚本 -> 计划(设置成每月执行一次) -> 任务设置(用户定义的脚本中填入步骤10的脚本的完整路径)
[^2018.05.09]: Let’s Encrypt 已经支持wildcard类型的证书,可能已经有比本文更好的方法了,待我研究之后再写一篇文章。
[^2018.05.30]: 泛域名的更新方法我已经另写了另一篇文章,大家可以参考:群晖 Let’s Encrypt 泛域名证书自动更新
参考
文章来源于互联网:群晖 Let’s Encrypt 证书的自动更新
未经允许不得转载:窗外天空 » 群晖 Let’s Encrypt 证书的自动更新