Skip to content

Commit f3b5a93

Browse files
author
Till Brehm
committed
Merge branch '5735-certbot-apache-is-needed-when-using-3-2' into 'develop'
Resolve "Certbot-Apache is needed, when using 3.2" Closes #5735 See merge request ispconfig/ispconfig3!1173
2 parents 84f0ff7 + c4e1637 commit f3b5a93

File tree

7 files changed

+211
-58
lines changed

7 files changed

+211
-58
lines changed

install/install.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,12 +536,6 @@
536536
$inst->configure_fail2ban();
537537
}
538538

539-
if($conf['services']['web'] == true) {
540-
//** Configure apps vhost
541-
swriteln('Configuring Apps vhost');
542-
$inst->configure_apps_vhost();
543-
}
544-
545539
//** Configure ISPConfig :-)
546540
$install_ispconfig_interface_default = ($conf['mysql']['master_slave_setup'] == 'y')?'n':'y';
547541
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 @@
582576
$inst->make_ispconfig_ssl_cert();
583577
}
584578

579+
if($conf['services']['web'] == true) {
580+
//** Configure apps vhost
581+
swriteln('Configuring Apps vhost');
582+
$inst->configure_apps_vhost();
583+
}
584+
585585
$inst->install_ispconfig();
586586

587587
//* Configure DBServer

install/lib/installer_base.lib.php

Lines changed: 156 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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)) && (($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 -d $hostname $renew_hook");
2845-
elseif($conf['apache']['installed'] == true)
2846-
exec("$le_client $certonly $acme_version --apache --email postmaster@$hostname -d $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");
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Alias /.well-known/acme-challenge /usr/local/ispconfig/interface/acme/.well-known/acme-challenge
2+
3+
<Directory /usr/local/ispconfig/interface/acme>
4+
AllowOverride None
5+
<tmpl_if name='apache_version' op='>' value='2.2' format='version'>
6+
Require all granted
7+
<tmpl_else>
8+
Order allow,deny
9+
Allow from all
10+
</tmpl_if>
11+
</Directory>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
server {
2+
listen 80;
3+
listen [::]:80;
4+
5+
server_name <tmpl_var name='domain'>;
6+
7+
root /usr/local/ispconfig/interface/acme;
8+
9+
autoindex off;
10+
index index.html;
11+
12+
## Disable .htaccess and other hidden files
13+
location ~ / {
14+
deny all;
15+
}
16+
17+
## Allow access for .well-known/acme-challenge
18+
location ^~ /.well-known/acme-challenge/ {
19+
access_log off;
20+
log_not_found off;
21+
auth_basic off;
22+
root /usr/local/ispconfig/interface/acme/;
23+
try_files $uri $uri/ =404;
24+
}
25+
}

server/scripts/letsencrypt_post_hook.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
## If you need a custom hook file, create a file with the same name in
1414
## /usr/local/ispconfig/server/conf-custom/scripts/
15-
if [[ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_post_hook.sh" ]] ; then
15+
if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_post_hook.sh" ] ; then
1616
. /usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_post_hook.sh && exit 0 || exit 1;
1717
fi
1818

server/scripts/letsencrypt_pre_hook.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
## If you need a custom hook file, create a file with the same name in
1414
## /usr/local/ispconfig/server/conf-custom/scripts/
15-
if [[ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_pre_hook.sh" ]] ; then
15+
if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_pre_hook.sh" ] ; then
1616
. /usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_pre_hook.sh && exit 0 || exit 1 ;
1717
fi
1818

server/scripts/letsencrypt_renew_hook.sh

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@
1212

1313
## If you need a custom hook file, create a file with the same name in
1414
## /usr/local/ispconfig/server/conf-custom/scripts/
15-
if [[ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook.sh" ]] ; then
15+
if [ -e "/usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook.sh" ] ; then
1616
. /usr/local/ispconfig/server/conf-custom/scripts/letsencrypt_renew_hook.sh && exit 0 || exit 1;
1717
fi
1818

19-
lelive=/etc/letsencrypt/live/$(hostname -f); if [ -d "$lelive" ]; then
19+
hostname=$(hostname -f)
20+
if [ -d "/usr/local/ispconfig/server/scripts/${hostname}" ] ; then
21+
lelive="/usr/local/ispconfig/server/scripts/${hostname}" ;
22+
elif [ -d "/root/.acme.sh/${hostname}" ] ; then
23+
lelive="/root/.acme.sh/${hostname}" ;
24+
else
25+
lelive="/etc/letsencrypt/live/${hostname}" ;
26+
fi
27+
28+
if [ -d "$lelive" ]; then
2029
cd /usr/local/ispconfig/interface/ssl; ibak=ispserver.*.bak; ipem=ispserver.pem; icrt=ispserver.crt; ikey=ispserver.key
2130
if ls $ibak 1> /dev/null 2>&1; then rm $ibak; fi
2231
if [ -e "$ipem" ]; then mv $ipem $ipem-$(date +"%y%m%d%H%M%S").bak; cat $ikey $icrt > $ipem; chmod 600 $ipem; fi
@@ -42,6 +51,5 @@ lelive=/etc/letsencrypt/live/$(hostname -f); if [ -d "$lelive" ]; then
4251
if [ $(dpkg-query -W -f='${Status}' mariadb 2>/dev/null | grep -c "ok installed") -eq 1 ]; then service mysql restart; fi
4352
if [ $(dpkg-query -W -f='${Status}' nginx 2>/dev/null | grep -c "ok installed") -eq 1 ]; then service nginx restart; fi
4453
if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ]; then service apache2 restart; fi
45-
else
4654
fi
4755
else echo `/bin/date` "Your Lets Encrypt SSL certs path for your ISPConfig server FQDN is missing.$line" >> /var/log/ispconfig/ispconfig.log; fi

0 commit comments

Comments
 (0)