From b4393ffc8c18226eb16bc16268f72e6a23f3fbd6 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe <erisds@gmail.com> Date: Sun, 26 May 2019 10:45:43 +0100 Subject: [PATCH] feat(nginx): customisable paths & program name no issue - Respect environment variables that customise where nginx lives and what it is called - Use env vars, not config, because this will be system-wide - Allows CLI to work with "flavours" of nginx, like OpenResty --- extensions/nginx/acme.js | 4 +- extensions/nginx/index.js | 45 ++++++++++++---------- lib/commands/doctor/checks/system-stack.js | 8 ++-- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/extensions/nginx/acme.js b/extensions/nginx/acme.js index 8c3bb0a14..b952dc17b 100644 --- a/extensions/nginx/acme.js +++ b/extensions/nginx/acme.js @@ -7,6 +7,8 @@ const download = require('download'); const {errors: {CliError, ProcessError, SystemError}} = require('../../lib'); +const nginxProgramName = process.env.NGINX_PROGRAM_NAME || 'nginx'; + function isInstalled() { return fs.existsSync('/etc/letsencrypt/acme.sh'); } @@ -67,7 +69,7 @@ function install(ui, task) { function generateCert(ui, domain, webroot, email, staging) { const cmd = `/etc/letsencrypt/acme.sh --issue --home /etc/letsencrypt --domain ${domain} --webroot ${webroot} ` + - `--reloadcmd "nginx -s reload" --accountemail ${email}${staging ? ' --staging' : ''}`; + `--reloadcmd "${nginxProgramName} -s reload" --accountemail ${email}${staging ? ' --staging' : ''}`; return ui.sudo(cmd).catch((error) => { if (error.code === 2) { diff --git a/extensions/nginx/index.js b/extensions/nginx/index.js index 30ec98c7b..dadc89e18 100644 --- a/extensions/nginx/index.js +++ b/extensions/nginx/index.js @@ -13,6 +13,9 @@ const template = require('lodash/template'); const {Extension, errors} = require('../../lib'); const {CliError, ProcessError} = errors; +const nginxConfigPath = process.env.NGINX_CONFIG_PATH || '/etc/nginx'; +const nginxProgramName = process.env.NGINX_PROGRAM_NAME || 'nginx'; + class NginxExtension extends Extension { migrations() { const migrations = require('./migrations'); @@ -47,7 +50,7 @@ class NginxExtension extends Extension { const confFile = `${hostname}.conf`; - if (fs.existsSync(`/etc/nginx/sites-available/${confFile}`)) { + if (fs.existsSync(`${nginxConfigPath}/sites-available/${confFile}`)) { return 'Nginx configuration already found for this url. Skipping Nginx setup.'; } @@ -74,7 +77,7 @@ class NginxExtension extends Extension { return 'SSL certs cannot be generated for IP addresses, skipping'; } - if (fs.existsSync(`/etc/nginx/sites-available/${confFile}`)) { + if (fs.existsSync(`${nginxConfigPath}/sites-available/${confFile}`)) { return 'SSL has already been set up, skipping'; } @@ -82,7 +85,7 @@ class NginxExtension extends Extension { return 'SSL email must be provided via the --sslemail option, skipping SSL setup'; } - if (!fs.existsSync(`/etc/nginx/sites-available/${hostname}.conf`)) { + if (!fs.existsSync(`${nginxConfigPath}/sites-available/${hostname}.conf`)) { return single ? 'Nginx config file does not exist, skipping SSL setup' : true; } @@ -105,8 +108,8 @@ class NginxExtension extends Extension { port: instance.config.get('server.port') }); - return this.template(instance, generatedConfig, 'nginx config', confFile, '/etc/nginx/sites-available').then( - () => this.ui.sudo(`ln -sf /etc/nginx/sites-available/${confFile} /etc/nginx/sites-enabled/${confFile}`) + return this.template(instance, generatedConfig, 'nginx config', confFile, `${nginxConfigPath}/sites-available`).then( + () => this.ui.sudo(`ln -sf ${nginxConfigPath}/sites-available/${confFile} ${nginxConfigPath}/sites-enabled/${confFile}`) ).then( () => this.restartNginx() ).catch((error) => { @@ -126,8 +129,8 @@ class NginxExtension extends Extension { const acme = require('./acme'); const rootPath = path.resolve(instance.dir, 'system', 'nginx-root'); - const dhparamFile = '/etc/nginx/snippets/dhparam.pem'; - const sslParamsFile = '/etc/nginx/snippets/ssl-params.conf'; + const dhparamFile = `${nginxConfigPath}/snippets/dhparam.pem`; + const sslParamsFile = `${nginxConfigPath}/snippets/ssl-params.conf`; const sslParamsConf = template(fs.readFileSync(path.join(__dirname, 'templates', 'ssl-params.conf'), 'utf8')); return this.ui.listr([{ @@ -210,8 +213,8 @@ class NginxExtension extends Extension { port: instance.config.get('server.port') }); - return this.template(instance, generatedSslConfig, 'ssl config', confFile, '/etc/nginx/sites-available').then( - () => this.ui.sudo(`ln -sf /etc/nginx/sites-available/${confFile} /etc/nginx/sites-enabled/${confFile}`) + return this.template(instance, generatedSslConfig, 'ssl config', confFile, `${nginxConfigPath}/sites-available`).then( + () => this.ui.sudo(`ln -sf ${nginxConfigPath}/sites-available/${confFile} ${nginxConfigPath}/sites-enabled/${confFile}`) ).catch(error => Promise.reject(new ProcessError(error))); } }, { @@ -233,29 +236,29 @@ class NginxExtension extends Extension { const promises = []; - if (fs.existsSync(`/etc/nginx/sites-available/${confFile}`)) { + if (fs.existsSync(`${nginxConfigPath}/sites-available/${confFile}`)) { // Nginx config exists, remove it promises.push( Promise.all([ - this.ui.sudo(`rm -f /etc/nginx/sites-available/${confFile}`), - this.ui.sudo(`rm -f /etc/nginx/sites-enabled/${confFile}`) + this.ui.sudo(`rm -f ${nginxConfigPath}/sites-available/${confFile}`), + this.ui.sudo(`rm -f ${nginxConfigPath}/sites-enabled/${confFile}`) ]).catch(error => Promise.reject(new CliError({ - message: `Nginx config file link could not be removed, you will need to do this manually for /etc/nginx/sites-available/${confFile}.`, - help: `Try running 'rm -f /etc/nginx/sites-available/${confFile} && rm -f /etc/nginx/sites-enabled/${confFile}'`, + message: `Nginx config file link could not be removed, you will need to do this manually for ${nginxConfigPath}/sites-available/${confFile}.`, + help: `Try running 'rm -f ${nginxConfigPath}/sites-available/${confFile} && rm -f ${nginxConfigPath}/sites-enabled/${confFile}'`, err: error }))) ); } - if (fs.existsSync(`/etc/nginx/sites-available/${sslConfFile}`)) { + if (fs.existsSync(`${nginxConfigPath}/sites-available/${sslConfFile}`)) { // SSL config exists, remove it promises.push( Promise.all([ - this.ui.sudo(`rm -f /etc/nginx/sites-available/${sslConfFile}`), - this.ui.sudo(`rm -f /etc/nginx/sites-enabled/${sslConfFile}`) + this.ui.sudo(`rm -f ${nginxConfigPath}/sites-available/${sslConfFile}`), + this.ui.sudo(`rm -f ${nginxConfigPath}/sites-enabled/${sslConfFile}`) ]).catch(error => Promise.reject(new CliError({ - message: `SSL config file link could not be removed, you will need to do this manually for /etc/nginx/sites-available/${sslConfFile}.`, - help: `Try running 'rm -f /etc/nginx/sites-available/${sslConfFile} && rm -f /etc/nginx/sites-enabled/${sslConfFile}'`, + message: `SSL config file link could not be removed, you will need to do this manually for ${nginxConfigPath}/sites-available/${sslConfFile}.`, + help: `Try running 'rm -f ${nginxConfigPath}/sites-available/${sslConfFile} && rm -f ${nginxConfigPath}/sites-enabled/${sslConfFile}'`, err: error }))) ); @@ -269,7 +272,7 @@ class NginxExtension extends Extension { } restartNginx() { - return this.ui.sudo('nginx -s reload') + return this.ui.sudo(`${nginxProgramName} -s reload`) .catch(error => Promise.reject(new CliError({ message: 'Failed to restart Nginx.', err: error @@ -278,7 +281,7 @@ class NginxExtension extends Extension { isSupported() { try { - execa.shellSync('dpkg -l | grep nginx', {stdio: 'ignore'}); + execa.shellSync(`dpkg -l | grep ${nginxProgramName}`, {stdio: 'ignore'}); return true; } catch (e) { return false; diff --git a/lib/commands/doctor/checks/system-stack.js b/lib/commands/doctor/checks/system-stack.js index b06b1f7d6..70b75f9b9 100644 --- a/lib/commands/doctor/checks/system-stack.js +++ b/lib/commands/doctor/checks/system-stack.js @@ -6,6 +6,8 @@ const errors = require('../../../errors'); const taskTitle = 'Checking operating system compatibility'; +const nginxProgramName = process.env.NGINX_PROGRAM_NAME || 'nginx'; + function systemStack(ctx, task) { let promise; @@ -25,9 +27,9 @@ function systemStack(ctx, task) { task: () => execa.shell('dpkg -l | grep systemd') .catch(() => Promise.reject({missing: 'systemd'})) }, { - title: 'Checking nginx is installed', - task: () => execa.shell('dpkg -l | grep nginx') - .catch(() => Promise.reject({missing: 'nginx'})) + title: `Checking ${nginxProgramName} is installed`, + task: () => execa.shell(`dpkg -l | grep ${nginxProgramName}`) + .catch(() => Promise.reject({missing: nginxProgramName})) }], ctx, { concurrent: true, exitOnError: false,