diff --git a/CHANGES b/CHANGES index 45b57766e..eb7041473 100644 --- a/CHANGES +++ b/CHANGES @@ -1682,4 +1682,5 @@ * Remove flicker of custom icon * Preserve PROVIDER setting from cloudron.conf * Add Skip backup option when updating an app +* Fix bug where nginx was not reloaded on cert renewal diff --git a/src/reverseproxy.js b/src/reverseproxy.js index 6ae21d54d..53b1eab92 100644 --- a/src/reverseproxy.js +++ b/src/reverseproxy.js @@ -354,8 +354,8 @@ function ensureCertificate(vhost, domain, auditSource, callback) { if (currentBundle) { debug(`ensureCertificate: ${vhost} certificate already exists at ${currentBundle.keyFilePath}`); - if (currentBundle.certFilePath.endsWith('.user.cert')) return callback(null, currentBundle); // user certs cannot be renewed - if (!isExpiringSync(currentBundle.certFilePath, 24 * 30) && providerMatchesSync(domainObject, currentBundle.certFilePath, apiOptions)) return callback(null, currentBundle); + if (currentBundle.certFilePath.endsWith('.user.cert')) return callback(null, currentBundle, { renewed: false }); // user certs cannot be renewed + if (!isExpiringSync(currentBundle.certFilePath, 24 * 30) && providerMatchesSync(domainObject, currentBundle.certFilePath, apiOptions)) return callback(null, currentBundle, { renewed: false }); debug(`ensureCertificate: ${vhost} cert require renewal`); } else { debug(`ensureCertificate: ${vhost} cert does not exist`); @@ -372,7 +372,7 @@ function ensureCertificate(vhost, domain, auditSource, callback) { // if no cert was returned use fallback. the fallback/caas provider will not provide any for example if (!certFilePath || !keyFilePath) return getFallbackCertificate(domain, callback); - callback(null, { certFilePath, keyFilePath }); + callback(null, { certFilePath, keyFilePath }, { renewed: true }); }); }); }); @@ -584,14 +584,17 @@ function renewCerts(options, auditSource, progressCallback, callback) { if (options.domain) appDomains = appDomains.filter(function (appDomain) { return appDomain.domain === options.domain; }); - let progress = 1; + let progress = 1, renewed = []; + async.eachSeries(appDomains, function (appDomain, iteratorCallback) { progressCallback({ percent: progress, message: `Renewing certs of ${appDomain.fqdn}` }); progress += Math.round(100/appDomains.length); - ensureCertificate(appDomain.fqdn, appDomain.domain, auditSource, function (error, bundle) { + ensureCertificate(appDomain.fqdn, appDomain.domain, auditSource, function (error, bundle, state) { if (error) return iteratorCallback(error); // this can happen if cloudron is not setup yet + if (state.renewed) renewed.push(appDomain.fqdn); + // hack to check if the app's cert changed or not. this doesn't handle prod/staging le change since they use same file name let currentNginxConfig = safe.fs.readFileSync(appDomain.nginxConfigFilename, 'utf8') || ''; if (currentNginxConfig.includes(bundle.certFilePath)) return iteratorCallback(); @@ -607,7 +610,15 @@ function renewCerts(options, auditSource, progressCallback, callback) { configureFunc(iteratorCallback); }); - }, callback); + }, function (error) { + if (error) return callback(error); + + debug(`renewCerts: Renewed certs of ${JSON.stringify(renewed)}`); + if (renewed.length === 0) return callback(null); + + // reload nginx if any certs were updated but the config was not rewritten + reload(callback); + }); }); }