使用greenlock实现自动申请和续签Let's encrypt证书 前言 代码

随着Let’s Encrypt证书的不断流行,大多数网站都开始使用其作为自己的证书。当然,最主要的还是它的申请流程简单且免费!

搜了很久也没找到可以用的,大部分文章都已过时,官方文档也太过简略,无奈只能看源码总结出了部分实现代码,已经尽力把注释写的很详细了。

代码

  1. 使用nodejs实现
  2. 使用greenlock npm包
  3. 使用https方式验证
  4. 以申请域名 xpengp.test.com 域名为例
'use strict';

const pkg = require('./package.json'); // 引入项目配置文件
const Greenlock = require('greenlock');
const path = require('path');
const greenlock = Greenlock.create({
    packageRoot: path.resolve(__dirname, './lets'), // 后面config,store,account,live 的根目录(若后面配置的是绝对路径,当然就不会受影响了)
    configDir: './config.json', // config.json文件目录
    maintainerEmail: 'youremail', // 申请证书所需邮箱(默认邮箱 但必须有)
    packageAgent: pkg.name + '/' + pkg.version, // 申请证书请求中的User-Agent字段 name不能是汉字(package.json项目名称不支持汉字)
    staging: true, // 是否使用测试环境 测试环境会有更多的错误申请次数
    notify: function (event, details) { // 错误回调
        if ('error' === event) {
            console.error('出错了:');
            console.error(details);
        }
    }
});

//设置默认参数
greenlock.manager
    .defaults({ // 设置以后添加域名时的默认参数
        agreeToTerms: true, // 同意申请协议
        subscriberEmail: 'youremail', // 默认邮箱 可在添加时重写此配置
        //   challenges: { // 自动生成的测试文件目录 可以再这里默认配置 也可以在添加时配置或重写
        //     "http-01": {
        //         module: "acme-http-01-webroot",
        //         webroot: "/www/wwwroot/:hostname/.well-known/acme-challenge" // :hostname 并没有什么作用 但在store.basePath中起作用
        //     }
        // },
        store: {
            module: 'greenlock-store-fs',
            basePath: '/root/letsencrypt'  // 申请的密钥目录  申请的证书默认会放在这里的live目录下 (为相对路径时 以packageRoot为根目录)
        }
    })
    .then(function (fullConfig) { // 设置默认参数后的成功回调
        console.log('初始化完成')
    });

// add domains
greenlock.add({ // 新增域名并自动申请证书
    subject: 'xpengp.test.com', // subject会用于其他地方创建目录名时 使用
    altnames: ['xpengp.test.com'], // 可以为多个 但第一个必须和subject相同
    challenges: { // 重写默认测试地址
        "http-01": { // 采用http方式申请 方便
            module: "acme-http-01-webroot",
            webroot: "/www/wwwroot/xpengp.test.com/.well-known/acme-challenge" // 该目录保存申请证书时的challenge文件 具体看下面注释
        }
    },
});
// 获取证书 可用于测试是否申请成功 返回promise
greenlock
    .get({ servername: 'xpengp.test.com' }) // 申请证书成功后 使用此方法可获取证书的所有信息
    .then(function (pems) { // 成功回调
        console.log(pems);
    })
    .catch(function (e) {
        console.error('Big bad error:', e.code);
        console.error(e);//
    });
(async ()=> {
    let ret = await greenlock.get({ servername: 'xpengp.test.com' });
    console.log(ret);
})();


// 自动续签检查更新(调用后会在后台运行并自动续签)
greenlock.renew({}).then(function(results) {
    // 检查完的回调
    results.forEach(function(site) {
        if (site.error) {
            console.error(site.subject, site.error);
            return;
        }
        console.log('Renewed certificate for', site.subject, site.altnames);
    });
});

// 函数描述
/*
* 1.使用Greenlock.create 创建使用Greenlock对象
* 2.greenlock.manager.defaults 设置后面添加域名的默认参数 可在添加时重写部分参数
* 3.greenlock.add 添加域名
* 4.greenlock.get获取域名的证书信息
* */

// let's 的证书申请流程(个人理解)
/*
* 1.使用该库构建acount信息 生成对应邮箱的公钥等信息 存放在store设置的目录下
* 2.申请时 会在本地自动创建challenge文件 存放在challenges.http-01.webroot设置的目录下
* 3.采用http验证方式 - 在发出申请请求时附带token let's服务器会根据token获取域名 .well-known/acme-challenge 目录下的对应文件 并比较是否相同  若相同即验证成功
* 4.验证成功后 会自动删除challenge文件
* 5.会在 store设置的根目录下创建live目录 然后对应域名 分别存放证书信息
* 6.之后 会根据config配置 自动检查并更新证书
* */

总结

  1. Let's发送的GET测试请求路径一般是固定的(.well-known/acme-challenge),所以可以把 .well-known 路径固定代理到一个文件夹来进行申请证书使用。如果自己项目中可能会用到这个路径,那只能在申请前先注释掉相应的代理了。
  2. 当然申请证书也是有次数限制的,尤其要注意账户申请次数和申请失败次数,所以建议先试用测试环境(不会避免限制,但可以增加次数)来测试申请证书。
    Let's速率限制(官方):https://letsencrypt.org/zh-cn/docs/rate-limits/
  3. 如果你的域名是解析到负载的,要对应多个ip。由于负载均衡,申请成功的概率会相应降低。