@@ -8,6 +8,7 @@ const config = require('../lib/config');
88const error = require ( '../lib/error' ) ;
99const utils = require ( '../lib/utils' ) ;
1010const certificateModel = require ( '../models/certificate' ) ;
11+ const tokenModel = require ( '../models/token' ) ;
1112const dnsPlugins = require ( '../global/certbot-dns-plugins' ) ;
1213const internalAuditLog = require ( './audit-log' ) ;
1314const internalNginx = require ( './nginx' ) ;
@@ -26,10 +27,11 @@ function omissions() {
2627
2728const internalCertificate = {
2829
29- allowedSslFiles : [ 'certificate' , 'certificate_key' , 'intermediate_certificate' ] ,
30- intervalTimeout : 1000 * 60 * 60 , // 1 hour
31- interval : null ,
32- intervalProcessing : false ,
30+ allowedSslFiles : [ 'certificate' , 'certificate_key' , 'intermediate_certificate' ] ,
31+ intervalTimeout : 1000 * 60 * 60 , // 1 hour
32+ interval : null ,
33+ intervalProcessing : false ,
34+ renewBeforeExpirationBy : [ 30 , 'days' ] ,
3335
3436 initTimer : ( ) => {
3537 logger . info ( 'Let\'s Encrypt Renewal Timer initialized' ) ;
@@ -44,62 +46,51 @@ const internalCertificate = {
4446 processExpiringHosts : ( ) => {
4547 if ( ! internalCertificate . intervalProcessing ) {
4648 internalCertificate . intervalProcessing = true ;
47- logger . info ( 'Renewing SSL certs close to expiry...' ) ;
48-
49- const cmd = certbotCommand + ' renew --non-interactive --quiet ' +
50- '--config "' + letsencryptConfig + '" ' +
51- '--work-dir "/tmp/letsencrypt-lib" ' +
52- '--logs-dir "/tmp/letsencrypt-log" ' +
53- '--preferred-challenges "dns,http" ' +
54- '--disable-hook-validation ' +
55- ( letsencryptStaging ? '--staging' : '' ) ;
56-
57- return utils . exec ( cmd )
58- . then ( ( result ) => {
59- if ( result ) {
60- logger . info ( 'Renew Result: ' + result ) ;
49+ logger . info ( 'Renewing SSL certs expiring within ' + internalCertificate . renewBeforeExpirationBy [ 0 ] + ' ' + internalCertificate . renewBeforeExpirationBy [ 1 ] + ' ...' ) ;
50+
51+ const expirationThreshold = moment ( ) . add ( internalCertificate . renewBeforeExpirationBy [ 0 ] , internalCertificate . renewBeforeExpirationBy [ 1 ] ) . format ( 'YYYY-MM-DD HH:mm:ss' ) ;
52+
53+ // Fetch all the letsencrypt certs from the db that will expire within the configured threshold
54+ certificateModel
55+ . query ( )
56+ . where ( 'is_deleted' , 0 )
57+ . andWhere ( 'provider' , 'letsencrypt' )
58+ . andWhere ( 'expires_on' , '<' , expirationThreshold )
59+ . then ( ( certificates ) => {
60+ if ( ! certificates || ! certificates . length ) {
61+ return null ;
6162 }
6263
63- return internalNginx . reload ( )
64- . then ( ( ) => {
65- logger . info ( 'Renew Complete' ) ;
66- return result ;
67- } ) ;
68- } )
69- . then ( ( ) => {
70- // Now go and fetch all the letsencrypt certs from the db and query the files and update expiry times
71- return certificateModel
72- . query ( )
73- . where ( 'is_deleted' , 0 )
74- . andWhere ( 'provider' , 'letsencrypt' )
75- . then ( ( certificates ) => {
76- if ( certificates && certificates . length ) {
77- let promises = [ ] ;
78-
79- certificates . map ( function ( certificate ) {
80- promises . push (
81- internalCertificate . getCertificateInfoFromFile ( '/etc/letsencrypt/live/npm-' + certificate . id + '/fullchain.pem' )
82- . then ( ( cert_info ) => {
83- return certificateModel
84- . query ( )
85- . where ( 'id' , certificate . id )
86- . andWhere ( 'provider' , 'letsencrypt' )
87- . patch ( {
88- expires_on : moment ( cert_info . dates . to , 'X' ) . format ( 'YYYY-MM-DD HH:mm:ss' )
89- } ) ;
90- } )
91- . catch ( ( err ) => {
92- // Don't want to stop the train here, just log the error
93- logger . error ( err . message ) ;
94- } )
95- ) ;
96- } ) ;
64+ /**
65+ * Renews must be run sequentially or we'll get an error 'Another
66+ * instance of Certbot is already running.'
67+ */
68+ let sequence = Promise . resolve ( ) ;
69+
70+ certificates . forEach ( function ( certificate ) {
71+ sequence = sequence . then ( ( ) =>
72+ internalCertificate
73+ . renew (
74+ {
75+ can : ( ) =>
76+ Promise . resolve ( {
77+ permission_visibility : 'all' ,
78+ } ) ,
79+ token : new tokenModel ( ) ,
80+ } ,
81+ { id : certificate . id } ,
82+ )
83+ . catch ( ( err ) => {
84+ // Don't want to stop the train here, just log the error
85+ logger . error ( err . message ) ;
86+ } ) ,
87+ ) ;
88+ } ) ;
9789
98- return Promise . all ( promises ) ;
99- }
100- } ) ;
90+ return sequence ;
10191 } )
10292 . then ( ( ) => {
93+ logger . info ( 'Completed SSL cert renew process' ) ;
10394 internalCertificate . intervalProcessing = false ;
10495 } )
10596 . catch ( ( err ) => {
0 commit comments