@@ -2046,7 +2046,6 @@ public function configure_apps_vhost() {
20462046 if (!@is_link ($ vhost_conf_enabled_dir .'/000-apps.vhost ' )) {
20472047 symlink ($ vhost_conf_dir .'/apps.vhost ' , $ vhost_conf_enabled_dir .'/000-apps.vhost ' );
20482048 }
2049-
20502049 }
20512050 }
20522051
@@ -2059,7 +2058,14 @@ public function make_ispconfig_ssl_cert() {
20592058
20602059 // Check dns a record exist and its ip equal to server public ip
20612060 $ svr_ip = file_get_contents ('http://dynamicdns.park-your-domain.com/getip ' );
2062- if (checkdnsrr (idn_to_ascii ($ hostname , IDNA_NONTRANSITIONAL_TO_ASCII , INTL_IDNA_VARIANT_UTS46 ), 'A ' )) {
2061+ if (function_exists ('idn_to_ascii ' )) {
2062+ if (defined ('IDNA_NONTRANSITIONAL_TO_ASCII ' ) && defined ('INTL_IDNA_VARIANT_UTS46 ' ) && constant ('IDNA_NONTRANSITIONAL_TO_ASCII ' )) {
2063+ $ hostname = idn_to_ascii ($ hostname , IDNA_NONTRANSITIONAL_TO_ASCII , INTL_IDNA_VARIANT_UTS46 );
2064+ } else {
2065+ $ hostname = idn_to_ascii ($ hostname );
2066+ }
2067+ }
2068+ if (checkdnsrr ($ hostname , 'A ' )) {
20632069 $ dnsa =dns_get_record ($ hostname , DNS_A );
20642070 $ dns_ips = array ();
20652071 foreach ($ dnsa as $ rec ) {
@@ -2071,44 +2077,111 @@ public function make_ispconfig_ssl_cert() {
20712077 $ le_live_dir = '/etc/letsencrypt/live/ ' . $ hostname ;
20722078 if (!@is_dir ($ le_live_dir ) && in_array ($ svr_ip , $ dns_ips )) {
20732079
2080+ // Set webroot path for all ISPConfig server LE certs
2081+ $ webroot_path = $ conf ['ispconfig_install_dir ' ].'/interface/acme ' ;
2082+ if (!@is_dir ($ webroot_path )) $ webroot_path = '/var/www/html ' ;
2083+
2084+ // This script is needed earlier to check and open http port 80 or standalone might fail
2085+ // Make executable and temporary symlink latest letsencrypt pre, post and renew hook script before install
2086+ if (file_exists ('/tmp/ispconfig3_install/server/scripts/letsencrypt_pre_hook.sh ' ))
2087+ symlink ('/tmp/ispconfig3_install/server/scripts/letsencrypt_pre_hook.sh ' , '/usr/local/bin/letsencrypt_pre_hook.sh ' );
2088+ if (file_exists ('/tmp/ispconfig3_install/server/scripts/letsencrypt_post_hook.sh ' ))
2089+ symlink ('/tmp/ispconfig3_install/server/scripts/letsencrypt_post_hook.sh ' , '/usr/local/bin/letsencrypt_post_hook.sh ' );
2090+ if (file_exists ('/tmp/ispconfig3_install/server/scripts/letsencrypt_renew_hook.sh ' ))
2091+ symlink ('/tmp/ispconfig3_install/server/scripts/letsencrypt_renew_hook.sh ' , '/usr/local/bin/letsencrypt_renew_hook.sh ' );
2092+ chown ('/usr/local/bin/letsencrypt_pre_hook.sh ' , 'root ' );
2093+ chown ('/usr/local/bin/letsencrypt_post_hook.sh ' , 'root ' );
2094+ chown ('/usr/local/bin/letsencrypt_renew_hook.sh ' , 'root ' );
2095+ chmod ('/usr/local/bin/letsencrypt_pre_hook.sh ' , 0700 );
2096+ chmod ('/usr/local/bin/letsencrypt_post_hook.sh ' , 0700 );
2097+ chmod ('/usr/local/bin/letsencrypt_renew_hook.sh ' , 0700 );
2098+
2099+ // Check http port 80 status as it cannot be determined at post hook stage
2100+ $ port80_status =exec ('true &>/dev/null </dev/tcp/127.0.0.1/80 && echo open || echo close ' );
2101+
2102+ // Set pre-, post- and renew hook
2103+ $ pre_hook = file_exists ('/usr/local/bin/letsencrypt_pre_hook.sh ' ) ? "--pre-hook \"letsencrypt_pre_hook.sh \"" : "" ;
2104+ $ renew_hook = file_exists ('/usr/local/bin/letsencrypt_renew_hook.sh ' ) ? " --renew-hook \"letsencrypt_renew_hook.sh \"" : "" ;
2105+ if ($ port80_status == 'close ' ) {
2106+ $ post_hook = file_exists ('/usr/local/bin/letsencrypt_post_hook.sh ' ) ? " --post-hook \"letsencrypt_post_hook.sh \"" : "" ;
2107+ $ hook = $ pre_hook . $ post_hook . $ renew_hook ;
2108+ }
2109+ else
2110+ $ hook = $ pre_hook . $ renew_hook ;
2111+
20742112 // Get the default LE client name and version
20752113 $ le_client = explode ("\n" , shell_exec ('which letsencrypt certbot /root/.local/share/letsencrypt/bin/letsencrypt /opt/eff.org/certbot/venv/bin/certbot ' ));
20762114 $ le_client = reset ($ le_client );
2077- $ le_info = exec ($ le_client . ' --version 2>&1 ' , $ ret , $ val );
2078- if (preg_match ('/^(\S+|\w+)\s+(\d+(\.\d+)+)$/ ' , $ le_info , $ matches )) { $ le_name = $ matches [1 ]; $ le_version = $ matches [2 ]; }
20792115
2080- // Define certbot commands
2081- $ acme_version = '--server https://acme-v0 ' . (($ le_version >=0.22 ) ? '2 ' : '1 ' ) . '.api.letsencrypt.org/directory ' ;
2082- $ certonly = 'certonly --agree-tos --non-interactive --expand --rsa-key-size 4096 ' ;
2083- $ webroot = '--authenticator webroot --webroot-path /var/www/html ' ;
2084- $ standalone = '--authenticator standalone ' ;
2085-
2086- // Only certbot is supported to prevent unknown failures
2087- if ($ le_name == 'certbot ' && is_executable ($ le_client )) {
2116+ // Check for Neilpang acme.sh as well
2117+ $ acme = explode ("\n" , shell_exec ('which /usr/local/ispconfig/server/scripts/acme.sh /root/.acme.sh/acme.sh ' ));
2118+ $ acme = reset ($ acme );
2119+
2120+ // Attempt to use Neilpang acme.sh first, as it is now the preferred LE client
2121+ if (is_executable ($ acme )) {
2122+
20882123 // If this is a webserver, we use webroot
2089- if (($ conf ['nginx ' ]['installed ' ] || $ conf ['apache ' ]['installed ' ]) == true ) {
2090- $ well_known = '/var/www/html/.well-known ' ;
2091- $ challenge = "$ well_known/acme_challenge " ;
2092- $ acme_challenge = '/usr/local/ispconfig/interface/acme/.well-known/acme-challenge ' ;
2093- if (!is_dir ($ well_known )) mkdir ($ well_known , 0755 , true );
2094- if (!is_dir ($ challenge )) exec ("ln -sf $ acme_challenge $ challenge " );
2095- exec ("$ le_client $ certonly $ acme_version $ webroot --email postmaster@ $ hostname -d $ hostname " );
2096- }
2124+ if (($ conf ['nginx ' ]['installed ' ] || $ conf ['apache ' ]['installed ' ]) == true )
2125+ exec ("$ acme --issue -d $ hostname --webroot $ webroot_path $ renew_hook " );
2126+
20972127 // Else, it is not webserver, so we use standalone
20982128 else
2099- exec ("$ le_client $ certonly $ acme_version $ standalone --email postmaster@ $ hostname -d $ hostname " );
2129+ exec ("$ acme --issue --standalone -d $ hostname $ hook " );
2130+
2131+ // Define LE certs name and path, then install them
2132+ if (!@is_dir ($ le_live_dir )) mkdir ($ le_live_dir , 0755 , true );
2133+ $ acme_cert = "--cert-file $ le_live_dir/cert.pem " ;
2134+ $ acme_key = "--key-file $ le_live_dir/privkey.pem " ;
2135+ $ acme_ca = "--ca-file $ le_live_dir/chain.pem " ;
2136+ $ acme_chain = "--fullchain-file $ le_live_dir/fullchain.pem " ;
2137+ exec ("$ acme --install-cert -d $ hostname $ acme_cert $ acme_key $ acme_ca $ acme_chain " );
2138+
2139+ // Else, we attempt to use the official LE certbot client certbot
2140+ } else {
2141+
2142+ // But only if it is otherwise available
2143+ if (is_executable ($ le_client )) {
2144+
2145+ // Get its version info due to be used for webroot arguement issues
2146+ $ le_info = exec ($ le_client . ' --version 2>&1 ' , $ ret , $ val );
2147+ if (preg_match ('/^(\S+|\w+)\s+(\d+(\.\d+)+)$/ ' , $ le_info , $ matches ))
2148+ $ le_version = $ matches [2 ];
2149+
2150+ // Define certbot commands
2151+ $ acme_version = '--server https://acme-v0 ' . (($ le_version >=0.22 ) ? '2 ' : '1 ' ) . '.api.letsencrypt.org/directory ' ;
2152+ $ certonly = 'certonly --agree-tos --non-interactive --expand --rsa-key-size 4096 ' ;
2153+
2154+ // certbot choice of authenticator
2155+ $ standalone_auth = '--authenticator standalone ' ;
2156+ $ webroot_auth = '--authenticator webroot ' ;
2157+
2158+ // certbot webroot arguments i.e. map for >=0.30 or path for <=0.29
2159+ $ webroot_map [$ hostname ] = $ webroot_path ;
2160+ if ($ le_version >=0.30 )
2161+ $ webroot_args = '--webroot-map ' . escapeshellarg (str_replace (array ('\r ' , '\n ' ), '' , json_encode ($ webroot_map )));
2162+ else
2163+ $ webroot_args = "-d $ hostname --webroot-path $ webroot_path " ;
2164+
2165+ // If this is a webserver, we use webroot
2166+ if (($ conf ['nginx ' ]['installed ' ] || $ conf ['apache ' ]['installed ' ]) == true ) {
2167+ exec ("$ le_client $ certonly $ acme_version $ webroot_auth --email postmaster@ $ hostname $ webroot_args $ renew_hook " );
2168+ }
2169+ // Else, it is not webserver, so we use standalone
2170+ else
2171+ exec ("$ le_client $ certonly $ acme_version $ standalone_auth --email postmaster@ $ hostname -d $ hostname $ hook " );
2172+
2173+ }
21002174 }
21012175 }
21022176
21032177 //* Define and check ISPConfig SSL folder */
2104- $ install_dir = $ conf ['ispconfig_install_dir ' ];
2178+ $ ssl_dir = $ conf ['ispconfig_install_dir ' ].'/interface/ssl ' ;
2179+ if (!@is_dir ($ ssl_dir )) mkdir ($ ssl_dir , 0755 , true );
21052180
2106- $ ssl_crt_file = $ install_dir .'/interface/ssl/ispserver.crt ' ;
2107- $ ssl_csr_file = $ install_dir .'/interface/ssl/ispserver.csr ' ;
2108- $ ssl_key_file = $ install_dir .'/interface/ssl/ispserver.key ' ;
2109- $ ssl_pem_file = $ install_dir .'/interface/ssl/ispserver.pem ' ;
2110-
2111- if (!@is_dir ($ install_dir .'/interface/ssl ' )) mkdir ($ install_dir .'/interface/ssl ' , 0755 , true );
2181+ $ ssl_crt_file = $ ssl_dir .'/ispserver.crt ' ;
2182+ $ ssl_csr_file = $ ssl_dir .'/ispserver.csr ' ;
2183+ $ ssl_key_file = $ ssl_dir .'/ispserver.key ' ;
2184+ $ ssl_pem_file = $ ssl_dir .'/ispserver.pem ' ;
21122185
21132186 $ date = new DateTime ();
21142187
@@ -2117,8 +2190,8 @@ public function make_ispconfig_ssl_cert() {
21172190
21182191 // Backup existing ispserver ssl files
21192192 if (file_exists ($ ssl_crt_file )) rename ($ ssl_crt_file , $ ssl_crt_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2120- if (file_exists ($ ssl_crt_file )) rename ($ ssl_key_file , $ ssl_key_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2121- if (file_exists ($ ssl_crt_file )) rename ($ ssl_pem_file , $ ssl_pem_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2193+ if (file_exists ($ ssl_key_file )) rename ($ ssl_key_file , $ ssl_key_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2194+ if (file_exists ($ ssl_pem_file )) rename ($ ssl_pem_file , $ ssl_pem_file . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
21222195
21232196 // Create symlink to LE fullchain and key for ISPConfig
21242197 symlink ($ le_live_dir .'/fullchain.pem ' , $ ssl_crt_file );
@@ -2145,41 +2218,41 @@ public function make_ispconfig_ssl_cert() {
21452218
21462219 // Extend LE SSL certs to postfix
21472220 if ($ conf ['postfix ' ]['installed ' ] == true && strtolower ($ this ->simple_query ('Symlink ISPConfig LE SSL certs to postfix? ' , array ('y ' , 'n ' ), 'y ' )) == 'y ' ) {
2148-
2149- // Define folder, file(s)
2150- $ cf = $ conf ['postfix ' ];
2151- $ postfix_dir = $ cf ['config_dir ' ];
2152- if (!is_dir ($ postfix_dir )) $ this ->error ("The postfix configuration directory ' $ postfix_dir' does not exist. " );
2153- $ smtpd_crt = $ postfix_dir .'/smtpd.cert ' ;
2154- $ smtpd_key = $ postfix_dir .'/smtpd.key ' ;
2155-
2156- // Backup existing postfix ssl files
2157- if (file_exists ($ smtpd_crt )) rename ($ smtpd_crt , $ smtpd_crt . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2158- if (file_exists ($ smtpd_key )) rename ($ smtpd_key , $ smtpd_key . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2159-
2160- // Create symlink to ISPConfig SSL files
2161- symlink ($ ssl_crt_file , $ smtpd_crt );
2162- symlink ($ ssl_key_file , $ smtpd_key );
2163- }
2164-
2165- // Extend LE SSL certs to pureftpd
2166- if ($ conf ['pureftpd ' ]['installed ' ] == true && strtolower ($ this ->simple_query ('Symlink ISPConfig LE SSL certs to pureftpd? Creating dhparam file takes some times. ' , array ('y ' , 'n ' ), 'y ' )) == 'y ' ) {
2167-
2168- // Define folder, file(s)
2169- $ pureftpd_dir = '/etc/ssl/private ' ;
2170- if (!is_dir ($ pureftpd_dir )) mkdir ($ pureftpd_dir , 0755 , true );
2171- $ pureftpd_pem = $ pureftpd_dir .'/pure-ftpd.pem ' ;
2172-
2173- // Backup existing pureftpd ssl files
2174- if (file_exists ($ pureftpd_pem )) rename ($ pureftpd_pem , $ pureftpd_pem . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2175-
2176- // Create symlink to ISPConfig SSL files
2177- symlink ($ ssl_pem_file , $ pureftpd_pem );
2178- if (!file_exists ("$ pureftpd_dir/pure-ftpd-dhparams.pem " ))
2179- exec ("cd $ pureftpd_dir; openssl dhparam -out dhparam4096 .pem 4096 ; ln -sf dhparam4096 .pem pure-ftpd-dhparams.pem " );
2180- }
2181-
2182- exec ("chown -R root:root $ install_dir /interface/ssl " );
2221+
2222+ // Define folder, file(s)
2223+ $ cf = $ conf ['postfix ' ];
2224+ $ postfix_dir = $ cf ['config_dir ' ];
2225+ if (!is_dir ($ postfix_dir )) $ this ->error ("The postfix configuration directory ' $ postfix_dir' does not exist. " );
2226+ $ smtpd_crt = $ postfix_dir .'/smtpd.cert ' ;
2227+ $ smtpd_key = $ postfix_dir .'/smtpd.key ' ;
2228+
2229+ // Backup existing postfix ssl files
2230+ if (file_exists ($ smtpd_crt )) rename ($ smtpd_crt , $ smtpd_crt . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2231+ if (file_exists ($ smtpd_key )) rename ($ smtpd_key , $ smtpd_key . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2232+
2233+ // Create symlink to ISPConfig SSL files
2234+ symlink ($ ssl_crt_file , $ smtpd_crt );
2235+ symlink ($ ssl_key_file , $ smtpd_key );
2236+ }
2237+
2238+ // Extend LE SSL certs to pureftpd
2239+ if ($ conf ['pureftpd ' ]['installed ' ] == true && strtolower ($ this ->simple_query ('Symlink ISPConfig LE SSL certs to pureftpd? Creating dhparam file takes some times. ' , array ('y ' , 'n ' ), 'y ' )) == 'y ' ) {
2240+
2241+ // Define folder, file(s)
2242+ $ pureftpd_dir = '/etc/ssl/private ' ;
2243+ if (!is_dir ($ pureftpd_dir )) mkdir ($ pureftpd_dir , 0755 , true );
2244+ $ pureftpd_pem = $ pureftpd_dir .'/pure-ftpd.pem ' ;
2245+
2246+ // Backup existing pureftpd ssl files
2247+ if (file_exists ($ pureftpd_pem )) rename ($ pureftpd_pem , $ pureftpd_pem . '- ' .$ date ->format ('YmdHis ' ) . '.bak ' );
2248+
2249+ // Create symlink to ISPConfig SSL files
2250+ symlink ($ ssl_pem_file , $ pureftpd_pem );
2251+ if (!file_exists ("$ pureftpd_dir/pure-ftpd-dhparams.pem " ))
2252+ exec ("cd $ pureftpd_dir; openssl dhparam -out dhparam2048 .pem 2048 ; ln -sf dhparam2048 .pem pure-ftpd-dhparams.pem " );
2253+ }
2254+
2255+ exec ("chown -R root:root $ ssl_dir " );
21832256
21842257 }
21852258
@@ -2610,6 +2683,20 @@ public function install_ispconfig() {
26102683 chmod ($ install_dir .'/server/scripts/ispconfig_update.sh ' , 0700 );
26112684 if (!is_link ('/usr/local/bin/ispconfig_update_from_dev.sh ' )) symlink ($ install_dir .'/server/scripts/ispconfig_update.sh ' , '/usr/local/bin/ispconfig_update_from_dev.sh ' );
26122685 if (!is_link ('/usr/local/bin/ispconfig_update.sh ' )) symlink ($ install_dir .'/server/scripts/ispconfig_update.sh ' , '/usr/local/bin/ispconfig_update.sh ' );
2686+
2687+ // Make executable then unlink and symlink letsencrypt pre, post and renew hook scripts
2688+ chown ($ install_dir .'/server/scripts/letsencrypt_pre_hook.sh ' , 'root ' );
2689+ chown ($ install_dir .'/server/scripts/letsencrypt_post_hook.sh ' , 'root ' );
2690+ chown ($ install_dir .'/server/scripts/letsencrypt_renew_hook.sh ' , 'root ' );
2691+ chmod ($ install_dir .'/server/scripts/letsencrypt_pre_hook.sh ' , 0700 );
2692+ chmod ($ install_dir .'/server/scripts/letsencrypt_post_hook.sh ' , 0700 );
2693+ chmod ($ install_dir .'/server/scripts/letsencrypt_renew_hook.sh ' , 0700 );
2694+ if (is_link ('/usr/local/bin/letsencrypt_pre_hook.sh ' )) unlink ('/usr/local/bin/letsencrypt_pre_hook.sh ' );
2695+ if (is_link ('/usr/local/bin/letsencrypt_post_hook.sh ' )) unlink ('/usr/local/bin/letsencrypt_post_hook.sh ' );
2696+ if (is_link ('/usr/local/bin/letsencrypt_renew_hook.sh ' )) unlink ('/usr/local/bin/letsencrypt_renew_hook.sh ' );
2697+ symlink ($ install_dir .'/server/scripts/letsencrypt_pre_hook.sh ' , '/usr/local/bin/letsencrypt_pre_hook.sh ' );
2698+ symlink ($ install_dir .'/server/scripts/letsencrypt_post_hook.sh ' , '/usr/local/bin/letsencrypt_post_hook.sh ' );
2699+ symlink ($ install_dir .'/server/scripts/letsencrypt_renew_hook.sh ' , '/usr/local/bin/letsencrypt_renew_hook.sh ' );
26132700
26142701 //* Make the logs readable for the ispconfig user
26152702 if (@is_file ('/var/log/mail.log ' )) exec ('chmod +r /var/log/mail.log ' );
0 commit comments