@@ -8,6 +8,7 @@ const config = require('../lib/config');
8
8
const error = require ( '../lib/error' ) ;
9
9
const utils = require ( '../lib/utils' ) ;
10
10
const certificateModel = require ( '../models/certificate' ) ;
11
+ const tokenModel = require ( '../models/token' ) ;
11
12
const dnsPlugins = require ( '../global/certbot-dns-plugins' ) ;
12
13
const internalAuditLog = require ( './audit-log' ) ;
13
14
const internalNginx = require ( './nginx' ) ;
@@ -26,10 +27,11 @@ function omissions() {
26
27
27
28
const internalCertificate = {
28
29
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' ] ,
33
35
34
36
initTimer : ( ) => {
35
37
logger . info ( 'Let\'s Encrypt Renewal Timer initialized' ) ;
@@ -44,62 +46,51 @@ const internalCertificate = {
44
46
processExpiringHosts : ( ) => {
45
47
if ( ! internalCertificate . intervalProcessing ) {
46
48
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 ;
61
62
}
62
63
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
+ } ) ;
97
89
98
- return Promise . all ( promises ) ;
99
- }
100
- } ) ;
90
+ return sequence ;
101
91
} )
102
92
. then ( ( ) => {
93
+ logger . info ( 'Completed SSL cert renew process' ) ;
103
94
internalCertificate . intervalProcessing = false ;
104
95
} )
105
96
. catch ( ( err ) => {
0 commit comments