From df26e5ec9977cc32a964f280454a1f98b3392eb6 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Tue, 15 Sep 2020 14:08:22 +0200 Subject: [PATCH 01/12] - WIP: fixing LE on install / update --- install/lib/installer_base.lib.php | 55 ++++++++++++++++++++++++---- install/tpl/apache_acme.vhost.master | 18 +++++++++ install/tpl/nginx_acme.vhost.master | 25 +++++++++++++ 3 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 install/tpl/apache_acme.vhost.master create mode 100644 install/tpl/nginx_acme.vhost.master diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index e262f31fa5..5c2d78c8c8 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2720,6 +2720,42 @@ class installer_base { return $response; } + private function make_acme_vhost($server_name, $server = 'apache') { + global $conf; + + $use_template = 'apache_acme.vhost.master'; + if($server === 'nginx') { + $use_template = 'nginx_acme.vhost.master'; + } + + $vhost_conf_dir = $conf[$server]['vhost_conf_dir']; + $vhost_conf_enabled_dir = $conf[$server]['vhost_conf_enabled_dir']; + + $tpl = new tpl($use_template); + $tpl->setVar('domain', $server_name); + + if($server !== 'nginx') { + $tpl->setVar('apache_version',getapacheversion()); + } + + wf($vhost_conf_dir.'/acme.vhost', $tpl->grab()); + + if(@is_link($vhost_conf_enabled_dir.'/999-acme.vhost')) { + unlink($vhost_conf_enabled_dir.'/999-acme.vhost'); + } + if(!@is_link($vhost_conf_enabled_dir.'/999-acme.vhost')) { + symlink($vhost_conf_dir.'/acme.vhost', $vhost_conf_enabled_dir.'/999-acme.vhost'); + } + + if($conf[$server]['installed'] == true && $conf[$server]['init_script'] != '') { + if($this->is_update) { + system($this->getinitcommand($conf[$server]['init_script'], 'force-reload').' &> /dev/null || ' . $this->getinitcommand($conf[$server]['init_script'], 'restart').' &> /dev/null'); + } else { + system($this->getinitcommand($conf[$server]['init_script'], 'restart').' &> /dev/null'); + } + } + } + public function make_ispconfig_ssl_cert() { global $conf, $autoinstall; @@ -2802,13 +2838,18 @@ class installer_base { $acme = explode("\n", shell_exec('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh')); $acme = reset($acme); + // first of all create the acme vhosts if not existing + if($conf['nginx']['installed'] == true) { + $this->make_acme_vhost($hostname, 'nginx'); + } elseif($conf['apache']['installed'] == true) { + $this->make_acme_vhost($hostname, 'apache'); + } + // Attempt to use Neilpang acme.sh first, as it is now the preferred LE client if (is_executable($acme)) { - if($conf['nginx']['installed'] == true) { - exec("$acme --issue --nginx -d $hostname $renew_hook"); - } elseif($conf['apache']['installed'] == true) { - exec("$acme --issue --apache -d $hostname $renew_hook"); + if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) { + exec("$acme --issue -w /usr/local/ispconfig/interface/acme -d $hostname $renew_hook"); } // Else, it is not webserver, so we use standalone else { @@ -2840,10 +2881,8 @@ class installer_base { $certonly = 'certonly --agree-tos --non-interactive --expand --rsa-key-size 4096'; // If this is a webserver - if($conf['nginx']['installed'] == true) - exec("$le_client $certonly $acme_version --nginx --email postmaster@$hostname -d $hostname $renew_hook"); - elseif($conf['apache']['installed'] == true) - exec("$le_client $certonly $acme_version --apache --email postmaster@$hostname -d $hostname $renew_hook"); + if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) + exec("$le_client $certonly $acme_version --authenticator webroot --webroot-path /usr/local/ispconfig/interface/acme --email postmaster@$hostname -d $hostname $renew_hook"); // Else, it is not webserver, so we use standalone else exec("$le_client $certonly $acme_version --standalone --email postmaster@$hostname -d $hostname $hook"); diff --git a/install/tpl/apache_acme.vhost.master b/install/tpl/apache_acme.vhost.master new file mode 100644 index 0000000000..59ece91c00 --- /dev/null +++ b/install/tpl/apache_acme.vhost.master @@ -0,0 +1,18 @@ + + + ServerName + + DocumentRoot /usr/local/ispconfig/interface/acme + + + AllowOverride None + + Require all granted + + Order allow,deny + Allow from all + + + + + diff --git a/install/tpl/nginx_acme.vhost.master b/install/tpl/nginx_acme.vhost.master new file mode 100644 index 0000000000..d7c576b04d --- /dev/null +++ b/install/tpl/nginx_acme.vhost.master @@ -0,0 +1,25 @@ +server { + listen 80; + listen [::]:80; + + server_name ; + + root /usr/local/ispconfig/interface/acme; + + autoindex off; + index index.html; + + ## Disable .htaccess and other hidden files + location ~ / { + deny all; + } + + ## Allow access for .well-known/acme-challenge + location ^~ /.well-known/acme-challenge/ { + access_log off; + log_not_found off; + auth_basic off; + root /usr/local/ispconfig/interface/acme/; + try_files $uri $uri/ =404; + } +} \ No newline at end of file -- GitLab From 7d3b76a0b5f053ee112e67b13458d7f67490caf8 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Tue, 15 Sep 2020 14:49:48 +0200 Subject: [PATCH 02/12] - fixed issues with acme path --- install/lib/installer_base.lib.php | 8 ++++++++ server/scripts/letsencrypt_renew_hook.sh | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 5c2d78c8c8..371b476f34 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2738,6 +2738,14 @@ class installer_base { $tpl->setVar('apache_version',getapacheversion()); } + $acme_dir = $conf['ispconfig_install_dir'] . '/interface/acme'; + + //* Create the ISPConfig installation directory + if(!@is_dir($acme_dir)) { + $command = "mkdir -p $acme_dir"; + caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); + } + wf($vhost_conf_dir.'/acme.vhost', $tpl->grab()); if(@is_link($vhost_conf_enabled_dir.'/999-acme.vhost')) { diff --git a/server/scripts/letsencrypt_renew_hook.sh b/server/scripts/letsencrypt_renew_hook.sh index 0a71f30d01..9f3283587a 100644 --- a/server/scripts/letsencrypt_renew_hook.sh +++ b/server/scripts/letsencrypt_renew_hook.sh @@ -42,6 +42,5 @@ lelive=/etc/letsencrypt/live/$(hostname -f); if [ -d "$lelive" ]; then if [ $(dpkg-query -W -f='${Status}' mariadb 2>/dev/null | grep -c "ok installed") -eq 1 ]; then service mysql restart; fi if [ $(dpkg-query -W -f='${Status}' nginx 2>/dev/null | grep -c "ok installed") -eq 1 ]; then service nginx restart; fi if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ]; then service apache2 restart; fi - else fi else echo `/bin/date` "Your Lets Encrypt SSL certs path for your ISPConfig server FQDN is missing.$line" >> /var/log/ispconfig/ispconfig.log; fi \ No newline at end of file -- GitLab From 1392353a9f6fc200c418ceb3d57a22a2bacfb52d Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Tue, 15 Sep 2020 14:59:28 +0200 Subject: [PATCH 03/12] - move apps vhost behind cert generation --- install/install.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/install/install.php b/install/install.php index 496ab3fdce..294298653a 100644 --- a/install/install.php +++ b/install/install.php @@ -536,12 +536,6 @@ if($force) { $inst->configure_fail2ban(); } -if($conf['services']['web'] == true) { - //** Configure apps vhost - swriteln('Configuring Apps vhost'); - $inst->configure_apps_vhost(); -} - //** Configure ISPConfig :-) $install_ispconfig_interface_default = ($conf['mysql']['master_slave_setup'] == 'y')?'n':'y'; if($install_mode == 'standard' || strtolower($inst->simple_query('Install ISPConfig Web Interface', array('y', 'n'), $install_ispconfig_interface_default,'install_ispconfig_web_interface')) == 'y') { @@ -582,6 +576,12 @@ if(!file_exists('/usr/local/ispconfig/interface/ssl/ispserver.crt')) { $inst->make_ispconfig_ssl_cert(); } +if($conf['services']['web'] == true) { + //** Configure apps vhost + swriteln('Configuring Apps vhost'); + $inst->configure_apps_vhost(); +} + $inst->install_ispconfig(); //* Configure DBServer -- GitLab From 9e9e0802acf7c11aecda74544071bfb550bb57fe Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Tue, 15 Sep 2020 15:11:56 +0200 Subject: [PATCH 04/12] - remove and restore symlink in apache --- install/lib/installer_base.lib.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 371b476f34..a4e7b4b6d8 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2846,10 +2846,21 @@ class installer_base { $acme = explode("\n", shell_exec('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh')); $acme = reset($acme); + $restore_conf_symlink = false; + + // we only need this for apache, so use fixed conf index + $vhost_conf_dir = $conf['apache']['vhost_conf_dir']; + $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir']; + // first of all create the acme vhosts if not existing if($conf['nginx']['installed'] == true) { $this->make_acme_vhost($hostname, 'nginx'); } elseif($conf['apache']['installed'] == true) { + if($this->is_update == false && @is_link($vhost_conf_enabled_dir.'/000-ispconfig.conf')) { + $restore_conf_symlink = true; + unlink($vhost_conf_enabled_dir.'/000-ispconfig.conf'); + } + $this->make_acme_vhost($hostname, 'apache'); } @@ -2896,6 +2907,12 @@ class installer_base { exec("$le_client $certonly $acme_version --standalone --email postmaster@$hostname -d $hostname $hook"); } } + + if($restore_conf_symlink) { + if(!@is_link($vhost_conf_enabled_dir.'/000-ispconfig.conf')) { + symlink($vhost_conf_dir.'/ispconfig.conf', $vhost_conf_enabled_dir.'/000-ispconfig.conf'); + } + } } //* Define and check ISPConfig SSL folder */ -- GitLab From 18105979177272365fc83cdeef28271e9035d5ae Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Tue, 15 Sep 2020 15:24:20 +0200 Subject: [PATCH 05/12] - move apache vhost to conf file instead --- install/lib/installer_base.lib.php | 16 ++++++++++------ ...acme.vhost.master => apache_acme.conf.master} | 9 +-------- 2 files changed, 11 insertions(+), 14 deletions(-) rename install/tpl/{apache_acme.vhost.master => apache_acme.conf.master} (65%) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index a4e7b4b6d8..0af5104d06 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2723,9 +2723,13 @@ class installer_base { private function make_acme_vhost($server_name, $server = 'apache') { global $conf; - $use_template = 'apache_acme.vhost.master'; + $use_template = 'apache_acme.conf.master'; + $use_symlink = '999-acme.conf'; + $use_name = 'acme.conf'; if($server === 'nginx') { $use_template = 'nginx_acme.vhost.master'; + $use_symlink = '999-acme.vhost'; + $use_name = 'acme.vhost'; } $vhost_conf_dir = $conf[$server]['vhost_conf_dir']; @@ -2746,13 +2750,13 @@ class installer_base { caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command"); } - wf($vhost_conf_dir.'/acme.vhost', $tpl->grab()); + wf($vhost_conf_dir.'/' . $use_name, $tpl->grab()); - if(@is_link($vhost_conf_enabled_dir.'/999-acme.vhost')) { - unlink($vhost_conf_enabled_dir.'/999-acme.vhost'); + if(@is_link($vhost_conf_enabled_dir.'/' . $use_symlink)) { + unlink($vhost_conf_enabled_dir.'/' . $use_symlink); } - if(!@is_link($vhost_conf_enabled_dir.'/999-acme.vhost')) { - symlink($vhost_conf_dir.'/acme.vhost', $vhost_conf_enabled_dir.'/999-acme.vhost'); + if(!@is_link($vhost_conf_enabled_dir.'' . $use_symlink)) { + symlink($vhost_conf_dir.'/' . $use_name, $vhost_conf_enabled_dir.'/' . $use_symlink); } if($conf[$server]['installed'] == true && $conf[$server]['init_script'] != '') { diff --git a/install/tpl/apache_acme.vhost.master b/install/tpl/apache_acme.conf.master similarity index 65% rename from install/tpl/apache_acme.vhost.master rename to install/tpl/apache_acme.conf.master index 59ece91c00..4a16294335 100644 --- a/install/tpl/apache_acme.vhost.master +++ b/install/tpl/apache_acme.conf.master @@ -1,8 +1,4 @@ - - - ServerName - - DocumentRoot /usr/local/ispconfig/interface/acme + Alias /.well-known/acme-challenge /usr/local/ispconfig/interface/acme/.well-known/acme-challenge AllowOverride None @@ -13,6 +9,3 @@ Allow from all - - - -- GitLab From 9a3bd79d71d750422adfe02e61816aab53f27e6c Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 13:29:46 +0200 Subject: [PATCH 06/12] - add error handling and do not use certbot cert dir on acme.sh --- install/lib/installer_base.lib.php | 109 +++++++++++++++-------- server/scripts/letsencrypt_post_hook.sh | 2 +- server/scripts/letsencrypt_pre_hook.sh | 2 +- server/scripts/letsencrypt_renew_hook.sh | 14 ++- 4 files changed, 85 insertions(+), 42 deletions(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 0af5104d06..0de0a73f53 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2807,8 +2807,27 @@ class installer_base { } } + //* Define and check ISPConfig SSL folder */ + $ssl_dir = $conf['ispconfig_install_dir'].'/interface/ssl'; + if(!@is_dir($ssl_dir)) { + mkdir($ssl_dir, 0755, true); + } + + $ssl_crt_file = $ssl_dir.'/ispserver.crt'; + $ssl_csr_file = $ssl_dir.'/ispserver.csr'; + $ssl_key_file = $ssl_dir.'/ispserver.key'; + $ssl_pem_file = $ssl_dir.'/ispserver.pem'; + + $date = new DateTime(); + // Request for certs if no LE SSL folder for server fqdn exist - $le_live_dir = '/etc/letsencrypt/live/' . $hostname; + $le_live_dir = '/usr/local/ispconfig/server/scripts/' . $hostname; + if(!@is_dir($le_live_dir)) { + $le_live_dir = '/root/.acme.sh/' . $hostname; + if(!@is_dir($le_live_dir)) { + $le_live_dir = '/etc/letsencrypt/live/' . $hostname; + } + } if (!@is_dir($le_live_dir) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { // This script is needed earlier to check and open http port 80 or standalone might fail @@ -2868,30 +2887,47 @@ class installer_base { $this->make_acme_vhost($hostname, 'apache'); } + $issued_successfully = false; + // Attempt to use Neilpang acme.sh first, as it is now the preferred LE client if (is_executable($acme)) { + $out = null; + $ret = null; if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) { - exec("$acme --issue -w /usr/local/ispconfig/interface/acme -d $hostname $renew_hook"); + exec("$acme --issue -w /usr/local/ispconfig/interface/acme -d $hostname $renew_hook", $out, $ret); } // Else, it is not webserver, so we use standalone else { - exec("$acme --issue --standalone -d $hostname $hook"); + exec("$acme --issue --standalone -d " . escapeshellarg($hostname) . " $hook", $out, $ret); } - // Define LE certs name and path, then install them - if (!@is_dir($le_live_dir)) mkdir($le_live_dir, 0755, true); - $acme_cert = "--cert-file $le_live_dir/cert.pem"; - $acme_key = "--key-file $le_live_dir/privkey.pem"; - $acme_ca = "--ca-file $le_live_dir/chain.pem"; - $acme_chain = "--fullchain-file $le_live_dir/fullchain.pem"; - exec("$acme --install-cert -d $hostname $acme_cert $acme_key $acme_ca $acme_chain"); + if($ret == 0) { + // Backup existing ispserver ssl files + if(file_exists($ssl_crt_file)) { + rename($ssl_crt_file, $ssl_crt_file . '-' . $date->format('YmdHis') . '.bak'); + } + if(file_exists($ssl_key_file)) { + rename($ssl_key_file, $ssl_key_file . '-' . $date->format('YmdHis') . '.bak'); + } + if(file_exists($ssl_pem_file)) { + rename($ssl_pem_file, $ssl_pem_file . '-' . $date->format('YmdHis') . '.bak'); + } + // Define LE certs name and path, then install them + //$acme_cert = "--cert-file $le_live_dir/cert.pem"; + $acme_key = "--key-file " . escapeshellarg($ssl_key_file); + $acme_chain = "--fullchain-file " . escapeshellarg($ssl_crt_file); + exec("$acme --install-cert -d $hostname $acme_key $acme_chain"); + $issued_successfully = true; + } // Else, we attempt to use the official LE certbot client certbot } else { // But only if it is otherwise available if(is_executable($le_client)) { + $out = null; + $ret = null; // Get its version info due to be used for webroot arguement issues $le_info = exec($le_client . ' --version 2>&1', $ret, $val); @@ -2904,11 +2940,28 @@ class installer_base { $certonly = 'certonly --agree-tos --non-interactive --expand --rsa-key-size 4096'; // If this is a webserver - if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) - exec("$le_client $certonly $acme_version --authenticator webroot --webroot-path /usr/local/ispconfig/interface/acme --email postmaster@$hostname -d $hostname $renew_hook"); + if($conf['nginx']['installed'] == true || $conf['apache']['installed'] == true) { + exec("$le_client $certonly $acme_version --authenticator webroot --webroot-path /usr/local/ispconfig/interface/acme --email " . escapeshellarg('postmaster@$hostname') . " -d " . escapeshellarg($hostname) . " $renew_hook", $out, $ret); + } // Else, it is not webserver, so we use standalone - else - exec("$le_client $certonly $acme_version --standalone --email postmaster@$hostname -d $hostname $hook"); + else { + exec("$le_client $certonly $acme_version --standalone --email " . escapeshellarg('postmaster@$hostname') . " -d " . escapeshellarg($hostname) . " $hook", $out, $ret); + } + + if($ret == 0) { + // Backup existing ispserver ssl files + if(file_exists($ssl_crt_file)) { + rename($ssl_crt_file, $ssl_crt_file . '-' . $date->format('YmdHis') . '.bak'); + } + if(file_exists($ssl_key_file)) { + rename($ssl_key_file, $ssl_key_file . '-' . $date->format('YmdHis') . '.bak'); + } + if(file_exists($ssl_pem_file)) { + rename($ssl_pem_file, $ssl_pem_file . '-' . $date->format('YmdHis') . '.bak'); + } + + $issued_successfully = true; + } } } @@ -2917,33 +2970,13 @@ class installer_base { symlink($vhost_conf_dir.'/ispconfig.conf', $vhost_conf_enabled_dir.'/000-ispconfig.conf'); } } + } elseif(($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips))) { + // the directory already exists so we have to assume that it was created previously + $issued_successfully = true; } - //* Define and check ISPConfig SSL folder */ - $ssl_dir = $conf['ispconfig_install_dir'].'/interface/ssl'; - if(!@is_dir($ssl_dir)) mkdir($ssl_dir, 0755, true); - - $ssl_crt_file = $ssl_dir.'/ispserver.crt'; - $ssl_csr_file = $ssl_dir.'/ispserver.csr'; - $ssl_key_file = $ssl_dir.'/ispserver.key'; - $ssl_pem_file = $ssl_dir.'/ispserver.pem'; - - $date = new DateTime(); - // If the LE SSL certs for this hostname exists - if (is_dir($le_live_dir) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { - - // Backup existing ispserver ssl files - if (file_exists($ssl_crt_file)) rename($ssl_crt_file, $ssl_crt_file . '-' .$date->format('YmdHis') . '.bak'); - if (file_exists($ssl_key_file)) rename($ssl_key_file, $ssl_key_file . '-' .$date->format('YmdHis') . '.bak'); - if (file_exists($ssl_pem_file)) rename($ssl_pem_file, $ssl_pem_file . '-' .$date->format('YmdHis') . '.bak'); - - // Create symlink to LE fullchain and key for ISPConfig - symlink($le_live_dir.'/fullchain.pem', $ssl_crt_file); - symlink($le_live_dir.'/privkey.pem', $ssl_key_file); - - } else { - + if(!is_dir($le_live_dir) || !$issued_successfully) { // We can still use the old self-signed method $ssl_pw = substr(md5(mt_rand()), 0, 6); exec("openssl genrsa -des3 -passout pass:$ssl_pw -out $ssl_key_file 4096"); diff --git a/server/scripts/letsencrypt_post_hook.sh b/server/scripts/letsencrypt_post_hook.sh index 02653f79a1..27d593196c 100644 --- a/server/scripts/letsencrypt_post_hook.sh +++ b/server/scripts/letsencrypt_post_hook.sh @@ -12,7 +12,7 @@ ## If you need a custom hook file, create a file with the same name in ## /usr/local/ispconfig/server/conf-custom/scripts/ -if [[ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_post_hook.sh" ]] ; then +if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_post_hook.sh" ] ; then . /usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_post_hook.sh && exit 0 || exit 1; fi diff --git a/server/scripts/letsencrypt_pre_hook.sh b/server/scripts/letsencrypt_pre_hook.sh index 56f246e803..60964a86d4 100644 --- a/server/scripts/letsencrypt_pre_hook.sh +++ b/server/scripts/letsencrypt_pre_hook.sh @@ -12,7 +12,7 @@ ## If you need a custom hook file, create a file with the same name in ## /usr/local/ispconfig/server/conf-custom/scripts/ -if [[ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_pre_hook.sh" ]] ; then +if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_pre_hook.sh" ] ; then . /usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_pre_hook.sh && exit 0 || exit 1 ; fi diff --git a/server/scripts/letsencrypt_renew_hook.sh b/server/scripts/letsencrypt_renew_hook.sh index 9f3283587a..df5c056b4f 100644 --- a/server/scripts/letsencrypt_renew_hook.sh +++ b/server/scripts/letsencrypt_renew_hook.sh @@ -12,11 +12,21 @@ ## If you need a custom hook file, create a file with the same name in ## /usr/local/ispconfig/server/conf-custom/scripts/ -if [[ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook.sh" ]] ; then +if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook.sh" ] ; then . /usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook.sh && exit 0 || exit 1; fi -lelive=/etc/letsencrypt/live/$(hostname -f); if [ -d "$lelive" ]; then +hostname=$(hostname -f) +acme=$(which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh) +if [ -e "/usr/local/ispconfig/server/scripts/${hostname}" ] ; then + lelive="/usr/local/ispconfig/server/scripts/${hostname}" ; +elif [ -e "/root/.acme.sh/${hostname}" ] ; then + lelive="/root/.acme.sh/${hostname}" ; +else + lelive="/etc/letsencrypt/live/${hostname}" ; +fi + +if [ -d "$lelive" ]; then cd /usr/local/ispconfig/interface/ssl; ibak=ispserver.*.bak; ipem=ispserver.pem; icrt=ispserver.crt; ikey=ispserver.key if ls $ibak 1> /dev/null 2>&1; then rm $ibak; fi if [ -e "$ipem" ]; then mv $ipem $ipem-$(date +"%y%m%d%H%M%S").bak; cat $ikey $icrt > $ipem; chmod 600 $ipem; fi -- GitLab From a0bdeff2cc0e7748c219526fc06487f0f12bd702 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 13:45:57 +0200 Subject: [PATCH 07/12] - further error handling for acme files --- install/lib/installer_base.lib.php | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 0de0a73f53..6835fa5331 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2821,24 +2821,28 @@ class installer_base { $date = new DateTime(); // Request for certs if no LE SSL folder for server fqdn exist - $le_live_dir = '/usr/local/ispconfig/server/scripts/' . $hostname; - if(!@is_dir($le_live_dir)) { - $le_live_dir = '/root/.acme.sh/' . $hostname; - if(!@is_dir($le_live_dir)) { - $le_live_dir = '/etc/letsencrypt/live/' . $hostname; + + $acme_cert_dir = '/usr/local/ispconfig/server/scripts/' . $hostname; + $check_acme_file = $acme_cert_dir . '/' . $hostname . '.cer'; + if(!@is_dir($acme_cert_dir)) { + $acme_cert_dir = '/root/.acme.sh/' . $hostname; + $check_acme_file = $acme_cert_dir . '/' . $hostname . '.cer'; + if(!@is_dir($acme_cert_dir)) { + $acme_cert_dir = '/etc/letsencrypt/live/' . $hostname; + $check_acme_file = $acme_cert_dir . '/cert.pem'; } } - if (!@is_dir($le_live_dir) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { + if ((!@is_dir($acme_cert_dir) || !@file_exists($check_acme_file)) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { // This script is needed earlier to check and open http port 80 or standalone might fail // Make executable and temporary symlink latest letsencrypt pre, post and renew hook script before install - if(file_exists(dirname(getcwd()) . '/server/scripts/letsencrypt_pre_hook.sh')) { + if(file_exists(dirname(getcwd()) . '/server/scripts/letsencrypt_pre_hook.sh') && !file_exists('/usr/local/bin/letsencrypt_pre_hook.sh')) { symlink(dirname(getcwd()) . '/server/scripts/letsencrypt_pre_hook.sh', '/usr/local/bin/letsencrypt_pre_hook.sh'); } - if(file_exists(dirname(getcwd()) . '/server/scripts/letsencrypt_post_hook.sh')) { + if(file_exists(dirname(getcwd()) . '/server/scripts/letsencrypt_post_hook.sh') && !file_exists('/usr/local/bin/letsencrypt_post_hook.sh')) { symlink(dirname(getcwd()) . '/server/scripts/letsencrypt_post_hook.sh', '/usr/local/bin/letsencrypt_post_hook.sh'); } - if(file_exists(dirname(getcwd()) . '/server/scripts/letsencrypt_renew_hook.sh')) { + if(file_exists(dirname(getcwd()) . '/server/scripts/letsencrypt_renew_hook.sh') && !file_exists('/usr/local/bin/letsencrypt_renew_hook.sh')) { symlink(dirname(getcwd()) . '/server/scripts/letsencrypt_renew_hook.sh', '/usr/local/bin/letsencrypt_renew_hook.sh'); } chown('/usr/local/bin/letsencrypt_pre_hook.sh', 'root'); @@ -2915,7 +2919,7 @@ class installer_base { } // Define LE certs name and path, then install them - //$acme_cert = "--cert-file $le_live_dir/cert.pem"; + //$acme_cert = "--cert-file $acme_cert_dir/cert.pem"; $acme_key = "--key-file " . escapeshellarg($ssl_key_file); $acme_chain = "--fullchain-file " . escapeshellarg($ssl_crt_file); exec("$acme --install-cert -d $hostname $acme_key $acme_chain"); @@ -2976,7 +2980,7 @@ class installer_base { } // If the LE SSL certs for this hostname exists - if(!is_dir($le_live_dir) || !$issued_successfully) { + if(!is_dir($acme_cert_dir) || !file_exists($check_acme_file) || !$issued_successfully) { // We can still use the old self-signed method $ssl_pw = substr(md5(mt_rand()), 0, 6); exec("openssl genrsa -des3 -passout pass:$ssl_pw -out $ssl_key_file 4096"); -- GitLab From b56460ce46f0cb30f477ba4e551e4faffeae67e6 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 13:56:51 +0200 Subject: [PATCH 08/12] - also rename broken symlink of interface ssl --- install/lib/installer_base.lib.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 6835fa5331..5d043ba00f 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2908,13 +2908,13 @@ class installer_base { if($ret == 0) { // Backup existing ispserver ssl files - if(file_exists($ssl_crt_file)) { + if(file_exists($ssl_crt_file) || is_link($ssl_crt_file)) { rename($ssl_crt_file, $ssl_crt_file . '-' . $date->format('YmdHis') . '.bak'); } - if(file_exists($ssl_key_file)) { + if(file_exists($ssl_key_file) || is_link($ssl_key_file)) { rename($ssl_key_file, $ssl_key_file . '-' . $date->format('YmdHis') . '.bak'); } - if(file_exists($ssl_pem_file)) { + if(file_exists($ssl_pem_file) || is_link($ssl_pem_file)) { rename($ssl_pem_file, $ssl_pem_file . '-' . $date->format('YmdHis') . '.bak'); } @@ -2954,13 +2954,13 @@ class installer_base { if($ret == 0) { // Backup existing ispserver ssl files - if(file_exists($ssl_crt_file)) { + if(file_exists($ssl_crt_file) || is_link($ssl_crt_file)) { rename($ssl_crt_file, $ssl_crt_file . '-' . $date->format('YmdHis') . '.bak'); } - if(file_exists($ssl_key_file)) { + if(file_exists($ssl_key_file) || is_link($ssl_key_file)) { rename($ssl_key_file, $ssl_key_file . '-' . $date->format('YmdHis') . '.bak'); } - if(file_exists($ssl_pem_file)) { + if(file_exists($ssl_pem_file) || is_link($ssl_pem_file)) { rename($ssl_pem_file, $ssl_pem_file . '-' . $date->format('YmdHis') . '.bak'); } -- GitLab From 9dc6b899e21d88a748175d74f63e5f1f78c96eff Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 13:59:15 +0200 Subject: [PATCH 09/12] - also re-issue if interface ssl is not yet existing --- install/lib/installer_base.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 5d043ba00f..6da7adeb9a 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2832,7 +2832,7 @@ class installer_base { $check_acme_file = $acme_cert_dir . '/cert.pem'; } } - if ((!@is_dir($acme_cert_dir) || !@file_exists($check_acme_file)) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { + if ((!@is_dir($acme_cert_dir) || !@file_exists($check_acme_file)) || !@file_exists($ssl_crt_file)) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { // This script is needed earlier to check and open http port 80 or standalone might fail // Make executable and temporary symlink latest letsencrypt pre, post and renew hook script before install -- GitLab From 3c57871361ffebb3d12a353a7abbc0119a9f3f94 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 13:59:58 +0200 Subject: [PATCH 10/12] - fixed typo --- install/lib/installer_base.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index 6da7adeb9a..c41af69a92 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2832,7 +2832,7 @@ class installer_base { $check_acme_file = $acme_cert_dir . '/cert.pem'; } } - if ((!@is_dir($acme_cert_dir) || !@file_exists($check_acme_file)) || !@file_exists($ssl_crt_file)) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { + if ((!@is_dir($acme_cert_dir) || !@file_exists($check_acme_file) || !@file_exists($ssl_crt_file)) && (($svr_ip4 && in_array($svr_ip4, $dns_ips)) || ($svr_ip6 && in_array($svr_ip6, $dns_ips)))) { // This script is needed earlier to check and open http port 80 or standalone might fail // Make executable and temporary symlink latest letsencrypt pre, post and renew hook script before install -- GitLab From 225260fcf89195fd2650875eab82a290d0d713e4 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 14:05:28 +0200 Subject: [PATCH 11/12] - allow return code 2 for acme --- install/lib/installer_base.lib.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php index c41af69a92..d9eb7aec02 100644 --- a/install/lib/installer_base.lib.php +++ b/install/lib/installer_base.lib.php @@ -2906,7 +2906,9 @@ class installer_base { exec("$acme --issue --standalone -d " . escapeshellarg($hostname) . " $hook", $out, $ret); } - if($ret == 0) { + if($ret == 0 || ($ret == 2 && file_exists($check_acme_file))) { + // acme.sh returns with 2 on issue for already existing certificate + // Backup existing ispserver ssl files if(file_exists($ssl_crt_file) || is_link($ssl_crt_file)) { rename($ssl_crt_file, $ssl_crt_file . '-' . $date->format('YmdHis') . '.bak'); @@ -2953,6 +2955,8 @@ class installer_base { } if($ret == 0) { + // certbot returns with 0 on issue for already existing certificate + // Backup existing ispserver ssl files if(file_exists($ssl_crt_file) || is_link($ssl_crt_file)) { rename($ssl_crt_file, $ssl_crt_file . '-' . $date->format('YmdHis') . '.bak'); -- GitLab From c4e1637464c407c8088460cf5745d4b21da6d403 Mon Sep 17 00:00:00 2001 From: Marius Burkard Date: Wed, 16 Sep 2020 14:07:52 +0200 Subject: [PATCH 12/12] - removed unneeded line from hook file --- server/scripts/letsencrypt_renew_hook.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/scripts/letsencrypt_renew_hook.sh b/server/scripts/letsencrypt_renew_hook.sh index df5c056b4f..53fc31befd 100644 --- a/server/scripts/letsencrypt_renew_hook.sh +++ b/server/scripts/letsencrypt_renew_hook.sh @@ -17,10 +17,9 @@ if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook. fi hostname=$(hostname -f) -acme=$(which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh) -if [ -e "/usr/local/ispconfig/server/scripts/${hostname}" ] ; then +if [ -d "/usr/local/ispconfig/server/scripts/${hostname}" ] ; then lelive="/usr/local/ispconfig/server/scripts/${hostname}" ; -elif [ -e "/root/.acme.sh/${hostname}" ] ; then +elif [ -d "/root/.acme.sh/${hostname}" ] ; then lelive="/root/.acme.sh/${hostname}" ; else lelive="/etc/letsencrypt/live/${hostname}" ; -- GitLab