@@ -2720,6 +2720,54 @@ private function curl_request($url, $use_ipv6 = false) {
27202720 return $ response ;
27212721 }
27222722
2723+ private function make_acme_vhost ($ server_name , $ server = 'apache ' ) {
2724+ global $ conf ;
2725+
2726+ $ use_template = 'apache_acme.conf.master ' ;
2727+ $ use_symlink = '999-acme.conf ' ;
2728+ $ use_name = 'acme.conf ' ;
2729+ if ($ server === 'nginx ' ) {
2730+ $ use_template = 'nginx_acme.vhost.master ' ;
2731+ $ use_symlink = '999-acme.vhost ' ;
2732+ $ use_name = 'acme.vhost ' ;
2733+ }
2734+
2735+ $ vhost_conf_dir = $ conf [$ server ]['vhost_conf_dir ' ];
2736+ $ vhost_conf_enabled_dir = $ conf [$ server ]['vhost_conf_enabled_dir ' ];
2737+
2738+ $ tpl = new tpl ($ use_template );
2739+ $ tpl ->setVar ('domain ' , $ server_name );
2740+
2741+ if ($ server !== 'nginx ' ) {
2742+ $ tpl ->setVar ('apache_version ' ,getapacheversion ());
2743+ }
2744+
2745+ $ acme_dir = $ conf ['ispconfig_install_dir ' ] . '/interface/acme ' ;
2746+
2747+ //* Create the ISPConfig installation directory
2748+ if (!@is_dir ($ acme_dir )) {
2749+ $ command = "mkdir -p $ acme_dir " ;
2750+ caselog ($ command .' &> /dev/null ' , __FILE__ , __LINE__ , "EXECUTED: $ command " , "Failed to execute the command $ command " );
2751+ }
2752+
2753+ wf ($ vhost_conf_dir .'/ ' . $ use_name , $ tpl ->grab ());
2754+
2755+ if (@is_link ($ vhost_conf_enabled_dir .'/ ' . $ use_symlink )) {
2756+ unlink ($ vhost_conf_enabled_dir .'/ ' . $ use_symlink );
2757+ }
2758+ if (!@is_link ($ vhost_conf_enabled_dir .'' . $ use_symlink )) {
2759+ symlink ($ vhost_conf_dir .'/ ' . $ use_name , $ vhost_conf_enabled_dir .'/ ' . $ use_symlink );
2760+ }
2761+
2762+ if ($ conf [$ server ]['installed ' ] == true && $ conf [$ server ]['init_script ' ] != '' ) {
2763+ if ($ this ->is_update ) {
2764+ system ($ this ->getinitcommand ($ conf [$ server ]['init_script ' ], 'force-reload ' ).' &> /dev/null || ' . $ this ->getinitcommand ($ conf [$ server ]['init_script ' ], 'restart ' ).' &> /dev/null ' );
2765+ } else {
2766+ system ($ this ->getinitcommand ($ conf [$ server ]['init_script ' ], 'restart ' ).' &> /dev/null ' );
2767+ }
2768+ }
2769+ }
2770+
27232771 public function make_ispconfig_ssl_cert () {
27242772 global $ conf , $ autoinstall ;
27252773
@@ -2759,19 +2807,42 @@ public function make_ispconfig_ssl_cert() {
27592807 }
27602808 }
27612809
2810+ //* Define and check ISPConfig SSL folder */
2811+ $ ssl_dir = $ conf ['ispconfig_install_dir ' ].'/interface/ssl ' ;
2812+ if (!@is_dir ($ ssl_dir )) {
2813+ mkdir ($ ssl_dir , 0755 , true );
2814+ }
2815+
2816+ $ ssl_crt_file = $ ssl_dir .'/ispserver.crt ' ;
2817+ $ ssl_csr_file = $ ssl_dir .'/ispserver.csr ' ;
2818+ $ ssl_key_file = $ ssl_dir .'/ispserver.key ' ;
2819+ $ ssl_pem_file = $ ssl_dir .'/ispserver.pem ' ;
2820+
2821+ $ date = new DateTime ();
2822+
27622823 // Request for certs if no LE SSL folder for server fqdn exist
2763- $ le_live_dir = '/etc/letsencrypt/live/ ' . $ hostname ;
2764- if (!@is_dir ($ le_live_dir ) && (($ svr_ip4 && in_array ($ svr_ip4 , $ dns_ips )) || ($ svr_ip6 && in_array ($ svr_ip6 , $ dns_ips )))) {
2824+
2825+ $ acme_cert_dir = '/usr/local/ispconfig/server/scripts/ ' . $ hostname ;
2826+ $ check_acme_file = $ acme_cert_dir . '/ ' . $ hostname . '.cer ' ;
2827+ if (!@is_dir ($ acme_cert_dir )) {
2828+ $ acme_cert_dir = '/root/.acme.sh/ ' . $ hostname ;
2829+ $ check_acme_file = $ acme_cert_dir . '/ ' . $ hostname . '.cer ' ;
2830+ if (!@is_dir ($ acme_cert_dir )) {
2831+ $ acme_cert_dir = '/etc/letsencrypt/live/ ' . $ hostname ;
2832+ $ check_acme_file = $ acme_cert_dir . '/cert.pem ' ;
2833+ }
2834+ }
2835+ if ((!@is_dir ($ acme_cert_dir ) || !@file_exists ($ check_acme_file ) || !@file_exists ($ ssl_crt_file ) || md5_file ($ check_acme_file ) != md5_file ($ ssl_crt_file )) && (($ svr_ip4 && in_array ($ svr_ip4 , $ dns_ips )) || ($ svr_ip6 && in_array ($ svr_ip6 , $ dns_ips )))) {
27652836
27662837 // This script is needed earlier to check and open http port 80 or standalone might fail
27672838 // Make executable and temporary symlink latest letsencrypt pre, post and renew hook script before install
2768- if (file_exists (dirname (getcwd ()) . '/server/scripts/letsencrypt_pre_hook.sh ' )) {
2839+ if (file_exists (dirname (getcwd ()) . '/server/scripts/letsencrypt_pre_hook.sh ' ) && ! file_exists ( ' /usr/local/bin/letsencrypt_pre_hook.sh ' ) ) {
27692840 symlink (dirname (getcwd ()) . '/server/scripts/letsencrypt_pre_hook.sh ' , '/usr/local/bin/letsencrypt_pre_hook.sh ' );
27702841 }
2771- if (file_exists (dirname (getcwd ()) . '/server/scripts/letsencrypt_post_hook.sh ' )) {
2842+ if (file_exists (dirname (getcwd ()) . '/server/scripts/letsencrypt_post_hook.sh ' ) && ! file_exists ( ' /usr/local/bin/letsencrypt_post_hook.sh ' ) ) {
27722843 symlink (dirname (getcwd ()) . '/server/scripts/letsencrypt_post_hook.sh ' , '/usr/local/bin/letsencrypt_post_hook.sh ' );
27732844 }
2774- if (file_exists (dirname (getcwd ()) . '/server/scripts/letsencrypt_renew_hook.sh ' )) {
2845+ if (file_exists (dirname (getcwd ()) . '/server/scripts/letsencrypt_renew_hook.sh ' ) && ! file_exists ( ' /usr/local/bin/letsencrypt_renew_hook.sh ' ) ) {
27752846 symlink (dirname (getcwd ()) . '/server/scripts/letsencrypt_renew_hook.sh ' , '/usr/local/bin/letsencrypt_renew_hook.sh ' );
27762847 }
27772848 chown ('/usr/local/bin/letsencrypt_pre_hook.sh ' , 'root ' );
@@ -2802,32 +2873,67 @@ public function make_ispconfig_ssl_cert() {
28022873 $ acme = explode ("\n" , shell_exec ('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh ' ));
28032874 $ acme = reset ($ acme );
28042875
2876+ $ restore_conf_symlink = false ;
2877+
2878+ // we only need this for apache, so use fixed conf index
2879+ $ vhost_conf_dir = $ conf ['apache ' ]['vhost_conf_dir ' ];
2880+ $ vhost_conf_enabled_dir = $ conf ['apache ' ]['vhost_conf_enabled_dir ' ];
2881+
2882+ // first of all create the acme vhosts if not existing
2883+ if ($ conf ['nginx ' ]['installed ' ] == true ) {
2884+ $ this ->make_acme_vhost ($ hostname , 'nginx ' );
2885+ } elseif ($ conf ['apache ' ]['installed ' ] == true ) {
2886+ if ($ this ->is_update == false && @is_link ($ vhost_conf_enabled_dir .'/000-ispconfig.conf ' )) {
2887+ $ restore_conf_symlink = true ;
2888+ unlink ($ vhost_conf_enabled_dir .'/000-ispconfig.conf ' );
2889+ }
2890+
2891+ $ this ->make_acme_vhost ($ hostname , 'apache ' );
2892+ }
2893+
2894+ $ issued_successfully = false ;
2895+
28052896 // Attempt to use Neilpang acme.sh first, as it is now the preferred LE client
28062897 if (is_executable ($ acme )) {
28072898
2808- if ( $ conf [ ' nginx ' ][ ' installed ' ] == true ) {
2809- exec ( " $ acme --issue --nginx -d $ hostname $ renew_hook " ) ;
2810- } elseif ( $ conf ['apache ' ]['installed ' ] == true ) {
2811- exec ("$ acme --issue --apache -d $ hostname $ renew_hook " );
2899+ $ out = null ;
2900+ $ ret = null ;
2901+ if ( $ conf [ ' nginx ' ][ ' installed ' ] == true || $ conf ['apache ' ]['installed ' ] == true ) {
2902+ exec ("$ acme --issue -w /usr/local/ispconfig/interface/acme -d $ hostname $ renew_hook " , $ out , $ ret );
28122903 }
28132904 // Else, it is not webserver, so we use standalone
28142905 else {
2815- exec ("$ acme --issue --standalone -d $ hostname $ hook " );
2906+ exec ("$ acme --issue --standalone -d " . escapeshellarg ( $ hostname) . " $ hook ", $ out , $ ret );
28162907 }
28172908
2818- // Define LE certs name and path, then install them
2819- if (!@is_dir ($ le_live_dir )) mkdir ($ le_live_dir , 0755 , true );
2820- $ acme_cert = "--cert-file $ le_live_dir/cert.pem " ;
2821- $ acme_key = "--key-file $ le_live_dir/privkey.pem " ;
2822- $ acme_ca = "--ca-file $ le_live_dir/chain.pem " ;
2823- $ acme_chain = "--fullchain-file $ le_live_dir/fullchain.pem " ;
2824- exec ("$ acme --install-cert -d $ hostname $ acme_cert $ acme_key $ acme_ca $ acme_chain " );
2909+ if ($ ret == 0 || ($ ret == 2 && file_exists ($ check_acme_file ))) {
2910+ // acme.sh returns with 2 on issue for already existing certificate
2911+
2912+ // Backup existing ispserver ssl files
2913+ if (file_exists ($ ssl_crt_file ) || is_link ($ ssl_crt_file )) {
2914+ rename ($ ssl_crt_file , $ ssl_crt_file . '- ' . $ date ->format ('YmdHis ' ) . '.bak ' );
2915+ }
2916+ if (file_exists ($ ssl_key_file ) || is_link ($ ssl_key_file )) {
2917+ rename ($ ssl_key_file , $ ssl_key_file . '- ' . $ date ->format ('YmdHis ' ) . '.bak ' );
2918+ }
2919+ if (file_exists ($ ssl_pem_file ) || is_link ($ ssl_pem_file )) {
2920+ rename ($ ssl_pem_file , $ ssl_pem_file . '- ' . $ date ->format ('YmdHis ' ) . '.bak ' );
2921+ }
28252922
2923+ // Define LE certs name and path, then install them
2924+ //$acme_cert = "--cert-file $acme_cert_dir/cert.pem";
2925+ $ acme_key = "--key-file " . escapeshellarg ($ ssl_key_file );
2926+ $ acme_chain = "--fullchain-file " . escapeshellarg ($ ssl_crt_file );
2927+ exec ("$ acme --install-cert -d $ hostname $ acme_key $ acme_chain " );
2928+ $ issued_successfully = true ;
2929+ }
28262930 // Else, we attempt to use the official LE certbot client certbot
28272931 } else {
28282932
28292933 // But only if it is otherwise available
28302934 if (is_executable ($ le_client )) {
2935+ $ out = null ;
2936+ $ ret = null ;
28312937
28322938 // Get its version info due to be used for webroot arguement issues
28332939 $ le_info = exec ($ le_client . ' --version 2>&1 ' , $ ret , $ val );
@@ -2840,42 +2946,45 @@ public function make_ispconfig_ssl_cert() {
28402946 $ certonly = 'certonly --agree-tos --non-interactive --expand --rsa-key-size 4096 ' ;
28412947
28422948 // If this is a webserver
2843- if ($ conf ['nginx ' ]['installed ' ] == true )
2844- exec ("$ le_client $ certonly $ acme_version --nginx --email postmaster@ $ hostname $ renew_hook " );
2845- elseif ($ conf ['apache ' ]['installed ' ] == true )
2846- exec ("$ le_client $ certonly $ acme_version --apache --email postmaster@ $ hostname $ renew_hook " );
2949+ if ($ conf ['nginx ' ]['installed ' ] == true || $ conf ['apache ' ]['installed ' ] == true ) {
2950+ 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 );
2951+ }
28472952 // Else, it is not webserver, so we use standalone
2848- else
2849- exec ("$ le_client $ certonly $ acme_version --standalone --email postmaster@ $ hostname -d $ hostname $ hook " );
2850- }
2851- }
2852- }
2853-
2854- //* Define and check ISPConfig SSL folder */
2855- $ ssl_dir = $ conf ['ispconfig_install_dir ' ].'/interface/ssl ' ;
2856- if (!@is_dir ($ ssl_dir )) mkdir ($ ssl_dir , 0755 , true );
2857-
2858- $ ssl_crt_file = $ ssl_dir .'/ispserver.crt ' ;
2859- $ ssl_csr_file = $ ssl_dir .'/ispserver.csr ' ;
2860- $ ssl_key_file = $ ssl_dir .'/ispserver.key ' ;
2861- $ ssl_pem_file = $ ssl_dir .'/ispserver.pem ' ;
2862-
2863- $ date = new DateTime ();
2953+ else {
2954+ exec ("$ le_client $ certonly $ acme_version --standalone --email " . escapeshellarg ('postmaster@$hostname ' ) . " -d " . escapeshellarg ($ hostname ) . " $ hook " , $ out , $ ret );
2955+ }
28642956
2865- // If the LE SSL certs for this hostname exists
2866- if ( is_dir ( $ le_live_dir ) && (( $ svr_ip4 && in_array ( $ svr_ip4 , $ dns_ips )) || ( $ svr_ip6 && in_array ( $ svr_ip6 , $ dns_ips )))) {
2957+ if ( $ ret == 0 ) {
2958+ // certbot returns with 0 on issue for already existing certificate
28672959
2868- // Backup existing ispserver ssl files
2869- if (file_exists ($ ssl_crt_file )) rename ($ ssl_crt_file , $ ssl_crt_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2870- if (file_exists ($ ssl_key_file )) rename ($ ssl_key_file , $ ssl_key_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2871- if (file_exists ($ ssl_pem_file )) rename ($ ssl_pem_file , $ ssl_pem_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2960+ // Backup existing ispserver ssl files
2961+ if (file_exists ($ ssl_crt_file ) || is_link ($ ssl_crt_file )) {
2962+ rename ($ ssl_crt_file , $ ssl_crt_file . '- ' . $ date ->format ('YmdHis ' ) . '.bak ' );
2963+ }
2964+ if (file_exists ($ ssl_key_file ) || is_link ($ ssl_key_file )) {
2965+ rename ($ ssl_key_file , $ ssl_key_file . '- ' . $ date ->format ('YmdHis ' ) . '.bak ' );
2966+ }
2967+ if (file_exists ($ ssl_pem_file ) || is_link ($ ssl_pem_file )) {
2968+ rename ($ ssl_pem_file , $ ssl_pem_file . '- ' . $ date ->format ('YmdHis ' ) . '.bak ' );
2969+ }
28722970
2873- // Create symlink to LE fullchain and key for ISPConfig
2874- symlink ($ le_live_dir .'/fullchain.pem ' , $ ssl_crt_file );
2875- symlink ($ le_live_dir .'/privkey.pem ' , $ ssl_key_file );
2971+ $ issued_successfully = true ;
2972+ }
2973+ }
2974+ }
28762975
2877- } else {
2976+ if ($ restore_conf_symlink ) {
2977+ if (!@is_link ($ vhost_conf_enabled_dir .'/000-ispconfig.conf ' )) {
2978+ symlink ($ vhost_conf_dir .'/ispconfig.conf ' , $ vhost_conf_enabled_dir .'/000-ispconfig.conf ' );
2979+ }
2980+ }
2981+ } elseif (($ svr_ip4 && in_array ($ svr_ip4 , $ dns_ips )) || ($ svr_ip6 && in_array ($ svr_ip6 , $ dns_ips ))) {
2982+ // the directory already exists so we have to assume that it was created previously
2983+ $ issued_successfully = true ;
2984+ }
28782985
2986+ // If the LE SSL certs for this hostname exists
2987+ if (!is_dir ($ acme_cert_dir ) || !file_exists ($ check_acme_file ) || !$ issued_successfully ) {
28792988 // We can still use the old self-signed method
28802989 $ ssl_pw = substr (md5 (mt_rand ()), 0 , 6 );
28812990 exec ("openssl genrsa -des3 -passout pass: $ ssl_pw -out $ ssl_key_file 4096 " );
0 commit comments