diff --git a/README.md b/README.md index f1be656..1cd8dc8 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ You could switch it back and forth to demo/live mode by adding and deleting the This module will create all required directories it needs to operate on the first attempt to run site Verify task with SSL option enabled, but you may want to create at least `[aegir_root]/tools/le/.ctrl/` before running it for the first time, so the demo mode will be active on the first attempt. -Read the task log lines which start with `[provision_hosting_le]` prefix for more information. +Read the task log lines which start with `[hosting_le]` prefix for more information. Exceptions ========== diff --git a/drush/provision_hosting_le.drush.inc b/drush/provision_hosting_le.drush.inc index 5552e4d..776d174 100644 --- a/drush/provision_hosting_le.drush.inc +++ b/drush/provision_hosting_le.drush.inc @@ -1,10 +1,8 @@ type == 'site') { @@ -18,19 +16,19 @@ function drush_provision_hosting_le_post_provision_verify() { $le_keyp = d('@server_master')->aegir_root . "/tools/le/private_key.pem"; $sitename = substr(d()->name, 1); - drush_log('[provision_hosting_le] This sitename is ' . $sitename); + drush_log('[hosting_le] This sitename is ' . $sitename); $cert_dir = $le_cert . "/" . $sitename; - drush_log('[provision_hosting_le] This cert_dir is ' . $cert_dir); + drush_log('[hosting_le] This cert_dir is ' . $cert_dir); $no_san_ctrl = d('@server_master')->aegir_root . "/static/control/ssl-no-san-" . $sitename . ".info"; - drush_log('[provision_hosting_le] The optional no-SAN flag is ' . $no_san_ctrl); + drush_log('[hosting_le] The optional no-SAN flag is ' . $no_san_ctrl); $immutable = $le_ctrl . "/dont-overwrite-" . $sitename . ".pid"; - drush_log('[provision_hosting_le] The optional immutable flag is ' . $immutable); + drush_log('[hosting_le] The optional immutable flag is ' . $immutable); $demo_mode = $le_ctrl . "/ssl-demo-mode.pid"; - drush_log('[provision_hosting_le] The optional demo flag is ' . $demo_mode); + drush_log('[hosting_le] The optional demo flag is ' . $demo_mode); } if (d()->type == 'site' && @@ -39,24 +37,24 @@ function drush_provision_hosting_le_post_provision_verify() { if (file_exists($cert_dir)) { exec("/bin/bash " . $le_exec . " -gc", $output_b); $acme_result_b = implode(' ', $output_b); - drush_log('[provision_hosting_le] ACME Cleanup Output: ' . $acme_result_b); + drush_log('[hosting_le] ACME Cleanup Output: ' . $acme_result_b); exec("symlinks -dr " . $cert_dir, $output_c); $acme_result_c = implode(' ', $output_c); - drush_log('[provision_hosting_le] ACME Cleanup Symlinks: ' . $acme_result_c); + drush_log('[hosting_le] ACME Cleanup Symlinks: ' . $acme_result_c); } } elseif (d()->type == 'site' && d()->ssl_enabled) { - provision_file()->create_dir($le_root, dt('[provision_hosting_le] LE root'), 0711); - provision_file()->create_dir($le_cert, dt('[provision_hosting_le] LE certs'), 0700); - provision_file()->create_dir($le_acme, dt('[provision_hosting_le] LE challenges'), 0711); - provision_file()->create_dir($le_ctrl, dt('[provision_hosting_le] LE ctrl'), 0711); + provision_file()->create_dir($le_root, dt('[hosting_le] LE root'), 0711); + provision_file()->create_dir($le_cert, dt('[hosting_le] LE certs'), 0700); + provision_file()->create_dir($le_acme, dt('[hosting_le] LE challenges'), 0711); + provision_file()->create_dir($le_ctrl, dt('[hosting_le] LE ctrl'), 0711); if (!provision_file()->exists($le_exec)->status()) { - drush_log('[provision_hosting_le] Please upload letsencrypt.sh to ' . $le_exec, 'warning'); - drush_log('[provision_hosting_le] URL: https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh', 'warning'); + drush_log('[hosting_le] Please upload letsencrypt.sh to ' . $le_exec, 'warning'); + drush_log('[hosting_le] URL: https://raw.githubusercontent.com/lukas2511/letsencrypt.sh/master/letsencrypt.sh', 'warning'); return FALSE; } @@ -64,7 +62,7 @@ function drush_provision_hosting_le_post_provision_verify() { preg_match("/\.(?:dev|devel|temp|tmp|temporary)\./", $sitename) || preg_match("/\.(?:test|testing|stage|staging)\./", $sitename) || $sitename == 'hostmaster') { - drush_log('[provision_hosting_le] Skipping LE setup for ' . $sitename); + drush_log('[hosting_le] Skipping LE setup for ' . $sitename); return FALSE; } @@ -74,16 +72,16 @@ function drush_provision_hosting_le_post_provision_verify() { $le_conf_lines = "#!/usr/bin/env bash\n\nCA=\"https://acme-staging.api.letsencrypt.org/directory\"\n"; provision_file()->file_put_contents($le_conf, $le_conf_lines) - ->succeed('[provision_hosting_le] Created cnf ' . $le_conf) - ->fail('[provision_hosting_le] Could not create cnf ' . $le_conf); + ->succeed('[hosting_le] Created cnf ' . $le_conf) + ->fail('[hosting_le] Could not create cnf ' . $le_conf); if (provision_file()->exists($le_keyp)->status()) { - drush_log('[provision_hosting_le] Demo LE account will be created.'); + drush_log('[hosting_le] Demo LE account will be created.'); rename($le_keyp, $le_keyp . "-live"); rename($le_keyj, $le_keyj . "-live"); } } - drush_log('[provision_hosting_le] Demo LE mode active. No real LE certs will be generated.'); + drush_log('[hosting_le] Demo LE mode active. No real LE certs will be generated.'); } else { if (provision_file()->exists($le_conf)->status()) { @@ -92,21 +90,21 @@ function drush_provision_hosting_le_post_provision_verify() { rename($le_keyp, $le_keyp . "-demo"); rename($le_keyj, $le_keyj . "-demo"); } - drush_log('[provision_hosting_le] Live LE account will be registered.'); + drush_log('[hosting_le] Live LE account will be registered.'); } - drush_log('[provision_hosting_le] Live LE mode active. Real LE certs will be generated.'); + drush_log('[hosting_le] Live LE mode active. Real LE certs will be generated.'); } - drush_log('[provision_hosting_le] LE certificate for ' . $sitename); + drush_log('[hosting_le] LE certificate for ' . $sitename); if (provision_file()->exists($no_san_ctrl)->status()) { $no_alt_names = TRUE; - drush_log('[provision_hosting_le] SSL no-SAN mode ctrl file detected for ' . $sitename); + drush_log('[hosting_le] SSL no-SAN mode ctrl file detected for ' . $sitename); } else { $no_alt_names = FALSE; $alt_names = implode(' -d ', str_replace('/', '.', d()->aliases)); - drush_log('[provision_hosting_le] ALT names: -d ' . $alt_names); + drush_log('[hosting_le] ALT names: -d ' . $alt_names); } $site_vhost = d('@server_master')->http_vhostd_path . "/" . $sitename; @@ -124,35 +122,35 @@ function drush_provision_hosting_le_post_provision_verify() { } $redirect_result = implode(' ', $grep_output); - drush_log('[provision_hosting_le] Redirect check result for ' . $sitename . ' : ' . $redirect_result); + drush_log('[hosting_le] Redirect check result for ' . $sitename . ' : ' . $redirect_result); if ($redirect_result && !$no_alt_names) { - drush_log("[provision_hosting_le] Aliases redirection must be disabled if all aliases are expected to be listed as SAN names.", 'info'); - drush_log("[provision_hosting_le] The alternative is to disable SAN mode for this site with empty ctrl file: " . $no_san_ctrl, 'info'); - drush_log('[provision_hosting_le] Forcing no-SAN-mode for ' . $sitename); + drush_log("[hosting_le] Aliases redirection must be disabled if all aliases are expected to be listed as SAN names.", 'info'); + drush_log("[hosting_le] The alternative is to disable SAN mode for this site with empty ctrl file: " . $no_san_ctrl, 'info'); + drush_log('[hosting_le] Forcing no-SAN-mode for ' . $sitename); $no_alt_names = TRUE; } } else { - drush_log("[provision_hosting_le] The site's vhost must already exist, or the LE agent will not be able to proceed.", 'warning'); - drush_log('[provision_hosting_le] Path to vhost: ' . $site_vhost); - drush_log('[provision_hosting_le] Skipping LE setup for ' . $sitename); + drush_log("[hosting_le] The site's vhost must already exist, or the LE agent will not be able to proceed.", 'warning'); + drush_log('[hosting_le] Path to vhost: ' . $site_vhost); + drush_log('[hosting_le] Skipping LE setup for ' . $sitename); return FALSE; } if (provision_file()->exists($immutable)->status() && provision_file()->exists($cert_dir)->status()) { - drush_log("[provision_hosting_le] Immutable protection mode detected for this domain: " . $cert_dir, 'info'); - drush_log("[provision_hosting_le] SSL Certificate for this domain already exists in: " . $cert_dir, 'info'); - drush_log("[provision_hosting_le] You can replace it with any other certificate since it will be left here as-is forever.", 'info'); - drush_log("[provision_hosting_le] To re-activate LE auto-renewals please delete this file: " . $immutable, 'info'); - drush_log("[provision_hosting_le] NOTE: On hosted Aegir service you need to contact your host support for further assistance.", 'info'); + drush_log("[hosting_le] Immutable protection mode detected for this domain: " . $cert_dir, 'info'); + drush_log("[hosting_le] SSL Certificate for this domain already exists in: " . $cert_dir, 'info'); + drush_log("[hosting_le] You can replace it with any other certificate since it will be left here as-is forever.", 'info'); + drush_log("[hosting_le] To re-activate LE auto-renewals please delete this file: " . $immutable, 'info'); + drush_log("[hosting_le] NOTE: On hosted Aegir service you need to contact your host support for further assistance.", 'info'); } else { - drush_log("[provision_hosting_le] To stop the LE Certificate auto-renewals please create an empty ctrl file.", 'info'); - drush_log("[provision_hosting_le] Path to use for this site specific empty ctrl file: " . $immutable, 'info'); - drush_log("[provision_hosting_le] You could then replace existing cert with any other cert since it will be left here as-is forever.", 'info'); - drush_log("[provision_hosting_le] NOTE: On hosted Aegir service you need to contact your host support for further assistance.", 'info'); + drush_log("[hosting_le] To stop the LE Certificate auto-renewals please create an empty ctrl file.", 'info'); + drush_log("[hosting_le] Path to use for this site specific empty ctrl file: " . $immutable, 'info'); + drush_log("[hosting_le] You could then replace existing cert with any other cert since it will be left here as-is forever.", 'info'); + drush_log("[hosting_le] NOTE: On hosted Aegir service you need to contact your host support for further assistance.", 'info'); $output = ''; if ($no_alt_names) { exec("/bin/bash " . $le_exec . " -c -d " . $sitename, $output); @@ -161,42 +159,42 @@ function drush_provision_hosting_le_post_provision_verify() { exec("/bin/bash " . $le_exec . " -c -d " . $sitename . " -d " . $alt_names, $output); } $acme_result = implode(' ', $output); - drush_log('[provision_hosting_le] ACME Output: ' . $acme_result); + drush_log('[hosting_le] ACME Output: ' . $acme_result); if (!provision_file()->exists($cert_dir)->status()) { $needs_update = FALSE; - drush_log("[provision_hosting_le] Error: The LE Certificate was not generated. This is probably a permissions issue.", 'error'); + drush_log("[hosting_le] Error: The LE Certificate was not generated. This is probably a permissions issue.", 'error'); return FALSE; } else { if (preg_match("/unchanged.*Skipping/i", $acme_result)) { $needs_update = FALSE; - drush_log("[provision_hosting_le] The existing LE Certificate is up to date in " . $cert_dir, 'success'); + drush_log("[hosting_le] The existing LE Certificate is up to date in " . $cert_dir, 'success'); } elseif (preg_match("/Forcing.*renew/i", $acme_result) && preg_match("/Creating.*fullchain/i", $acme_result)) { $needs_update = TRUE; - drush_log("[provision_hosting_le] The LE Certificate has been successfully updated in " . $cert_dir, 'success'); + drush_log("[hosting_le] The LE Certificate has been successfully updated in " . $cert_dir, 'success'); } elseif (preg_match("/Forcing.*renew/i", $acme_result) && !preg_match("/Creating.*fullchain/i", $acme_result)) { $needs_update = FALSE; - drush_log("[provision_hosting_le] The LE Certificate attempted update looks incomplete in " . $cert_dir, 'warning'); - drush_log("[provision_hosting_le] Make sure that all aliases have valid DNS names pointing to your instance IP address.", 'warning'); - drush_log("[provision_hosting_le] Aliases redirection must be disabled, or the LE agent will not be able to proceed.", 'warning'); - drush_log("[provision_hosting_le] The alternative is to disable SAN mode for this site with empty ctrl file: " . $no_san_ctrl, 'warning'); + drush_log("[hosting_le] The LE Certificate attempted update looks incomplete in " . $cert_dir, 'warning'); + drush_log("[hosting_le] Make sure that all aliases have valid DNS names pointing to your instance IP address.", 'warning'); + drush_log("[hosting_le] Aliases redirection must be disabled, or the LE agent will not be able to proceed.", 'warning'); + drush_log("[hosting_le] The alternative is to disable SAN mode for this site with empty ctrl file: " . $no_san_ctrl, 'warning'); } elseif (preg_match("/Requesting.*challenge/i", $acme_result) && !preg_match("/Forcing.*renew/i", $acme_result) && !preg_match("/Creating.*fullchain/i", $acme_result)) { $needs_update = FALSE; - drush_log("[provision_hosting_le] The LE Certificate attempted creation failed in " . $cert_dir, 'warning'); - drush_log("[provision_hosting_le] Make sure that all aliases have valid DNS names pointing to your instance IP address.", 'warning'); - drush_log("[provision_hosting_le] Aliases redirection must be disabled, or the LE agent will not be able to proceed.", 'warning'); - drush_log("[provision_hosting_le] The alternative is to disable SAN mode for this site with empty ctrl file: " . $no_san_ctrl, 'warning'); + drush_log("[hosting_le] The LE Certificate attempted creation failed in " . $cert_dir, 'warning'); + drush_log("[hosting_le] Make sure that all aliases have valid DNS names pointing to your instance IP address.", 'warning'); + drush_log("[hosting_le] Aliases redirection must be disabled, or the LE agent will not be able to proceed.", 'warning'); + drush_log("[hosting_le] The alternative is to disable SAN mode for this site with empty ctrl file: " . $no_san_ctrl, 'warning'); } else { $needs_update = TRUE; - drush_log("[provision_hosting_le] The LE Certificate has been successfully [re]generated in " . $cert_dir, 'success'); + drush_log("[hosting_le] The LE Certificate has been successfully [re]generated in " . $cert_dir, 'success'); } } } @@ -205,39 +203,39 @@ function drush_provision_hosting_le_post_provision_verify() { exec("/bin/bash " . $le_exec . " -gc", $output_clean); $acme_result_clean = implode(' ', $output_clean); - drush_log('[provision_hosting_le] ACME Cleanup Output: ' . $acme_result_clean); + drush_log('[hosting_le] ACME Cleanup Output: ' . $acme_result_clean); $ssl_symlinks[] = d('@server_master')->aegir_root . "/config/ssl.d/" . $sitename; $ssl_symlinks[] = d('@server_master')->aegir_root . "/config/server_master/ssl.d/" . $sitename; foreach ($ssl_symlinks as $symlink) { if (provision_file()->exists($symlink)->status()) { - drush_log('[provision_hosting_le] File exists: ' . $symlink); + drush_log('[hosting_le] File exists: ' . $symlink); if (!is_link($symlink)) { - drush_log('[provision_hosting_le] Moving original directory out of the way: ' . $symlink); + drush_log('[hosting_le] Moving original directory out of the way: ' . $symlink); // This will overwrite symlink.bak if necessary, so we don't end up // with dozens of backups of unused certificates. rename($symlink, $symlink . ".bak"); } else { - drush_log('[provision_hosting_le] SSL certificate already symlinked: ' . $symlink, 'success'); + drush_log('[hosting_le] SSL certificate already symlinked: ' . $symlink, 'success'); continue; } } - drush_log('[provision_hosting_le] Creating symlink at ' . $symlink); + drush_log('[hosting_le] Creating symlink at ' . $symlink); if (symlink($cert_dir, $symlink)) { - drush_log('[provision_hosting_le] Symlinked cert directory to ' . $symlink, 'success'); + drush_log('[hosting_le] Symlinked cert directory to ' . $symlink, 'success'); } else { - drush_log('[provision_hosting_le] Could not symlink cert directory to ' . $symlink, 'warning'); + drush_log('[hosting_le] Could not symlink cert directory to ' . $symlink, 'warning'); } } - drush_log('[provision_hosting_le] Replacing openssl symlinks.'); + drush_log('[hosting_le] Replacing openssl symlinks.'); $filenames = array( 'openssl.crt' => 'cert.pem', @@ -257,22 +255,22 @@ function drush_provision_hosting_le_post_provision_verify() { } if ($success) { - drush_log('[provision_hosting_le] Successfully replaced all symlinks.', 'success'); + drush_log('[hosting_le] Successfully replaced all symlinks.', 'success'); } else { - drush_log('[provision_hosting_le] Could not replace one or more symlinks. Check ' . $certdir, 'warning'); + drush_log('[hosting_le] Could not replace one or more symlinks. Check ' . $certdir, 'warning'); } $pid = $le_ctrl . "/" . $sitename . ".pid"; if ($sitename != 'hostmaster' && file_exists($cert_dir) && !file_exists($pid)) { provision_file()->file_put_contents($pid, $sitename) - ->succeed('[provision_hosting_le] Created pid ' . $pid) - ->fail('[provision_hosting_le] Could not create pid ' . $pid); + ->succeed('[hosting_le] Created pid ' . $pid) + ->fail('[hosting_le] Could not create pid ' . $pid); // We will not run the secondary Verify if pid file doesn't exist, // to avoid verify-inside-verify loop which could overload the system. if (provision_file()->exists($pid)->status()) { - drush_log('[provision_hosting_le] Running Verify again to reload web server once openssl_chain.crt is present in the vhost'); + drush_log('[hosting_le] Running Verify again to reload web server once openssl_chain.crt is present in the vhost'); $local_uri_verify = '@' . $sitename; provision_backend_invoke($local_uri_verify, 'provision-verify'); // We could run it via frontend but it is not needed currently. @@ -282,7 +280,7 @@ function drush_provision_hosting_le_post_provision_verify() { } $http_reload = d('@server_master')->http_restart_cmd; - drush_log('[provision_hosting_le] Running ' . $http_reload); + drush_log('[hosting_le] Running ' . $http_reload); shell_exec($http_reload); } } diff --git a/hosting_le.drush.inc b/hosting_le.drush.inc deleted file mode 100644 index 1b980a5..0000000 --- a/hosting_le.drush.inc +++ /dev/null @@ -1,23 +0,0 @@ -ref) && !empty($task->ref)) { - // $task->context_options['site_data'] = $task->ref->site_data; - // ddl($task->ref); - } -} - -/** - * Implements hook_drush_context_import(). - */ -function hosting_le_drush_context_import($context, &$node) { - drush_log('[hosting_le] Context import'); - // if ($context->type == 'site') { - // if (isset($context->site_data) && !empty($context->site_data)) { - // $node->site_data = $context->site_data; - // } - // } -} diff --git a/hosting_le_vhost/drush/Provision/Service/Le.php b/hosting_le_vhost/drush/Provision/Service/Le.php new file mode 100644 index 0000000..43814d0 --- /dev/null +++ b/hosting_le_vhost/drush/Provision/Service/Le.php @@ -0,0 +1,10 @@ + NULL); +} + +/* + * Implementation of hook_provision_nginx_vhost_config() + */ +function hosting_le_vhost_provision_nginx_vhost_config($uri, $data) { + + $aegir_root = d('@server_master')->aegir_root; + + if (d()->type == 'site' && d()->ssl_enabled) { + + $lines = array(); + + $lines[] = ""; + $lines[] = " ###"; + $lines[] = " ### Allow access to letsencrypt.org ACME challenges directory."; + $lines[] = " ###"; + $lines[] = " location ^~ /.well-known/acme-challenge {"; + $lines[] = " alias $aegir_root/tools/le/.acme-challenges;"; + $lines[] = " try_files \$uri 404;"; + $lines[] = " }"; + $lines[] = "\n"; + + return implode("\n", $lines); + } + + return ''; +} + +/* + * Implementation of hook_provision_apache_vhost_config() + */ +function hosting_le_vhost_provision_apache_vhost_config($uri, $data) { + + $aegir_root = d('@server_master')->aegir_root; + + if (d()->type == 'site' && d()->ssl_enabled) { + + $lines = array(); + + $lines[] = ""; + $lines[] = " Alias /.well-known/acme-challenge $aegir_root/tools/le/.acme-challenges"; + $lines[] = ""; + $lines[] = " # Allow access to letsencrypt.org ACME challenges directory."; + $lines[] = " "; + $lines[] = " Require all granted"; + $lines[] = " "; + $lines[] = "\n"; + + return implode("\n", $lines); + } + + return ''; +} diff --git a/hosting_le_vhost/hosting.feature.le_vhost.inc b/hosting_le_vhost/hosting.feature.le_vhost.inc new file mode 100644 index 0000000..b5859c6 --- /dev/null +++ b/hosting_le_vhost/hosting.feature.le_vhost.inc @@ -0,0 +1,22 @@ + t('Hosting LE Vhost'), + 'description' => t("Extends vhosts with ACME challenge paths for Let's Encrypt."), + 'status' => HOSTING_FEATURE_DISABLED, + 'module' => 'hosting_le_vhost', + 'group' => 'experimental', + ); + return $features; +} diff --git a/hosting_le_vhost/hosting_le_vhost.info b/hosting_le_vhost/hosting_le_vhost.info new file mode 100644 index 0000000..4fd14d1 --- /dev/null +++ b/hosting_le_vhost/hosting_le_vhost.info @@ -0,0 +1,6 @@ +name = Hosting LE Vhost +description = Extends vhosts with ACME challenge paths for Let's Encrypt +package = Hosting +dependencies[] = hosting_ssl +dependencies[] = hosting_le +core = 7.x diff --git a/hosting_le_vhost/hosting_le_vhost.module b/hosting_le_vhost/hosting_le_vhost.module new file mode 100644 index 0000000..a4abe2d --- /dev/null +++ b/hosting_le_vhost/hosting_le_vhost.module @@ -0,0 +1,2 @@ +