GithubHelp home page GithubHelp logo

therootcompany / greenlock.js Goto Github PK

View Code? Open in Web Editor NEW
61.0 3.0 16.0 602 KB

🔐 Free SSL, Free Wildcard SSL, and Fully Automated HTTPS for node.js, issued by Let's Encrypt v2 via ACME

Home Page: https://git.rootprojects.org/root/greenlock.js

License: Mozilla Public License 2.0

JavaScript 98.91% Shell 1.09%
letsencrypt acme-client acme acme-dns acme-challenge

greenlock.js's Introduction

New Documentation & v4 Migration Guide

We're still working on the full documentation for this new version, so please be patient.

To start, check out the Migration Guide.

"Greenlock Logo"

"Greenlock Function"

Greenlock is Let's Encrypt for JavaScript

| Built by Root for Hub

Greenlock™ is an Automated Certificate Management Environement 🔐.

| Greenlock | Greenlock Express | ACME.js |

It uses Let's Encrypt to generate Free SSL Certificates, including Wildcard SSL. It supports Automated Renewal of certs for Fully Automated HTTPS.

It's written in plain JavaScript and works in Node, Browsers, and WebPack.

the easiest way to integrate Let's Encrypt into your projects, products, and infrastructure.

  • Wildcard Certificates
  • IoT Environments
  • Enterprise and On-Prem
  • Private Networks
  • Localhost Development
  • Web Hosting Providers
  • Commercial support

We've built it simple enough for Hobbyists, and robust enough for the Enterprise.

Quick Start

Greenlock is fully-automated, SSL Certificate Manager for IoT, Web Hosting, and Enterprise On-Prem, Edge, and Hybrid Cloud.

(though we started building it for Home Servers)

You can use it for one-off certificates, like certbot, but it is much more powerful than that.

By setting just a few callbacks to let it know where it should store private keys and certificates, it will automatically renew any certificate that you add to it, as long as the process is running.

Certificates are renewed every 45 days by default, and renewal checks will happen several times a day.

1. Configure
'use strict';

var pkg = require('./package.json');
var Greenlock = require('greenlock');
var greenlock = Greenlock.create({
    packageRoot: __dirname,
    configDir: "./greenlock.d/",
    packageAgent: pkg.name + '/' + pkg.version,
    maintainerEmail: pkg.author,
    staging: true,
    notify: function(event, details) {
        if ('error' === event) {
            // `details` is an error object in this case
            console.error(details);
        }
    }
});

greenlock.manager
    .defaults({
        agreeToTerms: true,
        subscriberEmail: '[email protected]'
    })
    .then(function(fullConfig) {
        // ...
    });
2. Add Domains

The subject (primary domain on certificate) will be the id, so it's very important that the order of the given domains be deterministic.

var altnames = ['example.com', 'www.example.com'];

greenlock
    .add({
        subject: altnames[0],
        altnames: altnames
    })
    .then(function() {
        // saved config to db (or file system)
    });

Issuance and renewal will start immediately, and run continually.

3. Test for Success

The store callbacks will be called every any of your certificates are renewed.

However, you can do a quick one-off check with get.

It will return a certificate immediately (if available), or wait for the renewal to complete (or for it to fail again).

greenlock
    .get({ servername: subject })
    .then(function(pems) {
        if (pems && pems.privkey && pems.cert && pems.chain) {
            console.info('Success');
        }
        //console.log(pems);
    })
    .catch(function(e) {
        console.error('Big bad error:', e.code);
        console.error(e);
    });

JavaScript API

Greenlock.create({ configDir, packageAgent, maintainerEmail, staging })

Greenlock.create()

Creates an instance of greenlock with environment-level values.

var pkg = require('./package.json');
var gl = Greenlock.create({
    configDir: './greenlock.d/',

    // Staging for testing environments
    staging: true,

    // This should be the contact who receives critical bug and security notifications
    // Optionally, you may receive other (very few) updates, such as important new features
    maintainerEmail: '[email protected]',

    // for an RFC 8555 / RFC 7231 ACME client user agent
    packageAgent: pkg.name + '/' pkg.version
});
Parameter Description
configDir the directory to use for file-based plugins
maintainerEmail the developer contact for critical bug and security notifications
packageAgent if you publish your package for others to use, require('./package.json').name here
staging use the Let's Encrypt staging URL instead of the production URL
directoryUrl for use with other (not Let's Encrypt) ACME services, and the Pebble test server
Greenlock#manager.defaults()

Greenlock#manager.defaults()

Acts as a getter when given no arguments.

Otherwise sets default, site-wide values as described below.

greenlock.manager.defaults({
    // The "Let's Encrypt Subscriber" (often the same as the maintainer)
    // NOT the end customer (except where that is also the maintainer)
    subscriberEmail: '[email protected]',
    agreeToTerms: true
    challenges: {
      "http-01": {
        module: "acme-http-01-webroot",
        webroot: "/path/to/webroot"
      }
    }
});
Parameter Description
agreeToTerms (default: false) either 'true' or a function that presents the Terms of Service and returns it once accepted
challenges['http-01'] provide an http-01 challenge module
challenges['dns-01'] provide a dns-01 challenge module
challenges['tls-alpn-01'] provide a tls-alpn-01 challenge module
challenges[type].module the name of your challenge module
challenges[type].xxxx module-specific options
renewOffset leave the default Other than for testing, leave this at the default of 45 days before expiration date ('-45d') . Can also be set like 5w, meaning 5 weeks after issue date
servername the default servername to use for non-sni requests (many IoT clients)
subscriberEmail the contact who agrees to the Let's Encrypt Subscriber Agreement and the Greenlock Terms of Service
this contact receives renewal failure notifications
store override the default storage module
store.module the name of your storage module
store.xxxx options specific to your storage module
Greenlock#add({ subject, altnames })

Greenlock#add()

Greenlock is a Automated Certificate Management Environment.

Once you add a "site", it will begin to automatically renew, immediately.

The certificates will provided to the store callbacks as soon as they are ready, and whenever they renew. Failure to renew will be reported to the notify callback.

You can also retrieve them one-off with get.

gl.add({
    subject: 'example.com',
    altnames: ['example.com', 'www.example.com', 'exampleapi.com']
});
Parameter Description
subject the first domain on, and identifier of the certificate
altnames first domain, plus additional domains
note: the order should always be the same
subscriberEmail if different from the default (i.e. multi-tenant, whitelabel)
challenges (same as main config) use if this site needs to use non-default http-01 or dns-01 validation
Greenlock#get({ servername })

Greenlock#get()

Disclaimer: This is only intended for testing, demos, and SNICallback (in Greenlock Express).

Greenlock is intended to be left running to allow it to fetech and renew certifictates automatically.

It is intended that you use the store callbacks to new certificates instantly as soon as they renew. This also protects you from accidentally stampeding the Let's Encrypt API with hundreds (or thousands) of certificate requests.

return greenlock.get({ servername }).then(function(site) {
    if (!site) {
        console.log(servername + ' was not found in any site config');
        return;
    }

    var privkey = site.pems.privkey;
    var fullchain = site.pems.cert + '\n' + site.pems.chain + '\n';
    console.log(privkey);
    console.log(fullchain);
});
Parameter Description
servername any altname listed on the certificate (including the subject)
Greenlock#renew({ renewBefore })

Greenlock#renew()

This will renew only domains that have reached their renewAt or are within the befault renewOffset.

Note: This runs at regular intervals, multiple times a day, in the background. You are not required to call it. If you implement the store callbacks, the certificates will automatically be saved (and if you don't implement them, they all get saved to disk).

return 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);
    });
});
Parameter Type Description
(optional) ALL parameters are optional, but some should be paired
force bool force silly options, such as tiny durations
renewBefore ms Check domains that are scheduled to renew before the given date in milliseconds
Greenlock#remove({ subject })

Greenlock#manager.remove()

To stop certificates from being renewed, you must remove them.

If you are implementing your own manager callbacks, I recommend that you mark them as deleted (i.e. deleted_at in your database) rather than actually removing them. Just in case.

gl.remove({
    subject: 'example.com'
}).then(function(siteConfig) {
    // save the old site config elsewhere, just in case you need it again
});
Parameter Description
subject the first domain on, and identifier of the certificate
Events

Most of the events bubble from ACME.js.

See https://git.rootprojects.org/root/acme.js#api-overview

TODO: document the greenlock-specific events.

Install

Greenlock comes with reasonable defaults but when you install it, you should also install any plugins that you need.

npm install --save @root/greenlock@v4
npm install --save @greenlock/manager
npm install --save greenlock-store-fs
npm install --save acme-http-01-standalone

Easy to Customize

SSL Cert & Domain Management

SSL Certificate & Domain Management

Full Docs: https://git.rootprojects.org/root/greenlock-manager-test.js

This is what keeps the mapping of domains <-> certificates. In many cases it will interact with the same database as the Key & Cert Store, and probably the code as well.

  • set({ subject, altnames, renewAt })
  • find({ servernames, renewBefore })
    // should return a list of site configs:
    [
        {
            subject: 'example.com',
            altnames: ['example.com', 'exampleapi.com'],
            renewAt: 1575197231760
        },
        {
            subject: '*.example.com',
            altnames: ['*.example.com'],
            renewAt: 1575197231760,
            challenges: {
                'dns-01': {
                    module: 'acme-dns-01-dnsimple',
                    apikey: 'xxxx'
                }
            }
        }
    ];
  • remove({ subject })
  • defaults() (both getter and setter)
    {
        "subscriberEmail": "[email protected]",
        "agreeToTerms": true,
        "challenges": {
            "http-01": {
                "module": "acme-http-01-standalone"
            }
        }
    }
Key & Cert Storage

Key and Certificate Store

Full Docs: https://git.rootprojects.org/root/greenlock-store-test.js

This set of callbacks update your service with new certificates and keypairs.

Account Keys (JWK)

(though typically you only have one account key - because you only have one subscriber email)

  • accounts.setKeypair({ email, keypair })
  • accounts.checkKeypair({ email })

Certificate Keys (JWK + PEM)

(typically you have one for each set of domains, and each load balancer)

  • certificates.setKeypair({ subject, keypair })
  • certificates.checkKeypair({ subject }) (these are fine to implement the same as above, swapping subject/email)

Certificate PEMs

  • certificates.set({ subject, pems })
  • certificates.check({ subject })
ACME HTTP-01 Challenges

ACME Challenge HTTP-01 Strategies

Full Docs: https://git.rootprojects.org/root/acme-http-01-test.js

This validation and authorization strategy is done over plain HTTP on Port 80.

These are used to set files containing tokens that Let's Encrypt will fetch from each domain before authorizing a certificate.

NOT for Wildcards.

  • init({ request })
  • set({ challenge: { type, token, keyAuthorization, challengeUrl } })
  • get({ challenge: { type, token } })
  • remove({ challenge: { type, token } })
ACME DNS-01 Challenges

ACME Challenge DNS-01 Strategies

Full Docs https://git.rootprojects.org/root/acme-dns-01-test.js

This validation and authorization strategy is done over DNS on UDP and TCP ports 53.

For Wildcards

These are used to set TXT records containing tokens that Let's Encrypt will fetch for each domain before authorizing a certificate.

  • init({ request })
  • zones()
  • set({ challenge: { type, dnsZone, dnsPrefix, dnsHost, keyAuthorizationDigest } })
  • get({ challenge: { type, dnsZone, dnsPrefix, dnsHost } })
  • remove({ challenge: { type, dnsZone, dnsPrefix, dnsHost } })
Notes on HTTP-01 & DNS-01 Integrations

Notes on HTTP-01 & DNS-01 Integrations

For Public Web Servers running on a VPS, the default HTTP-01 challenge plugin will work just fine, for most people.

However, for environments that cannot be verified via public HTTP, such as

  • Wildcard Certificates
  • IoT Environments
  • Enterprise On-Prem
  • Private Networks

Greenlock provides an easy way to integrate Let's Encrypt with your existing services through a variety of DNS-01 challenges.

Why not use dns01 for everything?

Typically file propagation is faster and more reliably than DNS propagation. Therefore, http-01 will be preferred to dns-01 except when wildcards or private domains are in use.

http-01 will only be supplied as a defaut if no other challenge is provided.

Ready-made Integrations

Greenlock Express integrates between Let's Encrypt's ACME Challenges and many popular services.

Type Service Plugin
dns-01 CloudFlare acme-dns-01-cloudflare
dns-01 Digital Ocean acme-dns-01-digitalocean
dns-01 DNSimple acme-dns-01-dnsimple
dns-01 DuckDNS acme-dns-01-duckdns
http-01 File System / Web Root acme-http-01-webroot
dns-01 GoDaddy acme-dns-01-godaddy
dns-01 Gandi acme-dns-01-gandi
dns-01 NameCheap acme-dns-01-namecheap
dns-01 Name.com acme-dns-01-namedotcom
dns-01 Route53 (AWS) acme-dns-01-route53
http-01 S3 (AWS, Digital Ocean, Scaleway) acme-http-01-s3
dns-01 Vultr acme-dns-01-vultr
dns-01 Build your own acme-dns-01-test
http-01 Build your own acme-http-01-test
tls-alpn-01 Contact us -

Search acme-http-01- or acme-dns-01- on npm to find more.

Commercial Support

Do you need...

  • training?
  • specific features?
  • different integrations?
  • bugfixes, on your timeline?
  • custom code, built by experts?
  • commercial support and licensing?

You're welcome to contact us in regards to IoT, On-Prem, Enterprise, and Internal installations, integrations, and deployments.

We have both commercial support and commercial licensing available.

We also offer consulting for all-things-ACME and Let's Encrypt.

Legal & Rules of the Road

Greenlock™ is a trademark of AJ ONeal

The rule of thumb is "attribute, but don't confuse". For example:

Built with Greenlock Express (a Root project).

Please contact us if you have any questions in regards to our trademark, attribution, and/or visible source policies. We want to build great software and a great community.

Greenlock™ | MPL-2.0 | Terms of Use | Privacy Policy

greenlock.js's People

Contributors

bayareanewsgroup-pmarashian avatar coolaj86 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

greenlock.js's Issues

TypeScript .d.ts

So far I'm pretty pleased with everything this module has to offer. I don't think it's reasonable to rewrite the hole thing in typescript but having a definition file is probably a good idea.

I tried downloading @types/greenlock and @types/@root/greenlock but found nothing. If there's something I'm missing, please let me know.

I got started on it but there are a couple of spots that I got hung up.

For places I don't know the exact value necessary I just put in any or made a note how how the shape is supposed to look like. If you have any insights, I'll gladly accept them. I probably won't be interacting with @root/greenlock directly so I probably could have just exported the class as any but this may help someone else and may help you all internally if you ever plan to make the switch to typescript. I may not be a big fan of microsoft but I'm a fan of typescript

Unfinished greenlock.d.ts

declare module "@root/greenlock" {

  type JSON_Primitives = boolean | number | string;
  type JSON_Array = Array<JSON_Primitives | JSON_Array | JSON_Object>
  type JSON_Object = {
    [key: string]: JSON_Primitives | JSON_Array | JSON_Object
  }
  type JSON_Unknown = JSON_Primitives | JSON_Array | JSON_Object;

  // Note: the get args cannot have a number of options
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/greenlock.js#L262
  type GetArgs = {
    serverName: string
  }

  // I may be missing args related to mega.find
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L237
  // Also args related to gconf.find
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L237
  export function create(gconf?: {
    maintainerEmail: string,
    notify?: (ev: string, params: any)=>any
    packageRoot?: string
    manager: {
      module: string
    }
    staging?: boolean
    directoryUrl?: string
    renew?: boolean
  }): Greenlock;

  type RenewArgs = {
    servername?: string
    wildname?: string
    servernames?: Array<string>
    altnames?: Array<string>
    subject?: string
    renewBefore?: number
  }

  // Returns the value of mega.find
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L237
  // which is mini.find
  // which comes fro loadManager
  // which is loaded from a generic file
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L237

  // I'm able to guess what it looks like but no certianty
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/greenlock.js#L341
  type RenewValue = {
    // I don't know what the site is supposed to look like
    site: any
    // I don't know what the pems are supposed to look like
    pems?: any
    error?: any & {
      toJSON(): JSON_Unknown
      context: any | "cert_order"
      subject?: any
      servername?: string
    }
  }

  // Maybe more, since mega then does its own thing
  // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L169
  type SiteArg = {
    renewOffset?: number | string
    renewStagger?: number | string
    subject: string,
    altnames: Array<string>
  }

  type AddSite = (arg: SiteArg)=>any
  type UpdateSite = (arg: SiteArg)=>any
  type RemoveSite = ({ subject: string })=>any

  type SitesUpdater = {
    add: AddSite
    update: UpdateSite
    remove: RemoveSite
  }

  type SitesGetter = {
    get(args: any):  Promise<any>
  }


  type SitesManager = {
    // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L54
    defaults(conf?: any): Promise<any>
    set: UpdateSite
    // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L196
    // https://github.com/therootcompany/greenlock.js/blob/f01286d5b1dfd73015be9316dd3e5c1cd614d25f/lib/manager-wrapper.js#L344
    init(args: any): any
  }

  export type Greenlock = SitesUpdater & {
    notify(ev: string, params: any): void
    renew(args?: RenewArgs): Promise<Array<RenewValue>>
    get(args: GetArgs): Promise<null|RenewValue>
    sites: SitesUpdater & SitesGetter
    manager: SitesUpdater & SitesGetter & SitesManager
    challenges: {
      get(chall: {
        servername?: string,
        altname?: string,
        identifier?: {
          value: string
        }
        // Is type necessary?
        type: string
        token?: string
      }): Promise<(
        null |
        { keyAuthorization: string} |
        { keyAuthorizationDigest: string }
      )>
    }
  }

}

Using greenlock without express module

I am trying to use the only the greenlock module with my server so that I have more customization capability
The code is given below

const app = require('./app.ts');
const path = require('path');
const pkg = require('../package.json');
const rootdir = path.join(__dirname, '../');
console.log(rootdir);
const Greenlock = require('greenlock');
const greenlock = Greenlock.create({
    packageRoot: rootdir,
    configDir: './greenlock.d/',
    packageAgent: pkg.name + '/' + pkg.version,
    maintainerEmail: '[email protected]',
    staging: false,
    notify: function (event: any, details: any) {
        if ('error' === event) {
            // `details` is an error object in this case
            console.error('details', details);
        }
    },
});


greenlock.manager
    .defaults({
        agreeToTerms: true,
        subscriberEmail: '[email protected]'
    })
    .then(function(fullConfig:any) {
        console.log('fullconfig',fullConfig)
    });


const altnames = ['con.getbonton.com'];

greenlock
    .add({
        subject: altnames[0],
        altnames: altnames,
    })
    .then(function (data: any) {
        // saved config to db (or file system)
        console.log('config', data);
    });
app.listen(80)
app.listen(443)

I am getting dry challenge failed error when I try to run the above code

Could you push greenlock 4.0.5 to NPM?

Hello and thank you for the great project.

I noticed 4.0.5 was commited 11 months ago and updates ACME.js which had improvements on poling and HTTP methods.

But NPM still has 4.0.3 from even longer ago.

Do you mind pushing the updated greenlock so we don't need to install from GitHub URLs instead of NPM?

Thank you!

Project status

The last commit has been pushed two years ago and there are nearly 30 open issues between github and rootprojects.

Is this project actively maintained? Is it abandoned?

Thank you for your work.

Is this still maintained?

Hi

I hope this message finds you well. I wanted to reach out and inquire about the current status of the greenlock.js project, as I noticed that there haven't been any updates in some time.

I'm particularly interested in this project and would love to contribute to its development. If you're no longer maintaining the repo, I would be interested in taking over as the project's maintainer.

I'm passionate about open source software and have experience contributing to other projects.

If you're open to the idea, I'd be happy to discuss what taking over the project would entail and answer any questions you may have. Alternatively, if you're still interested in maintaining the project, I would be happy to contribute as a collaborator and try to modernize this codebase a bit to bring it up to todays standard and targeting node LTS versions.

Thank you for your time and consideration. I look forward to hearing from you.

Best regards,
Jimmy Wärting

@root/csr (dep of greenlock) erroneously lists @root/keypairs ad a devDepencency when i's a production dependency

Because it's no longer possible to submit tickets here: https://git.coolaj86.com/coolaj86/csr.js.git ...
I appears that @root/keypairs is erroneously listed as a devDependency here: https://git.coolaj86.com/coolaj86/csr.js/src/branch/master/package.json#L39
when in fact it is clearly a production dependency as it's called here: https://git.coolaj86.com/coolaj86/csr.js/src/branch/master/csr.js#L18
which impacts the initial certificate acquisition workflow if a server is (npm install'd and) started with NODE_ENV=production using modern releases of Node.js. In my debugging efforts, I used Node 18.14.2

Unknown desc = failed to select one blockedKeys: commands out of sync

On Oct 13, Let's Encrypt suffered a 10-min downtime. Similarly to #1, I, oblivious to the outage, had to restart my Node server around that time. Although the server had a valid cert until Dec, it couldn't boot, and I got the following errors:

Error cert_order:
[400] rpc error: code = Unknown desc = failed to select one blockedKeys: commands out of sync.
Did you run multiple statements at once?

and

code: E_ACME
Error: [400] sa.StorageAuthority.KeyBlocked timed out after 5001 ms
    at /app/node_modules/@root/acme/utils.js:119:8
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at Object.greenlock._order (/app/node_modules/@root/greenlock/greenlock.js:445:23)
    at Object.greenlock._renew (/app/node_modules/@root/greenlock/greenlock.js:335:9)
    at Object.greenlock.get (/app/node_modules/@root/greenlock/greenlock.js:212:23)

In this case, the Node server wouldn't run until the Let's Encrypt endpoint was restored. It would be much better if Node was still allowed to start, and the error was only logged as a warning. Even if the cert was expired (which it wasn't), it would still be preferable to have a running server with an expired cert than to suffer downtime.

Any thoughts on how this could be improved, perhaps with softer error handling?

Thank you.

Let's Encrypt may be down for maintenance or `directoryUrl` may be wrong

Earlier this week (Monday, Apr 26 around 12:30 ET) Let's Encrypt was undergoing maintenance and its ACME v2 URL https://acme-v02.api.letsencrypt.org/directory was returning an error. I have greenlock-express set up with a valid cert (issued in March, expiring in June). I needed to restart Node but I got the following error:

Listening on 0.0.0.0:80 for ACME challenges, and redirecting to HTTPS
Listening on 0.0.0.0:443 for secure traffic
Ready to Serve:
	 demo.example.com
ACME Directory URL: https://acme-v02.api.letsencrypt.org/directory
[debug] Let's Encrypt may be down for maintenance or `directoryUrl` may be wrong
set greenlockOptions.notify to override the default logger
Error cert_order:
Cannot read property 'termsOfService' of undefined
TypeError: Cannot read property 'termsOfService' of undefined
    at fin (/path/node_modules/@root/acme/acme.js:74:23)
    at /path/node_modules/@root/acme/acme.js:95:12
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at Object.greenlock._acme (/path/node_modules/@root/greenlock/greenlock.js:393:9)
    at Object.greenlock._order (/path/node_modules/@root/greenlock/greenlock.js:421:20)
    at Object.greenlock._renew (/path/node_modules/@root/greenlock/greenlock.js:335:9)
    at Object.greenlock.get (/path/node_modules/@root/greenlock/greenlock.js:212:23)

It seems that greenlock pings the ACME endpoint every 1 hour, is that correct? From @root/greenlock/greenlock.js:387:

var dir = caches[dirUrl];
// don't cache more than an hour
if (dir && Date.now() - dir.ts < 1 * 60 * 60 * 1000) {
    return dir.promise;
}

await acme.init(dirUrl).catch(function(err) {
    // TODO this is a special kind of failure mode. What should we do?
    console.error(
        "[debug] Let's Encrypt may be down for maintenance or `directoryUrl` may be wrong"
    );
    throw err;
});

I don't fully understand the intent here but my question is - if the cert is still valid (in my case, it's expiring in June), a. why is it necessary to ping the ACME endpoint, and b. why does this ping prevent the Node server from starting (again, despite a valid cert)?

Expected: given a valid cert, greenlock should start the Node server.
Actual: given a valid cert, greenlock fails to start because ACME v2 endpoint is unavailable.

Packages:

  • @root/greenlock v4.0.5
  • @root/acme v3.1.0
  • @root/greenlock-express v4.0.4

Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.