From b2f07de1848ecf13cfeda07db73f9dfb0aa35fea Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 01:25:13 +0200 Subject: [PATCH 01/45] reformat code --- wo/cli/main.py | 4 +++- wo/cli/plugins/stack.py | 3 +-- wo/cli/plugins/stack_migrate.py | 4 ++-- wo/core/aptget.py | 16 +++++++++------- wo/core/cron.py | 29 ++++++++++++++--------------- wo/core/download.py | 3 ++- wo/core/exc.py | 1 + wo/core/fileutils.py | 4 ++-- wo/core/mysql.py | 17 +++++++++++------ wo/core/variables.py | 7 ++++--- 10 files changed, 49 insertions(+), 39 deletions(-) diff --git a/wo/cli/main.py b/wo/cli/main.py index e8d9812..230257d 100644 --- a/wo/cli/main.py +++ b/wo/cli/main.py @@ -86,7 +86,8 @@ def main(): # if not root...kick out if not os.geteuid() == 0: - print("\nNon-privileged users cant use WordOps. Switch to root or invoke sudo.\n") + print("\nNon-privileged users cant use WordOps. " + "Switch to root or invoke sudo.\n") app.close(1) # Setup the application @@ -130,5 +131,6 @@ def get_test_app(**kw): app = WOApp(**kw) return app + if __name__ == '__main__': main() diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 00ea021..38160c0 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1,7 +1,7 @@ """Stack Plugin for WordOps""" from cement.core.controller import CementBaseController, expose -from cement.core import handler, hook +from cement.core import handler from wo.cli.plugins.site_functions import * from wo.core.variables import WOVariables from wo.core.aptget import WOAptGet @@ -20,7 +20,6 @@ from wo.core.variables import WOVariables import random import string import configparser -import time import shutil import os import pwd diff --git a/wo/cli/plugins/stack_migrate.py b/wo/cli/plugins/stack_migrate.py index 058d076..38bb394 100644 --- a/wo/cli/plugins/stack_migrate.py +++ b/wo/cli/plugins/stack_migrate.py @@ -100,8 +100,8 @@ class WOStackMigrateController(CementBaseController): Log.error( self, "Remote MySQL server in use, skipping local install") - if WOShellExec.cmd_exec(self, "mysqladmin ping") and (not - WOAptGet.is_installed(self, 'mariadb-server')): + if (WOShellExec.cmd_exec(self, "mysqladmin ping") and + (not WOAptGet.is_installed(self, 'mariadb-server'))): Log.info(self, "If your database size is big, " "migration may take some time.") diff --git a/wo/core/aptget.py b/wo/core/aptget.py index 7c274cf..bacaef4 100644 --- a/wo/core/aptget.py +++ b/wo/core/aptget.py @@ -36,7 +36,8 @@ class WOAptGet(): for single_error in error_list: if "NO_PUBKEY" in single_error: key = single_error.rsplit(None, 1)[-1] - WORepo.add_key(self, key, keyserver="hkp://pgp.mit.edu") + WORepo.add_key( + self, key, keyserver="hkp://pgp.mit.edu") proc = subprocess.Popen('apt-get update', shell=True, @@ -47,7 +48,8 @@ class WOAptGet(): if proc.returncode == 0: return True else: - Log.info(self, Log.FAIL + "Whoops, something went wrong...") + Log.info(self, Log.FAIL + + "Whoops, something went wrong...") Log.error(self, "Check the WordOps log for more details " "`tail /var/log/wo/wordops.log` and please try again...") @@ -60,7 +62,7 @@ class WOAptGet(): """ try: check_update = subprocess.Popen(['apt-get upgrade -s | grep ' - '\"^Inst\" | wc -l'], + '\"^Inst\" | wc -l'], stdout=subprocess.PIPE, shell=True).communicate()[0] if check_update == b'0\n': @@ -190,13 +192,13 @@ class WOAptGet(): apt_cache = apt.cache.Cache() apt_cache.open() if (package_name.strip() in apt_cache and - apt_cache[package_name.strip()].is_installed): + apt_cache[package_name.strip()].is_installed): # apt_cache.close() return True # apt_cache.close() return False - def download_only(self,package_name,repo_url=None,repo_key=None): + def download_only(self, package_name, repo_url=None, repo_key=None): """ Similar to `apt-get install --download-only PACKAGE_NAME` """ @@ -221,11 +223,11 @@ class WOAptGet(): if proc.returncode == 0: return True else: - Log.error(self,"Error in fetching dpkg package.\nReverting changes ..",False) + Log.error( + self, "Error in fetching dpkg package.\nReverting changes ..", False) if repo_url is not None: WORepo.remove(self, repo_url=repo_url) return False except Exception as e: Log.error(self, "Error while downloading packages, " "apt-get exited with error") - diff --git a/wo/core/cron.py b/wo/core/cron.py index 2392ad4..abd3bd6 100644 --- a/wo/core/cron.py +++ b/wo/core/cron.py @@ -5,28 +5,27 @@ from wo.core.logging import Log Set CRON on LINUX system. """ + class WOCron(): - def setcron_weekly(self,cmd,comment='Cron set by WordOps',user='root',min=0,hour=12): + def setcron_weekly(self, cmd, comment='Cron set by WordOps', user='root', min=0, hour=12): if not WOShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)): WOShellExec.cmd_exec(self, "/bin/bash -c \"crontab -l " - "2> /dev/null | {{ cat; echo -e" - " \\\"" - "\\n0 0 * * 0 " - "{0}".format(cmd) + - " # {0}".format(comment)+ - "\\\"; } | crontab -\"") + "2> /dev/null | {{ cat; echo -e" + " \\\"" + "\\n0 0 * * 0 " + "{0}".format(cmd) + + " # {0}".format(comment) + + "\\\"; } | crontab -\"") Log.debug(self, "Cron set") - - - def remove_cron(self,cmd): + def remove_cron(self, cmd): if WOShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)): if not WOShellExec.cmd_exec(self, "/bin/bash -c " - "\"crontab " - "-l | sed '/{0}/d'" - "| crontab -\"" - .format(cmd)): - Log.error(self, "Failed to remove crontab entry",False) + "\"crontab " + "-l | sed '/{0}/d'" + "| crontab -\"" + .format(cmd)): + Log.error(self, "Failed to remove crontab entry", False) else: Log.debug(self, "Cron not found") diff --git a/wo/core/download.py b/wo/core/download.py index ef94d4f..36d3d7a 100644 --- a/wo/core/download.py +++ b/wo/core/download.py @@ -22,7 +22,8 @@ class WODownload(): if not os.path.exists(directory): os.makedirs(directory) Log.info(self, "Downloading {0:20}".format(pkg_name), end=' ') - req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) + req = urllib.request.Request( + url, headers={'User-Agent': 'Mozilla/5.0'}) with urllib.request.urlopen(req) as response, open(filename, 'wb') as out_file: out_file.write(response.read()) Log.info(self, "{0}".format("[" + Log.ENDC + "Done" diff --git a/wo/core/exc.py b/wo/core/exc.py index 67e968f..02c03dc 100644 --- a/wo/core/exc.py +++ b/wo/core/exc.py @@ -3,6 +3,7 @@ class WOError(Exception): """Generic errors.""" + def __init__(self, msg): Exception.__init__(self) self.msg = msg diff --git a/wo/core/fileutils.py b/wo/core/fileutils.py index a6032b8..a7a4c29 100644 --- a/wo/core/fileutils.py +++ b/wo/core/fileutils.py @@ -21,14 +21,14 @@ class WOFileUtils(): Log.info(self, "Removing {0:65}".format(file), end=' ') os.remove(file) Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + - Log.OKBLUE + "]")) + Log.OKBLUE + "]")) Log.debug(self, 'file Removed') if os.path.isdir(file): try: Log.info(self, "Removing {0:65}".format(file), end=' ') shutil.rmtree(file) Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + - Log.OKBLUE + "]")) + Log.OKBLUE + "]")) except shutil.Error as e: Log.debug(self, "{err}".format(err=str(e.reason))) Log.error(self, 'Unable to Remove file ') diff --git a/wo/core/mysql.py b/wo/core/mysql.py index 92a1c5e..6b1f115 100644 --- a/wo/core/mysql.py +++ b/wo/core/mysql.py @@ -28,10 +28,12 @@ class WOMysql(): """Method for MySQL connection""" def connect(self): - """Makes connection with MySQL server""" + # Makes connection with MySQL server try: if os.path.exists('/etc/mysql/conf.d/my.cnf'): - connection = pymysql.connect(read_default_file='/etc/mysql/conf.d/my.cnf') + connection = \ + pymysql.connect(read_default_file='/etc/mysql/' + 'conf.d/my.cnf') else: connection = pymysql.connect(read_default_file='~/.my.cnf') return connection @@ -45,9 +47,11 @@ class WOMysql(): def dbConnection(self, db_name): try: if os.path.exists('/etc/mysql/conf.d/my.cnf'): - connection = pymysql.connect(db=db_name,read_default_file='/etc/mysql/conf.d/my.cnf') + connection = pymysql.connect( + db=db_name, read_default_file='/etc/mysql/conf.d/my.cnf') else: - connection = pymysql.connect(db=db_name,read_default_file='~/.my.cnf') + connection = pymysql.connect( + db=db_name, read_default_file='~/.my.cnf') return connection except DatabaseError as e: @@ -58,12 +62,13 @@ class WOMysql(): except pymysql.err.InternalError as e: Log.debug(self, str(e)) raise MySQLConnectionError - except Exception as e : + except Exception as e: Log.debug(self, "[Error]Setting up database: \'" + str(e) + "\'") raise MySQLConnectionError def execute(self, statement, errormsg='', log=True): - """Get login details from /etc/mysql/conf.d/my.cnf & Execute MySQL query""" + # Get login details from /etc/mysql/conf.d/my.cnf + # & Execute MySQL query connection = WOMysql.connect(self) log and Log.debug(self, "Exceuting MySQL Statement : {0}" .format(statement)) diff --git a/wo/core/variables.py b/wo/core/variables.py index 74c4cec..054ef53 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -3,7 +3,6 @@ import platform import socket import configparser import os -import sys import psutil import datetime @@ -149,11 +148,13 @@ class WOVariables(): # MySQL repo and packages if wo_platform_distro == 'ubuntu': - wo_mysql_repo = ("deb [arch=amd64,ppc64el] http://sfo1.mirrors.digitalocean.com/mariadb/repo/" + wo_mysql_repo = ("deb [arch=amd64,ppc64el] " + "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/ubuntu {codename} main" .format(codename=wo_platform_codename)) elif wo_platform_distro == 'debian': - wo_mysql_repo = ("deb [arch=amd64,ppc64el] http://sfo1.mirrors.digitalocean.com/mariadb/repo/" + wo_mysql_repo = ("deb [arch=amd64,ppc64el] " + "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/debian {codename} main" .format(codename=wo_platform_codename)) From 739f1bc0f877e8105e58f6699cafc4bde5f933be Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 01:34:33 +0200 Subject: [PATCH 02/45] fix hook --- wo/cli/plugins/stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 38160c0..eab3f5c 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1,7 +1,7 @@ """Stack Plugin for WordOps""" from cement.core.controller import CementBaseController, expose -from cement.core import handler +from cement.core import handler, hook from wo.cli.plugins.site_functions import * from wo.core.variables import WOVariables from wo.core.aptget import WOAptGet From 4ac9a5f4fec102111018fcfd797b82fd4b13b29a Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 01:38:14 +0200 Subject: [PATCH 03/45] add fail2ban --- smtp-cli.pl | 1074 ------------------------------ wo/cli/plugins/stack.py | 28 + wo/cli/plugins/stack_services.py | 43 +- 3 files changed, 67 insertions(+), 1078 deletions(-) delete mode 100644 smtp-cli.pl diff --git a/smtp-cli.pl b/smtp-cli.pl deleted file mode 100644 index 0eeb426..0000000 --- a/smtp-cli.pl +++ /dev/null @@ -1,1074 +0,0 @@ -#!/usr/bin/perl - -# -# Command line SMTP client with SSL, STARTTLS, SMTP-AUTH and IPv6 support. -# Michal Ludvig, 2003-2018 -# See http://smtp-cli.logix.cz for details -# and https://github.com/mludvig/smtp-cli for code. -# Thanks to all contributors for ideas and fixes! -# - -my $version = "3.9"; - -# -# ChangeLog: -# * Version 3.9 (2018-04-06) -# - Don't attempt to use IO::Socket::INET6 with --ipv4. -# -# * Version 3.8 (2017-07-05) -# - New parameter --local-addr -# - Support body and attachment reading from non-regular files -# - Various protocol fixes -# -# * Version 3.7 (2014-11-21) -# - Support STDIN input with --body-plain=- or --body-html=- -# -# * Version 3.6 (2013-07-11) -# - Improved compatibility with perl < 5.10 and perl >= 5.18 -# - Added support for more chars in user-part of email address. -# -# * Version 3.5 (2013-05-08) -# - Improved compliance with SMTP RFC 5321 -# - New parameter --text-encoding -# -# * Version 3.4 (2013-02-05) -# - Ok, ok, support both File::Type and File::LibMagic -# -# * Version 3.3 (2012-07-30) -# - Moved from File::Type to File::LibMagic -# (File::Type is no longer maintained and not available -# in EPEL for RHEL 6) -# -# * Version 3.2 (2012-06-26) -# - Fixed syntax error -# -# * Version 3.1 (2012-06-25) -# - New --add-header, --replace-header and --remove-header options. -# - Improved compatibility with new IO::Socket::SSL releases. -# -# * Version 3.0 (2012-01-24) -# - Support for server SSL verification agains CA root cert. -# - Use "Content-Disposition: attachment" for all attachments -# unless --attach-inline was used. -# - No longer default to --server=localhost -# - Support for --charset= affecting all text/* parts. -# - Ensure "To: undisclosed-recipients:;" if sending only to Bcc. -# -# * Version 2.9 (2011-09-02) -# - Fixed problem when using IPv6 addresses with --server. -# For example with --server 2001:db8::123 it was connecting -# to server 2001:db8:: port 123. Fixed now. -# -# * Version 2.8 (2011-01-05) -# - Added --ssl to support for SSMTP (SMTP over SSL). This is -# turned on by default when --port=465. -# -# * Version 2.7 (2010-09-08) -# - Added support for Cc header (--cc=...) -# - Addressess (From, To, Cc) can now contain a "display name", -# for example --from="Michal Ludvig " -# - Support for --mail-from and --rcpt-to addresses independent -# on --from, --to, --cc and --bcc -# - Fixed warnings in Perl 5.12 -# -# * Version 2.6 (2009-08-05) -# - Message building fixed for plaintext+attachment case. -# - Auto-enable AUTH as soon as --user parameter is used. -# (previously --enable-auth or --auth-plain had to be used -# together with --user, that was confusing). -# - New --print-only parameter for displaying the composed -# MIME message without sending. -# - All(?) non-standard modules are now optional. -# - Displays local and remote address on successfull connect. -# -# * Version 2.5 (2009-07-21) -# - IPv6 support provided the required modules are -# available. -# -# * Version 2.1 (2008-12-08) -# - Make the MIME modules optional. Simply disable -# the required functionality if they're not available. -# -# * Version 2.0 (2008-11-18) -# - Support for message building through MIME::Lite, -# including attachments, multipart, etc. -# -# * Version 1.1 (2006-08-26) -# - STARTTLS and AUTH support -# -# * Version 1.0 -# - First public version -# -# This program is licensed under GNU Public License v3 (GPLv3) -# - -## Require Perl 5.8 or higher -> we need open(.., .., \$variable) construct -require 5.008; - -use strict; -use IO::Socket::INET; -use MIME::Base64 qw(encode_base64 decode_base64); -use Getopt::Long; -use Socket qw(:DEFAULT :crlf); - -my @valid_encodings = ("7bit", "8bit", "binary", "base64", "quoted-printable"); - -my ($user, $pass, $host, $port, $addr_family, $localaddr, - $use_login, $use_plain, $use_cram_md5, - $ehlo_ok, $auth_ok, $starttls_ok, $ssl, $verbose, - $hello_host, $datasrc, - $mail_from, @rcpt_to, $from, @to, @cc, @bcc, - $missing_modules_ok, $missing_modules_count, - $subject, $body_plain, $body_html, $charset, $text_encoding, $print_only, - @attachments, @attachments_inline, - @add_headers, @replace_headers, @remove_headers, - $ssl_ca_file, $ssl_ca_path, - $sock, $built_message); - -$host = undef; -$port = 'smtp(25)'; -$addr_family = AF_UNSPEC; -$localaddr = undef; -$hello_host = 'localhost'; -$verbose = 0; -$use_login = 0; -$use_plain = 0; -$use_cram_md5 = 0; -$starttls_ok = 1; -$ssl = undef; -$auth_ok = 0; -$ehlo_ok = 1; -$missing_modules_ok = 0; -$missing_modules_count = 0; -$charset = undef; -$text_encoding = "quoted-printable"; -$print_only = 0; - -# Get command line options. -GetOptions ( - 'host|server=s' => \$host, - 'port=i' => \$port, - '4|ipv4' => sub { $addr_family = AF_INET; }, - '6|ipv6' => sub { $addr_family = AF_INET6; }, - 'local-addr=s' => \$localaddr, - 'user=s' => \$user, 'password=s' => \$pass, - 'auth-login' => \$use_login, - 'auth-plain' => \$use_plain, - 'auth-cram-md5' => \$use_cram_md5, - 'disable-ehlo' => sub { $ehlo_ok = 0; }, - 'force-ehlo' => sub { $ehlo_ok = 2; }, - 'hello-host|ehlo-host|helo-host=s' => \$hello_host, - 'auth|enable-auth' => \$auth_ok, - 'disable-starttls|disable-tls|disable-ssl' => - sub { $starttls_ok = 0; }, - 'ssl' => sub { $ssl = 1 }, - 'disable-ssl' => sub { $ssl = 0 }, - 'mail-from=s' => \$mail_from, - 'rcpt-to=s' => \@rcpt_to, - 'from=s' => \$from, - 'to=s' => \@to, - 'cc=s' => \@cc, - 'bcc=s' => \@bcc, - 'data=s' => \$datasrc, - 'subject=s' => \$subject, - 'body|body-plain=s' => \$body_plain, - 'body-html=s' => \$body_html, - 'charset=s' => \$charset, - 'text-encoding=s' => \$text_encoding, - 'attachment|attach=s' => \@attachments, - 'attachment-inline|attach-inline=s' => \@attachments_inline, - 'add-header=s' => \@add_headers, - 'replace-header=s' => \@replace_headers, - 'remove-header=s' => \@remove_headers, - 'print-only' => \$print_only, - 'missing-modules-ok' => \$missing_modules_ok, - 'ssl-ca-file=s' => \$ssl_ca_file, - 'ssl-ca-path=s' => \$ssl_ca_path, - 'v|verbose+' => \$verbose, - 'version' => sub { &version() }, - 'help' => sub { &usage() } ); - -#### Try to load optional modules - -## IO::Socket::SSL and Net::SSLeay are optional -my $have_ssl = eval { require IO::Socket::SSL; require Net::SSLeay; 1; }; -if (not $have_ssl and not $missing_modules_ok) { - warn("!!! IO::Socket::SSL and/or Net::SSLeay modules are not found\n"); - warn("!!! These modules are required for SSL and STARTTLS support\n"); - $missing_modules_count += 2; -} - -## IO::Socket::INET6 and Socket6 are optional -my $socket6 = eval { require IO::Socket::INET6; require Socket6; 1; }; -if (not $socket6 and not ($addr_family == AF_INET)) { - if ($addr_family == AF_INET6) { - die("!!! IO::Socket::INET6 and Socket6 modules are not found\nIPv6 support is not available\n"); - } - if (not $missing_modules_ok) { - warn("!!! IO::Socket::INET6 -- optional module not found\n"); - warn("!!! Socket6 -- optional module not found\n"); - warn("!!! These modules are required for IPv6 support\n\n"); - $missing_modules_count += 2; - } -} - -## MIME::Lite dependency is optional -my $mime_lite = eval { require MIME::Lite; 1; }; -if (not $mime_lite and not $missing_modules_ok) { - warn("!!! MIME::Lite -- optional module not found\n"); - warn("!!! Used for composing messages from --subject, --body, --attachment, etc.\n\n"); - $missing_modules_count++; -} - -## File::LibMagic dependency is optional -my $file_libmagic = eval { require File::LibMagic; File::LibMagic->new(); }; - -## File::Type dependency is optional -## Not needed if File::LibMagic is available -my $file_type = eval { require File::Type; File::Type->new(); }; - -if (not $file_libmagic and not $file_type and not $missing_modules_ok) { - warn("!!! Neither File::LibMagic nor File::Type module found.\n"); - warn("!!! Used for guessing MIME types of attachments. Optional.\n\n"); - $missing_modules_count++; -} - -## Term::ReadKey dependency is optional -my $have_term_readkey = eval { require Term::ReadKey; 1; }; -if (not $have_term_readkey and not $missing_modules_ok) { - warn("!!! Term::ReadKey -- optional module not found\n"); - warn("!!! Used for hidden reading SMTP password from the terminal\n\n"); - $missing_modules_count++; -} - -my $have_hmac_md5 = eval { require Digest::HMAC_MD5; 1; }; -if (not $have_hmac_md5 and not $missing_modules_ok) { - if ($use_cram_md5) { - die("!!! CRAM-MD5 authentication is not available because Digest::HMAC_MD5 module is missing\n"); - } - warn("!!! Digest::HMAC_MD5 -- optional module missing\n"); - warn("!!! Used for CRAM-MD5 authentication method\n"); - $missing_modules_count++; -} - -## Advise about --missing-modules-ok parameter -if ($missing_modules_count) { - warn("!!! Use --missing-modules-ok if you don't need the above listed modules\n"); - warn("!!! and don't want to see this message again.\n\n"); -} - -## Make sure we've got a server name to connect to -if (not defined($host)) { - if (not $print_only) { - die("Error: Specify the SMTP server with --server=hostname[:port]\n"); - } else { - # We're printing to stdout only, let's assign just about any - # hostname to satisfy the next few tests. - $host = "localhost"; - } -} - -## Make sure the --text-encoding value is valid -if (not grep(/^$text_encoding$/, @valid_encodings)) -{ - die ("The --text-encoding value is invalid: $text_encoding\nMust be one of: " . join(', ', @valid_encodings) . "\n"); -} - -## Accept hostname with port number as host:port -## Either it's a hostname:port or 1.2.3.4:port or [2001:db8::1]:port. -## Don't parse 2001:db8::1 as $host=2001:db8:: and $port=1! -if (($host =~ /^([^:]+):([:alnum:]+)$/) or - ($host =~ /^\[([[:xdigit:]:]+)\]:([:alnum:]+)$/)) -{ - $host = $1; - $port = $2; -} - -## Automatically start in SSL mode if port == 465 (SSMTP) -if (not defined($ssl)) { - $ssl = ($port == 465); -} - -# Extract $mail_from address from $from -if (not defined($mail_from) and defined($from)) { - $mail_from = &find_email_addr($from) or - die ("The --from string does not contain a valid email address: $from\n"); -} - -# Extract @rcpt_to list from @to, @cc and @bcc -if (not @rcpt_to) { - foreach my $rcpt (@to, @cc, @bcc) { - my $rcpt_addr = &find_email_addr($rcpt); - if (not defined($rcpt_addr)) { - warn("No valid email address found in: $rcpt\n"); - next; - } - push(@rcpt_to, $rcpt_addr); - } -} - -# Ensure "To: undisclosed-recipients:;" when sending only to Bcc's -if (not @to and not @cc) { - push(@to, "undisclosed-recipients:;"); -} - -# Build the MIME message if required -if (defined($subject) or defined($body_plain) or defined($body_html) or - @attachments or @attachments_inline) { - if (not $mime_lite) { - die("Module MIME::Lite is not available. Unable to build the message, sorry.\n". - "Use --data and provide a complete email payload including headers instead.\n"); - } - if (defined($datasrc)) { - die("Requested building a message and at the same time used --data parameter.\n". - "That's not possible, sorry.\n"); - } - if (defined($body_plain)) { - if (-e $body_plain) { - local $/=undef; - open(FILE, $body_plain); - $body_plain = ; - close(FILE); - } elsif ($body_plain eq "-") { - local $/=undef; - $body_plain = ; - } - } - if (defined($body_html)) { - if (-e $body_html) { - local $/=undef; - open(FILE, $body_html); - $body_html = ; - close(FILE); - } elsif ($body_html eq "-") { - local $/=undef; - $body_html = ; - } - } - my $message = &build_message(); - - open(BUILT_MESSAGE, "+>", \$built_message); - $datasrc = "///built_message"; - if ($print_only) { - $message->print(); - exit(0); - } else { - $message->print(\*BUILT_MESSAGE); - } - seek(BUILT_MESSAGE, 0, 0); -} - -# Username was given -> enable AUTH -if ($user) - { $auth_ok = 1; } - -# If at least one --auth-* option was given, enable AUTH. -if ($use_login + $use_plain + $use_cram_md5 > 0) - { $auth_ok = 1; } - -# If --enable-auth was given, enable all AUTH methods. -elsif ($auth_ok && ($use_login + $use_plain + $use_cram_md5 == 0)) -{ - $use_login = 1; - $use_plain = 1; - $use_cram_md5 = 1 if ($have_hmac_md5); -} - -# Exit if user haven't specified username for AUTH. -if ($auth_ok && !defined ($user)) - { die ("SMTP AUTH support requested without --user\n"); } - -# Ask for password if it wasn't supplied on the command line. -if ($auth_ok && defined ($user) && !defined ($pass)) -{ - if ($have_term_readkey) { - # Set echo off. - Term::ReadKey::ReadMode (2); - } else { - warn ("Module Term::ReadKey not available - password WILL NOT be hidden!!!\n"); - } - printf ("Enter password for %s@%s : ", $user, $host); - $pass = <>; - if ($have_term_readkey) { - # Restore echo. - Term::ReadKey::ReadMode (0); - printf ("\n"); - } - exit if (! defined ($pass)); - chop ($pass); -} - -# Connect to the SMTP server. -my %connect_args = ( - PeerAddr => $host, - PeerPort => $port, - Proto => 'tcp', - Timeout => 5); - -if (defined($localaddr)) { - $connect_args{'LocalAddr'} = $localaddr; -} - -if ($addr_family == AF_INET) { - # If the user requested --ipv4 don't even bother with INET6 module - # (although it should work some users reported problems) - $sock = IO::Socket::INET->new(%connect_args) or die ("Connect failed: $@\n"); -} else { - # Either --ipv6 or no preference - do the best we can - $connect_args{'Domain'} = $addr_family; - $sock = IO::Socket::INET6->new(%connect_args) or die ("Connect failed: $@\n"); -} - -if ($verbose >= 1) { - my $addr_fmt = "%s"; - $addr_fmt = "[%s]" if ($sock->sockhost() =~ /:/); ## IPv6 connection - - printf ("Connection from $addr_fmt:%s to $addr_fmt:%s\n", - $sock->sockhost(), $sock->sockport(), - $sock->peerhost(), $sock->peerport()); -} - -if ($ssl) { - printf ("Starting SMTP/SSL...\n") if ($verbose >= 1); - &socket_to_ssl($sock); -} - -my ($code, $text); -my (%features); - -# Wait for the welcome message of the server. -($code, $text) = &get_line ($sock); -die ("Unknown welcome string: '$code $text'\n") if ($code != 220); -$ehlo_ok-- if ($text !~ /ESMTP/); - -# Send EHLO -&say_hello ($sock, $ehlo_ok, $hello_host, \%features) or exit (1); - -# Run the SMTP session -my $exitcode = &run_smtp (); - -# Good bye... -&send_line ($sock, "QUIT\n"); -($code, $text) = &get_line ($sock); -die ("Unknown QUIT response '$code'.\n") if ($code != 221); - -exit $exitcode; - -# This is the main SMTP "engine". -sub run_smtp -{ - # See if we could start encryption - if ((defined ($features{'STARTTLS'}) || defined ($features{'TLS'})) && $starttls_ok && !$have_ssl) - { - warn ("Module IO::Socket::SSL is missing - STARTTLS support disabled.\n"); - warn ("Use --disable-starttls or install the modules to avoid this warning.\n"); - undef ($features{'STARTTLS'}); - undef ($features{'TLS'}); - } - - if ((defined ($features{'STARTTLS'}) || defined ($features{'TLS'})) && $starttls_ok) - { - printf ("Starting TLS...\n") if ($verbose >= 1); - - &send_line ($sock, "STARTTLS\n"); - ($code, $text) = &get_line ($sock); - die ("Unknown STARTTLS response '$code'.\n") if ($code != 220); - - &socket_to_ssl($sock); - - # Send EHLO again (required by the SMTP standard). - &say_hello ($sock, $ehlo_ok, $hello_host, \%features) or return 0; - } - - # See if we should authenticate ourself - if (defined ($features{'AUTH'}) && $auth_ok) - { - printf ("AUTH method (%s): ", $features{'AUTH'}) if ($verbose >= 1); - - ## Try DIGEST-MD5 first - # Actually we won't. It never worked reliably here. - # After all DIGEST-MD5 is on a way to deprecation - # see this thread: http://www.imc.org/ietf-sasl/mail-archive/msg02996.html - - # Instead use CRAM-MD5 if supported by the server - if ($features{'AUTH'} =~ /CRAM-MD5/i && $use_cram_md5) - { - printf ("using CRAM-MD5\n") if ($verbose >= 1); - &send_line ($sock, "AUTH CRAM-MD5\n"); - ($code, $text) = &get_line ($sock); - if ($code != 334) - { die ("AUTH CRAM-MD5 failed: $code $text\n"); } - - my $response = &encode_cram_md5 ($text, $user, $pass); - &send_line ($sock, "%s\n", $response); - ($code, $text) = &get_line ($sock); - if ($code != 235) - { die ("AUTH CRAM-MD5 failed: $code $text\n"); } - } - # Eventually try LOGIN method - elsif ($features{'AUTH'} =~ /LOGIN/i && $use_login) - { - printf ("using LOGIN\n") if ($verbose >= 1); - &send_line ($sock, "AUTH LOGIN\n"); - ($code, $text) = &get_line ($sock); - if ($code != 334) - { die ("AUTH LOGIN failed: $code $text\n"); } - - &send_line ($sock, "%s\n", encode_base64 ($user, "")); - - ($code, $text) = &get_line ($sock); - if ($code != 334) - { die ("AUTH LOGIN failed: $code $text\n"); } - - &send_line ($sock, "%s\n", encode_base64 ($pass, "")); - - ($code, $text) = &get_line ($sock); - if ($code != 235) - { die ("AUTH LOGIN failed: $code $text\n"); } - } - # Or finally PLAIN if nothing else was supported. - elsif ($features{'AUTH'} =~ /PLAIN/i && $use_plain) - { - printf ("using PLAIN\n") if ($verbose >= 1); - &send_line ($sock, "AUTH PLAIN %s\n", - encode_base64 ("$user\0$user\0$pass", "")); - ($code, $text) = &get_line ($sock); - if ($code != 235) - { die ("AUTH PLAIN failed: $code $text\n"); } - } - # Complain otherwise. - else - { - warn ("No supported authentication method\n". - "advertised by the server.\n"); - return 1; - } - - printf ("Authentication of $user\@$host succeeded\n") if ($verbose >= 1); - } - - # We can do a relay-test now if a recipient was set. - if ($#rcpt_to >= 0) - { - if (!defined ($mail_from)) - { - warn ("From: address not set. Using empty one.\n"); - $mail_from = ""; - } - &send_line ($sock, "MAIL FROM:<%s>\n", $mail_from); - ($code, $text) = &get_line ($sock); - if ($code != 250) - { - warn ("MAIL FROM <$mail_from> failed: '$code $text'\n"); - return 1; - } - - my $i; - for ($i=0; $i <= $#rcpt_to; $i++) - { - &send_line ($sock, "RCPT TO:<%s>\n", $rcpt_to[$i]); - ($code, $text) = &get_line ($sock); - if ($code != 250) - { - warn ("RCPT TO <".$rcpt_to[$i]."> ". - "failed: '$code $text'\n"); - return 0; - } - } - } - - # Wow, we should even send something! - if (defined ($datasrc)) - { - if ($datasrc eq "///built_message") - { - *MAIL = *BUILT_MESSAGE; - } - elsif ($datasrc eq "-") - { - *MAIL = *STDIN; - } - elsif (!open (MAIL, $datasrc)) - { - warn ("Can't open file '$datasrc'\n"); - return 0; - } - - &send_line ($sock, "DATA\n"); - ($code, $text) = &get_line ($sock); - if ($code != 354) - { - warn ("DATA failed: '$code $text'\n"); - return 0; - } - - while () - { - my $line = $_; - # RFC 5321 section 4.5.2 - leading dot must be doubled - $line =~ s/^\./\.\./; - # RFC 5321 section 2.3.8 - ensure CR-LF line ending - $line =~ s/[\r\n]+$/$CRLF/; - $sock->print ($line); - } - - close (MAIL); - - $sock->printf ("$CRLF.$CRLF"); - - ($code, $text) = &get_line ($sock); - if ($code != 250) - { - warn ("DATA not send: '$code $text'\n"); - return 0; - } - } - - # Perfect. Everything succeeded! - return 1; -} - -# Get one line of response from the server. -sub get_one_line ($) -{ - my $sock = shift; - my ($code, $sep, $text) = ($sock->getline() =~ /(\d+)(.)([^\r]*)/); - my $more; - $more = ($sep eq "-"); - if ($verbose) - { printf ("[%d] '%s'\n", $code, $text); } - return ($code, $text, $more); -} - -# Get concatenated lines of response from the server. -sub get_line ($) -{ - my $sock = shift; - my ($code, $text, $more) = &get_one_line ($sock); - while ($more) { - my ($code2, $line); - ($code2, $line, $more) = &get_one_line ($sock); - $text .= " $line"; - die ("Error code changed from $code to $code2. That's illegal.\n") if ($code ne $code2); - } - return ($code, $text); -} - -# Send one line back to the server -sub send_line ($@) -{ - my $socket = shift; - my @args = @_; - - if ($verbose) - { printf ("> "); printf (@args); } - $args[0] =~ s/\n/$CRLF/g; - $socket->printf (@args); -} - -sub socket_to_ssl($) -{ - if (!$have_ssl) { - die ("SSL/TLS support is not available due to missing modules. Sorry.\n"); - } - - # Do Net::SSLeay initialization - Net::SSLeay::load_error_strings(); - Net::SSLeay::SSLeay_add_ssl_algorithms(); - Net::SSLeay::randomize(); - - if (! IO::Socket::SSL->start_SSL($sock, { - SSL_ca_file => $ssl_ca_file, - SSL_ca_path => $ssl_ca_path, - SSL_verify_mode => (defined($ssl_ca_file) or defined($ssl_ca_path)) ? 0x01 : 0x00, - })) - { - die ("SSL/TLS: ".IO::Socket::SSL::errstr()."\n"); - } - - if ($verbose >= 1) - { - printf ("Using cipher: %s\n", $sock->get_cipher ()); - printf ("%s", $sock->dump_peer_certificate()); - } -} - -# Helper function to encode CRAM-MD5 challenge -sub encode_cram_md5 ($$$) -{ - my ($ticket64, $username, $password) = @_; - my $ticket = decode_base64($ticket64) or - die ("Unable to decode Base64 encoded string '$ticket64'\n"); - - print "Decoded CRAM-MD5 challenge: $ticket\n" if ($verbose > 1); - my $password_md5 = Digest::HMAC_MD5::hmac_md5_hex($ticket, $password); - return encode_base64 ("$username $password_md5", ""); -} - -# Store all server's ESMTP features to a hash. -sub say_hello ($$$$) -{ - my ($sock, $ehlo_ok, $hello_host, $featref) = @_; - my ($feat, $param); - my $hello_cmd = $ehlo_ok > 0 ? "EHLO" : "HELO"; - - &send_line ($sock, "$hello_cmd $hello_host\n"); - my ($code, $text, $more) = &get_one_line ($sock); - - if ($code != 250) - { - warn ("$hello_cmd failed: '$code $text'\n"); - return 0; - } - - # Empty the hash - %{$featref} = (); - - ($feat, $param) = ($text =~ /^(\w+)[= ]*(.*)$/); - $featref->{$feat} = $param; - - # Load all features presented by the server into the hash - while ($more == 1) - { - ($code, $text, $more) = &get_one_line ($sock); - ($feat, $param) = ($text =~ /^(\w+)[= ]*(.*)$/); - $featref->{$feat} = $param; - } - - return 1; -} - -sub find_email_addr($) -{ - my $addr = shift; - if ($addr =~ /([A-Z0-9._%=#+-]+@(?:[A-Z0-9-]+\.)+[A-Z]+)\b/i) { - return $1; - } - return undef; -} - -sub guess_mime_type($) -{ - my $filename = shift; - if (defined($file_libmagic)) { - ## Use File::LibMagic if possible - return $file_libmagic->checktype_filename($filename); - } elsif (defined($file_type)) { - ## Use File::Type if possible - return $file_type->mime_type($filename); - } else { - ## Module File::LibMagic is not available - ## Still recognise some common extensions - return "image/jpeg" if ($filename =~ /\.jpe?g/i); - return "image/gif" if ($filename =~ /\.gif/i); - return "image/png" if ($filename =~ /\.png/i); - return "text/plain" if ($filename =~ /\.txt/i); - return "application/zip" if ($filename =~ /\.zip/i); - return "application/x-gzip" if ($filename =~ /\.t?gz/i); - return "application/x-bzip" if ($filename =~ /\.t?bz2?/i); - } - return "application/octet-stream"; -} - -sub basename($) -{ - my $path = shift; - my @parts = split(/\//, $path); - return $parts[$#parts]; -} - -sub prepare_attachment($) -{ - my $attachment = shift; - my ($path, $mime_type); - - if (-e $attachment) { - $path = $attachment; - $mime_type = guess_mime_type($attachment); - } elsif ($attachment =~ /(.*)@([^@]*)$/ and -e $1) { - $path = $1; - $mime_type = $2; - } - return ($path, $mime_type); -} - -sub attach_attachments($$@) -{ - my $message = shift; - my $disposition = shift; - my @attachments = @_; - - foreach my $attachment (@attachments) { - my ($path, $mime_type) = prepare_attachment($attachment); - if (not defined($path)) { - warn("$attachment: File not found. Ignoring.\n"); - next; - } - $message->attach( - Type => $mime_type, - Path => $path, - Id => basename($path), - Disposition => $disposition, - ); - } -} - -sub safe_attach($$) -{ - my ($message, $part) = @_; - ## Remove some headers when $part is becoming a subpart of $message - $part->delete("Date"); - $part->delete("X-Mailer"); - $part->attr("MIME-Version" => undef); - $message->attach($part); - return $message; -} - -sub mime_message($$) -{ - my ($type, $data) = @_; - - ## Set QP encoding for text/* types, let MIME::Lite decide for all other types. - my $encoding = $type =~ /^text\// ? $text_encoding : undef; - my $message = MIME::Lite->new( - Type => $type, - Encoding=> $encoding, - Data => $data); - $message->attr('content-type.charset' => $charset) if (($type =~ /^text\//i) and defined($charset)); - return $message; -} - -sub build_message -{ - my ($part_plain, $part_html, $part_body, $message); - - if (@attachments_inline) { - if (not defined($body_html)) { - die("Inline attachments (--attach-inline) must be used with --body-html\n"); - } - $part_html = MIME::Lite->new(Type => 'multipart/related'); - $part_html->attach(Type => 'text/html', Data => $body_html); - attach_attachments($part_html, "inline", @attachments_inline); - $message = $part_html; - # undefine $body_html to prevent confusion in the next if() - undef($body_html); - } - - if (defined($body_html)) { - $part_html = mime_message('text/html', $body_html); - $message = $part_html; - } - - if (defined($body_plain)) { - $part_plain = mime_message('text/plain', $body_plain); - $message = $part_plain; - } - - if (defined($part_plain) and defined($part_html)) { - $part_body = mime_message("multipart/alternative", undef); - safe_attach($part_body, $part_plain); - safe_attach($part_body, $part_html); - $message = $part_body; - } - - if (@attachments) { - if (defined($message)) { - # We already have some plaintext and/or html content built - # => make it the first part of multipart/mixed - my $message_body = $message; - $message = mime_message("multipart/mixed", undef); - safe_attach($message, $message_body); - attach_attachments($message, "attachment", @attachments); - } elsif ($#attachments == 0) { - # Only one single attachment - let it be the body - my ($path, $mime_type) = prepare_attachment($attachments[0]); - if (not defined($path)) { - die($attachments[0].": File not found. No other message parts defined. Aborting.\n"); - } - $message = MIME::Lite->new( - Type => $mime_type, - Path => $path); - } else { - # Message consisting only of attachments - $message = mime_message("multipart/mixed", undef); - attach_attachments($message, "attachment", @attachments); - } - } - - # Last resort - empty plaintext message - if (!defined($message)) { - $message = mime_message("TEXT", ""); - } - - $message->replace("From" => $from); - $message->replace("To" => join(", ", @to)); - $message->replace("Cc" => join(", ", @cc)); - $message->replace("Subject" => $subject); - $message->replace("X-Mailer" => "smtp-cli $version, see http://smtp-cli.logix.cz"); - $message->replace("Message-ID" => "<".time()."-".int(rand(999999))."\@smtp-cli>"); - - for my $header (@add_headers) { - my ($hdr, $val) = ($header =~ /^([^:]+):\s*(.*)$/); - die("Not a valid header format: ${header}\n") if (not $hdr or not $val); - $message->add($hdr => $val); - } - for my $header (@replace_headers) { - my ($hdr, $val) = ($header =~ /^([^:]+):\s*(.*)$/); - die("Not a valid header format: ${header}\n") if (not $hdr or not $val); - $message->replace($hdr => $val); - } - for my $header (@remove_headers) { - my ($hdr) = ($header =~ /^([^:\s]+)/); - $message->replace($header => ""); - } - - return $message; -} - -sub version () -{ - print "smtp-cli version $version\n"; - exit (0); -} - -sub usage () -{ - printf ( -"Simple SMTP client written in Perl that supports advanced -features like STARTTLS and SMTP-AUTH and IPv6. It can also -create messages from components (files, text snippets) and -attach files. - -Version: smtp-cli v$version - -Author: Michal Ludvig (c) 2003-2017 - http://smtp-cli.logix.cz - -Usage: smtp-cli [--options] - - --server=[:] - Host name or IP address of the SMTP server. - May include the port after colon, alternatively - use --port. - --port= Port where the SMTP server is listening. - (default: 25) - -4 or --ipv4 Use standard IP (IPv4) protocol. - -6 or --ipv6 Use IPv6 protocol. For hosts that have - both IPv6 and IPv4 addresses the IPv6 - connection is tried first. - --local-addr=
Specify local address (by default the OS chooses) - - --hello-host= String to use in the EHLO/HELO command. - --disable-ehlo Don't use ESMTP EHLO command, only HELO. - --force-ehlo Use EHLO even if server doesn't say ESMTP. - - Transport encryption (TLS) - --disable-starttls Don't use encryption even if the remote - host offers it. - --ssl Start in SMTP/SSL mode (aka SSMTP). - Default when --port=465 - --disable-ssl Don't start SSMTP even if --port=465 - --ssl-ca-file= - Verify the server's SSL certificate against - a trusted CA root certificate file. - --ssl-ca-path= Similar to --ssl-ca-file but will look for - the appropriate root certificate file in - the given directory. The certificates must - must be stored one per file with hash-links - generated by, for example, c_rehash script - from OpenSSL. - - Authentication options (AUTH) - --user= Username for SMTP authentication. - --pass= Corresponding password. - --auth-login Enable only AUTH LOGIN method. - --auth-plain Enable only AUTH PLAIN method. - --auth-cram-md5 Enable only AUTH CRAM-MD5 method. - --auth Enable all supported methods. This is - normally not needed, --user enables - everything as well. - - Sender / recipient - --from=\"Display Name \" - Sender's name address (or address only). - --to=\"Display Name \" - --cc=\"Display Name \" - --bcc=\"Display Name \" - Message recipients. Each parameter can be - used multiple times. - The --bcc addresses won't apprear in - the composed message. - - SMTP Envelope sender / recipient - (rarely needed, use --from, --to, --cc and --bcc instead) - --mail-from=
Address to use in MAIL FROM command. - Use --from instead, unless you want - a different address in the envelope and - in the headers. - --rcpt-to=
Address to use in RCPT TO command. Can be - used multiple times. Normally not needed, - use --to, --cc and --bcc instead. - If set the --to, --cc and --bcc will only - be used for composing the message body and - not for delivering the messages. - - Send a complete RFC822-compliant email message: - --data= Name of file to send after DATA command. - With \"--data=-\" the script will read - standard input (useful e.g. for pipes). - - Alternatively build email a message from provided components: - --subject= Subject of the message - --body-plain= - --body-html= - Plaintext and/or HTML body of the message - If both are provided the message is sent - as multipart. - --charset= Character set used for Subject and Body, - for example UTF-8, ISO-8859-2, KOI8-R, etc. - --text-encoding= - Enforce Content-Transfer-Encoding for text - parts of the email, including body and - attachments. Must be one of: - ".join(", ", @valid_encodings)." - The default is: quoted-printable - --attach=[\@] - Attach a given filename. - MIME-Type of the attachment is guessed - by default guessed but can optionally - be specified after '\@' delimiter. - For instance: --attach mail.log\@text/plain - Parameter can be used multiple times. - --attach-inline=[\@] - Attach a given filename (typically a picture) - as a 'related' part to the above 'body-html'. - Refer to these pictures as - in the 'body-html' contents. - See --attach for details about MIME-Type. - Can be used multiple times. - --add-header=\"Header: value\" - --replace-header=\"Header: value\" - --remove-header=\"Header\" - Add, Replace or Remove pretty much any header - in the email. For example to set a different - Mailer use --replace-header=\"X-Mailer: Blah\", - to remove it altogether --remove-header=X-Mailer - or to add a completely custom header use - --add-header=\"X-Something: foo bar\". - --print-only Dump the composed MIME message to standard - output. This is useful mainly for debugging - or in the case you need to run the message - through some filter before sending. - - Other options - --verbose[=] Be more verbose, print the SMTP session. - --missing-modules-ok Don't complain about missing optional modules. - --version Print: smtp-cli version $version - --help Guess what is this option for ;-) - -PayPal donations: http://smtp-cli.logix.cz/donate - Thanks in advance for your support! - -"); - exit (0); -} diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index eab3f5c..1f2b330 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -71,6 +71,8 @@ class WOStackController(CementBaseController): dict(help='Install WordOps dashboard', action='store_true')), (['--adminer'], dict(help='Install Adminer stack', action='store_true')), + (['--fail2ban'], + dict(help='Install Fail2ban stack', action='store_true')), (['--utils'], dict(help='Install Utils stack', action='store_true')), (['--redis'], @@ -1014,6 +1016,23 @@ class WOStackController(CementBaseController): WOGit.add(self, ["/etc/mysql"], msg="Adding MySQL into Git") WOService.reload_service(self, 'mysql') + if set(WOVariables.wo_fail2ban).issubset(set(apt_packages)): + if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"): + data = dict() + Log.debug(self, "Setting up fail2ban jails configuration") + wo_fail2ban = open('/etc/fail2ban/jail.d/custom.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'fail2ban.mustache', + out=wo_fail2ban) + wo_fail2ban.close() + + Log.debug(self, "Setting up fail2ban wp filter") + wo_fail2ban = open('/etc/fail2ban/filter.d/wo-wordpress.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'fail2ban-wp.mustache', + out=wo_fail2ban) + wo_fail2ban.close() + if len(packages): if any('/usr/local/bin/wp' == x[1] for x in packages): Log.debug(self, "Setting Privileges" @@ -1441,6 +1460,15 @@ class WOStackController(CementBaseController): Log.debug(self, "WP-CLI is already installed") Log.info(self, "WP-CLI is already installed") + # fail2ban + if self.app.pargs.fail2ban: + Log.debug(self, "Setting apt_packages variable for Fail2ban") + if not WOAptGet.is_installed(self, 'fail2ban'): + apt_packages = apt_packages + WOVariables.wo_fail2ban + else: + Log.debug(self, "Fail2ban already installed") + Log.info(self, "Fail2ban already installed") + # PHPMYADMIN if self.app.pargs.phpmyadmin: Log.debug(self, "Setting packages variable for phpMyAdmin ") diff --git a/wo/cli/plugins/stack_services.py b/wo/cli/plugins/stack_services.py index 8b81b86..872e518 100644 --- a/wo/cli/plugins/stack_services.py +++ b/wo/cli/plugins/stack_services.py @@ -26,7 +26,9 @@ class WOStackStatusController(CementBaseController): self.app.pargs.php73 or self.app.pargs.mysql or self.app.pargs.memcached or - self.app.pargs.redis): + self.app.pargs.redis or + self.app.pargs.fail2ban or + self.app.pargs.netdata): self.app.pargs.nginx = True self.app.pargs.php = True self.app.pargs.mysql = True @@ -78,6 +80,12 @@ class WOStackStatusController(CementBaseController): else: Log.info(self, "Redis server is not installed") + if self.app.pargs.fail2ban: + if WOAptGet.is_installed(self, 'fail2ban'): + services = services + ['fail2ban-client'] + else: + Log.info(self, "fail2ban is not installed") + for service in services: Log.debug(self, "Starting service: {0}".format(service)) WOService.start_service(self, service) @@ -143,6 +151,12 @@ class WOStackStatusController(CementBaseController): else: Log.info(self, "Redis server is not installed") + if self.app.pargs.fail2ban: + if WOAptGet.is_installed(self, 'fail2ban'): + services = services + ['fail2ban-client'] + else: + Log.info(self, "fail2ban is not installed") + for service in services: Log.debug(self, "Stopping service: {0}".format(service)) WOService.stop_service(self, service) @@ -155,7 +169,8 @@ class WOStackStatusController(CementBaseController): self.app.pargs.php73 or self.app.pargs.mysql or self.app.pargs.memcached or - self.app.pargs.redis): + self.app.pargs.redis or + self.app.pargs.fail2ban): self.app.pargs.nginx = True self.app.pargs.php = True self.app.pargs.mysql = True @@ -209,6 +224,12 @@ class WOStackStatusController(CementBaseController): else: Log.info(self, "Redis server is not installed") + if self.app.pargs.fail2ban: + if WOAptGet.is_installed(self, 'fail2ban'): + services = services + ['fail2ban-client'] + else: + Log.info(self, "fail2ban is not installed") + for service in services: Log.debug(self, "Restarting service: {0}".format(service)) WOService.restart_service(self, service) @@ -221,7 +242,8 @@ class WOStackStatusController(CementBaseController): self.app.pargs.php73 or self.app.pargs.mysql or self.app.pargs.memcached or - self.app.pargs.redis): + self.app.pargs.redis or + self.app.pargs.fail2ban): self.app.pargs.nginx = True self.app.pargs.php = True self.app.pargs.mysql = True @@ -274,6 +296,12 @@ class WOStackStatusController(CementBaseController): else: Log.info(self, "Redis server is not installed") + if self.app.pargs.fail2ban: + if WOAptGet.is_installed(self, 'fail2ban'): + services = services + ['fail2ban-client'] + else: + Log.info(self, "fail2ban is not installed") + for service in services: if WOService.get_service_status(self, service): Log.info(self, "{0:10}: {1}".format(service, "Running")) @@ -286,7 +314,8 @@ class WOStackStatusController(CementBaseController): self.app.pargs.php73 or self.app.pargs.mysql or self.app.pargs.memcached or - self.app.pargs.redis): + self.app.pargs.redis or + self.app.pargs.fail2ban): self.app.pargs.nginx = True self.app.pargs.php = True self.app.pargs.mysql = True @@ -340,6 +369,12 @@ class WOStackStatusController(CementBaseController): else: Log.info(self, "Redis server is not installed") + if self.app.pargs.fail2ban: + if WOAptGet.is_installed(self, 'fail2ban'): + services = services + ['fail2ban-client'] + else: + Log.info(self, "fail2ban is not installed") + for service in services: Log.debug(self, "Reloading service: {0}".format(service)) WOService.reload_service(self, service) From 5536a66a9d816b8191fb81308de3139216c82158 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 10:47:48 +0200 Subject: [PATCH 04/45] update ssl config * remove ssl on; for Nginx 1.16.0 * add ca certifcate * enable OSCP stapling --- wo/cli/plugins/site_functions.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 818e23e..c18581c 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1287,6 +1287,7 @@ def setupLetsEncrypt(self, wo_domain_name): "--key-file {0}/{1}/key.pem " "--fullchain-file " "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " "--reloadcmd " "\"service nginx restart\" " .format(WOVariables.wo_ssl_live, @@ -1300,9 +1301,10 @@ def setupLetsEncrypt(self, wo_domain_name): encoding='utf-8', mode='w') sslconf.write("listen 443 ssl http2;\n" "listen [::]:443 ssl http2;\n" - "ssl on;\n" "ssl_certificate {0}/{1}/fullchain.pem;\n" "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" .format(WOVariables.wo_ssl_live, wo_domain_name)) sslconf.close() updateSiteInfo(self, wo_domain_name, ssl=True) @@ -1368,6 +1370,7 @@ def setupLetsEncryptSubdomain(self, wo_domain_name): "--key-file {0}/{1}/key.pem " "--fullchain-file " "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " "--reloadcmd " "\"service nginx restart\" " .format(WOVariables.wo_ssl_live, @@ -1382,9 +1385,10 @@ def setupLetsEncryptSubdomain(self, wo_domain_name): encoding='utf-8', mode='w') sslconf.write("listen 443 ssl http2;\n" "listen [::]:443 ssl http2;\n" - "ssl on;\n" "ssl_certificate {0}/{1}/fullchain.pem;\n" "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" .format(WOVariables.wo_ssl_live, wo_domain_name)) sslconf.close() updateSiteInfo(self, wo_domain_name, ssl=True) @@ -1548,6 +1552,7 @@ def archivedCertificateHandle(self, domain): "--key-file {0}/{1}/key.pem " "--fullchain-file " "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " "--reloadcmd " "\"service nginx restart\" " .format(WOVariables.wo_ssl_live, @@ -1567,10 +1572,11 @@ def archivedCertificateHandle(self, domain): encoding='utf-8', mode='w') sslconf.write("listen 443 ssl http2;\n" "listen [::]:443 ssl http2;\n" - "ssl on;\n" "ssl_certificate " "{0}/{1}/fullchain.pem;\n" "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" .format(WOVariables.wo_ssl_live, domain)) sslconf.close() @@ -1614,6 +1620,8 @@ def archivedCertificateHandle(self, domain): "--key-file {0}/{1}/key.pem " "--fullchain-file " "{0}/{1}/fullchain.pem " + "ssl_trusted_certificate " + "{0}/{1}/ca.pem;\n" "--reloadcmd " "\"service nginx restart\" " .format(WOVariables.wo_ssl_live, domain)) From 4ba8007a065ba494962f64b00444833b67a0f671 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 11:01:26 +0200 Subject: [PATCH 05/45] update version to prepare release --- install | 26 +++++++++++++------------- setup.py | 2 +- wo/core/variables.py | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/install b/install index 1ea406b..59f8d3e 100755 --- a/install +++ b/install @@ -7,10 +7,10 @@ # Copyright (c) 2019 - WordOps # This script is licensed under M.I.T # ------------------------------------------------------------------------- -# Version 3.9.5 - 2019-04-22 +# Version 3.9.5 - 2019-04-25 # ------------------------------------------------------------------------- readonly wo_version_old="2.2.3" -readonly wo_version_new="3.9.4.6" +readonly wo_version_new="3.9.5" # CONTENTS # --- # 1. VARIABLES AND DECLARATIONS @@ -380,15 +380,6 @@ wo_install_acme_sh() { # enable auto-upgrade /etc/letsencrypt/acme.sh --config-home /etc/letsencrypt/config --upgrade --auto-upgrade - # Let's Encrypt .well-known folder setup - if [ ! -d /var/www/html/.well-known/acme-challenge ]; then - mkdir -p /var/www/html/.well-known/acme-challenge - chown -R www-data:www-data /var/www/html /var/www/html/.well-known - chmod 750 /var/www/html /var/www/html/.well-known - else - chmod 750 /var/www/html /var/www/html/.well-known - fi - } >> "$wo_install_log" 2>&1 fi if [ -d "$HOME/.acme.sh" ]; then @@ -406,6 +397,14 @@ wo_install_acme_sh() { } >> "$wo_install_log" 2>&1 fi + # Let's Encrypt .well-known folder setup + if [ ! -d /var/www/html/.well-known/acme-challenge ]; then + mkdir -p /var/www/html/.well-known/acme-challenge + chown -R www-data:www-data /var/www/html /var/www/html/.well-known + chmod 750 /var/www/html /var/www/html/.well-known + else + chmod 750 /var/www/html /var/www/html/.well-known + fi } # Clone Github repository if it doesn't exist @@ -642,8 +641,9 @@ wo_clean_ee() { # 1 - WO already installed if [ -x /usr/local/bin/wo ]; then - wo -v 2>&1 | grep $wo_version_new - if [[ $? -ne 0 ]]; then + if ! { + wo -v 2>&1 | grep $wo_version_new + }; then read -p "Update WordOps to $wo_version_new (y/n): " wo_ans if [ "$wo_ans" = "y" ] || [ "$wo_ans" = "Y" ]; then wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log diff --git a/setup.py b/setup.py index 39ecda6..82c3cde 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ if not os.path.isfile('/root/.gitconfig'): shutil.copy2(os.path.expanduser("~")+'/.gitconfig', '/root/.gitconfig') setup(name='wo', - version='3.9.4', + version='3.9.5', description=long_description, long_description=long_description, classifiers=[], diff --git a/wo/core/variables.py b/wo/core/variables.py index 054ef53..68fab32 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -11,7 +11,7 @@ class WOVariables(): """Intialization of core variables""" # WordOps version - wo_version = "3.9.4" + wo_version = "3.9.5" # WordOps packages versions wo_wp_cli = "2.1.0" wo_adminer = "4.7.1" From b892e171b8e257a4a25ece88b8744e5f4435f0cc Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 12:05:48 +0200 Subject: [PATCH 06/45] add python3-mysqldb for netdata --- wo/cli/plugins/stack.py | 4 ++++ wo/core/variables.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 1f2b330..5b29844 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1522,6 +1522,10 @@ class WOStackController(CementBaseController): 'kickstart-static64.sh', '/tmp/kickstart.sh', 'Netdata']] + if not WOAptGet.is_installed(self, 'python3-mysqldb'): + Log.debug( + self, "Setting apt_packages variable for Fail2ban") + apt_packages = apt_packages + WOVariables.wo_netdata # WordOps Dashboard if self.app.pargs.dashboard: diff --git a/wo/core/variables.py b/wo/core/variables.py index 68fab32..6b2556f 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -162,6 +162,8 @@ class WOVariables(): wo_fail2ban = "fail2ban" + wo_netdata = "python3-mysqldb" + # Redis repo details if wo_platform_distro == 'ubuntu': wo_redis_repo = ("ppa:chris-lea/redis-server") From 77aa92137c5dfe7f50e0c35689b10ea12699c467 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 25 Apr 2019 13:02:11 +0200 Subject: [PATCH 07/45] move python3-mysqldb to mysql packages --- wo/cli/plugins/stack.py | 4 ---- wo/core/variables.py | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 5b29844..1f2b330 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1522,10 +1522,6 @@ class WOStackController(CementBaseController): 'kickstart-static64.sh', '/tmp/kickstart.sh', 'Netdata']] - if not WOAptGet.is_installed(self, 'python3-mysqldb'): - Log.debug( - self, "Setting apt_packages variable for Fail2ban") - apt_packages = apt_packages + WOVariables.wo_netdata # WordOps Dashboard if self.app.pargs.dashboard: diff --git a/wo/core/variables.py b/wo/core/variables.py index 6b2556f..fd12917 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -158,12 +158,10 @@ class WOVariables(): "10.3/debian {codename} main" .format(codename=wo_platform_codename)) - wo_mysql = ["mariadb-server", "percona-toolkit"] + wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] wo_fail2ban = "fail2ban" - wo_netdata = "python3-mysqldb" - # Redis repo details if wo_platform_distro == 'ubuntu': wo_redis_repo = ("ppa:chris-lea/redis-server") From 2f9b598113274b3bf462e92ca759a81f7e5b4a22 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Fri, 26 Apr 2019 21:30:46 +0200 Subject: [PATCH 08/45] Add fail2ban conf --- config/bash_completion.d/wo_auto.rc | 2 +- docs/wo.8 | 2 +- install | 15 +- wo/cli/plugins/update.py | 7 +- wo/cli/templates/fail2ban-forbidden.mustache | 4 + wo/cli/templates/fail2ban.mustache | 2 +- wo/cli/templates/fastcgi.mustache | 4 +- wo/cli/templates/sysctl.mustache | 266 +++++++++++++++++++ 8 files changed, 289 insertions(+), 13 deletions(-) create mode 100644 wo/cli/templates/fail2ban-forbidden.mustache create mode 100644 wo/cli/templates/sysctl.mustache diff --git a/config/bash_completion.d/wo_auto.rc b/config/bash_completion.d/wo_auto.rc index 6a6e3a9..ead7ffc 100644 --- a/config/bash_completion.d/wo_auto.rc +++ b/config/bash_completion.d/wo_auto.rc @@ -74,7 +74,7 @@ _wo_complete() # HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE "install" | "purge" | "remove" ) COMPREPLY=( $(compgen \ - -W "--web --admin --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --all --redis --phpredisadmin --composer --netdata --fail2ban" \ + -W "--web --admin --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --all --redis --phpredisadmin --composer --netdata --fail2ban --dashboard" \ -- $cur) ) ;; "upgrade" ) diff --git a/docs/wo.8 b/docs/wo.8 index 5c62929..f0d2891 100644 --- a/docs/wo.8 +++ b/docs/wo.8 @@ -5,7 +5,7 @@ .SH SYNOPSIS wo [ --version | --help | info | stack | site | debug | update | clean | import_slow_log | log | secure | sync | maintenance] .TP -wo stack [ install | remove | purge | migrate | upgrade] [ --web | --all | --nginx | --php | --php73 | --mysql | --admin | --adminer | --redis | --phpmyadmin | --phpredisadmin | --wpcli | --utils ] +wo stack [ install | remove | purge | migrate | upgrade] [ --web | --all | --nginx | --php | --php73 | --mysql | --admin | --adminer | --redis | --phpmyadmin | --phpredisadmin | --wpcli | --utils | --dashboard | --netdata ] .TP wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php | --php73 |--mysql | --web | --memcached | --redis] .TP diff --git a/install b/install index 59f8d3e..e7e6cf7 100755 --- a/install +++ b/install @@ -7,7 +7,7 @@ # Copyright (c) 2019 - WordOps # This script is licensed under M.I.T # ------------------------------------------------------------------------- -# Version 3.9.5 - 2019-04-25 +# Version 3.9.5 - 2019-04-26 # ------------------------------------------------------------------------- readonly wo_version_old="2.2.3" readonly wo_version_new="3.9.5" @@ -216,9 +216,6 @@ wo_sync_db() { # Copy the EasyEngine database cp /var/lib/ee/ee.db /var/lib/wo/dbase-ee.db - # Set the migration variable for the closing text - migration=1 - ### # Clean WO installation ### @@ -327,9 +324,9 @@ wo_sync_db() { secure_wo_db() { # The owner is root - chown -R root:root /var/lib/wo/ + chown -R root:root /var/lib/wo # Only allow access by root, block others - chmod -R 600 /var/lib/wo/ + chmod -R 600 /var/lib/wo } @@ -635,6 +632,12 @@ wo_clean_ee() { rm -f /usr/local/bin/ee /etc/bash_completion.d/ee_auto.rc /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee >> /var/log/wo/install.log 2>&1 } +# wo_tweak_kernel() { +# if [ ! -f /etc/sysctl.d/60-ubuntu-nginx-web-server.conf ]; then + +# fi +# } + ### # 4 - WO MAIN SETUP ### diff --git a/wo/cli/plugins/update.py b/wo/cli/plugins/update.py index 4f589de..fa955bc 100644 --- a/wo/cli/plugins/update.py +++ b/wo/cli/plugins/update.py @@ -1,9 +1,10 @@ -from cement.core.controller import CementBaseController, expose +import os +import time + from cement.core import handler, hook +from cement.core.controller import CementBaseController, expose from wo.core.download import WODownload from wo.core.logging import Log -import time -import os def wo_update_hook(app): diff --git a/wo/cli/templates/fail2ban-forbidden.mustache b/wo/cli/templates/fail2ban-forbidden.mustache new file mode 100644 index 0000000..6f708bf --- /dev/null +++ b/wo/cli/templates/fail2ban-forbidden.mustache @@ -0,0 +1,4 @@ +[Definition] +failregex = ^ \[error\] \d+#\d+: .* forbidden .*, client: , .*$ + +ignoreregex = diff --git a/wo/cli/templates/fail2ban.mustache b/wo/cli/templates/fail2ban.mustache index 10937f6..f7eb611 100644 --- a/wo/cli/templates/fail2ban.mustache +++ b/wo/cli/templates/fail2ban.mustache @@ -21,4 +21,4 @@ port = http,https logpath = /var/log/nginx/*error*.log findtime = 60 bantime = 6000 -maxretry = 3 \ No newline at end of file +maxretry = 5 \ No newline at end of file diff --git a/wo/cli/templates/fastcgi.mustache b/wo/cli/templates/fastcgi.mustache index 7300bb0..72cd66b 100644 --- a/wo/cli/templates/fastcgi.mustache +++ b/wo/cli/templates/fastcgi.mustache @@ -1,4 +1,4 @@ -# FastCGI cache settings - WO v3.9.5.1 +# FastCGI cache settings - WO v3.9.5 fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:50m inactive=60m max_size=256M; fastcgi_cache_key "$scheme$request_method$host$request_uri"; fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503; @@ -17,3 +17,5 @@ fastcgi_buffer_size 32k; fastcgi_param SERVER_NAME $http_host; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; fastcgi_keep_conn on; +# only available with Nginx 1.15.6 and earlier +fastcgi_socket_keepalive on; diff --git a/wo/cli/templates/sysctl.mustache b/wo/cli/templates/sysctl.mustache new file mode 100644 index 0000000..cc2c332 --- /dev/null +++ b/wo/cli/templates/sysctl.mustache @@ -0,0 +1,266 @@ +# Kernel sysctl configuration file for Linux +# +# Version 1.16 - 2019-10-25 +# Michiel Klaver - IT Professional +# Modified by VirtuBox +# +# Instructions available on https://github.com/VirtuBox/ubuntu-nginx-web-server +# +# Sources : +# https://klaver.it/linux/sysctl.conf +# https://easyengine.io/tutorials/linux/sysctl-conf/ +# +# +# Credits: +# +# http://www.enigma.id.au/linux_tuning.txt +# http://www.securityfocus.com/infocus/1729 +# http://fasterdata.es.net/TCP-tuning/linux.html +# http://fedorahosted.org/ktune/browser/sysctl.ktune +# http://www.cymru.com/Documents/ip-stack-tuning.html +# http://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt +# http://www.frozentux.net/ipsysctl-tutorial/chunkyhtml/index.html +# http://knol.google.com/k/linux-performance-tuning-and-measurement +# http://www.cyberciti.biz/faq/linux-kernel-tuning-virtual-memory-subsystem/ +# http://www.redbooks.ibm.com/abstracts/REDP4285.html +# http://www.speedguide.net/read_articles.php?id=121 +# http://lartc.org/howto/lartc.kernel.obscure.html +# http://en.wikipedia.org/wiki/Sysctl +# +# Usage +# wget -O /etc/sysctl.d/60-ubuntu-nginx-web-server.conf https://virtubox.github.io/ubuntu-nginx-web-server/files/etc/sysctl.d/60-ubuntu-nginx-web-server.conf +# +# sysctl -e -p /etc/sysctl.d/60-ubuntu-nginx-web-server.conf +# For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and sysctl.conf(5) for more details. +# + +### +### GENERAL SYSTEM SECURITY OPTIONS ### +### + +# Controls the System Request debugging functionality of the kernel +kernel.sysrq = 0 + +# Controls whether core dumps will append the PID to the core filename. +# Useful for debugging multi-threaded applications. +kernel.core_uses_pid = 1 + +#Allow for more PIDs +kernel.pid_max = 65535 + +# The contents of /proc//maps and smaps files are only visible to +# readers that are allowed to ptrace() the process +kernel.maps_protect = 1 + +#Enable ExecShield protection +kernel.exec-shield = 1 +kernel.randomize_va_space = 2 + +# Controls the maximum size of a message, in bytes +kernel.msgmnb = 65535 + +# Controls the default maxmimum size of a mesage queue +kernel.msgmax = 65535 + +# Restrict core dumps +fs.suid_dumpable = 0 + +# Hide exposed kernel pointers +kernel.kptr_restrict = 1 + +### +### IMPROVE SYSTEM MEMORY MANAGEMENT ### +### + +# Increase size of file handles and inode cache +fs.file-max = 209708 + +# Do less swapping +vm.swappiness = 10 +vm.dirty_ratio = 30 +vm.dirty_background_ratio = 5 + +# specifies the minimum virtual address that a process is allowed to mmap +vm.mmap_min_addr = 4096 + +# 50% overcommitment of available memory +vm.overcommit_ratio = 50 + +# allow memory overcommit required for redis +vm.overcommit_memory = 1 + +# Set maximum amount of memory allocated to shm to 256MB +kernel.shmmax = 268435456 +kernel.shmall = 268435456 + +# Keep at least 64MB of free RAM space available +vm.min_free_kbytes = 65535 + +### +### GENERAL NETWORK SECURITY OPTIONS ### +### + +#Prevent SYN attack, enable SYNcookies (they will kick-in when the max_syn_backlog reached) +net.ipv4.tcp_syncookies = 1 +net.ipv4.tcp_syn_retries = 2 +net.ipv4.tcp_synack_retries = 2 +net.ipv4.tcp_max_syn_backlog = 4096 + +# Disables IP source routing +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +net.ipv6.conf.all.accept_source_route = 0 +net.ipv6.conf.default.accept_source_route = 0 + +# Enable IP spoofing protection, turn on source route verification +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 + +# Disable ICMP Redirect Acceptance +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.secure_redirects = 0 +net.ipv4.conf.default.secure_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 + +# Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets +net.ipv4.conf.all.log_martians = 1 +net.ipv4.conf.default.log_martians = 1 + +# Decrease the time default value for tcp_fin_timeout connection +net.ipv4.tcp_fin_timeout = 7 + +# Decrease the time default value for connections to keep alive +net.ipv4.tcp_keepalive_time = 300 +net.ipv4.tcp_keepalive_probes = 5 +net.ipv4.tcp_keepalive_intvl = 15 + +# Don't relay bootp +net.ipv4.conf.all.bootp_relay = 0 + +# Don't proxy arp for anyone +net.ipv4.conf.all.proxy_arp = 0 + +# Turn on the tcp_timestamps, accurate timestamp make TCP congestion control algorithms work better +net.ipv4.tcp_timestamps = 1 + +# Don't ignore directed pings +net.ipv4.icmp_echo_ignore_all = 0 + +# Enable ignoring broadcasts request +net.ipv4.icmp_echo_ignore_broadcasts = 1 + +# Enable bad error message Protection +net.ipv4.icmp_ignore_bogus_error_responses = 1 + +# Allowed local port range +net.ipv4.ip_local_port_range = 16384 65535 + +# Enable a fix for RFC1337 - time-wait assassination hazards in TCP +net.ipv4.tcp_rfc1337 = 1 + +# Do not auto-configure IPv6 +net.ipv6.conf.all.autoconf=0 +net.ipv6.conf.all.accept_ra=0 +net.ipv6.conf.default.autoconf=0 +net.ipv6.conf.default.accept_ra=0 +net.ipv6.conf.all.accept_ra_defrtr = 0 +net.ipv6.conf.default.accept_ra_defrtr = 0 +net.ipv6.conf.all.accept_ra_pinfo = 0 +net.ipv6.conf.default.accept_ra_pinfo = 0 + +### +### TUNING NETWORK PERFORMANCE ### +### + +# For servers with tcp-heavy workloads, enable 'fq' queue management scheduler (kernel > 3.12) +net.core.default_qdisc = fq + +# Turn on the tcp_window_scaling +net.ipv4.tcp_window_scaling = 1 + +# Increase the read-buffer space allocatable +net.ipv4.tcp_rmem = 8192 87380 16777216 +net.ipv4.udp_rmem_min = 16384 +net.core.rmem_default = 262144 +net.core.rmem_max = 16777216 + +# Increase the write-buffer-space allocatable +net.ipv4.tcp_wmem = 8192 65536 16777216 +net.ipv4.udp_wmem_min = 16384 +net.core.wmem_default = 262144 +net.core.wmem_max = 16777216 + +# Increase number of incoming connections +net.core.somaxconn = 32768 + +# Increase number of incoming connections backlog +net.core.netdev_max_backlog = 16384 +net.core.dev_weight = 64 + +# Increase the maximum amount of option memory buffers +net.core.optmem_max = 65535 + +# Increase the tcp-time-wait buckets pool size to prevent simple DOS attacks +net.ipv4.tcp_max_tw_buckets = 1440000 + +# try to reuse time-wait connections, but don't recycle them (recycle can break clients behind NAT) +net.ipv4.tcp_tw_recycle = 0 +net.ipv4.tcp_tw_reuse = 1 + +# Limit number of orphans, each orphan can eat up to 16M (max wmem) of unswappable memory +net.ipv4.tcp_max_orphans = 16384 +net.ipv4.tcp_orphan_retries = 0 + +# Limit the maximum memory used to reassemble IP fragments (CVE-2018-5391) +net.ipv4.ipfrag_low_thresh = 196608 +net.ipv6.ip6frag_low_thresh = 196608 +net.ipv4.ipfrag_high_thresh = 262144 +net.ipv6.ip6frag_high_thresh = 262144 + + +# don't cache ssthresh from previous connection +net.ipv4.tcp_no_metrics_save = 1 +net.ipv4.tcp_moderate_rcvbuf = 1 + +# Increase size of RPC datagram queue length +net.unix.max_dgram_qlen = 50 + +# Don't allow the arp table to become bigger than this +net.ipv4.neigh.default.gc_thresh3 = 2048 + +# Tell the gc when to become aggressive with arp table cleaning. +# Adjust this based on size of the LAN. 1024 is suitable for most /24 networks +net.ipv4.neigh.default.gc_thresh2 = 1024 + +# Adjust where the gc will leave arp table alone - set to 32. +net.ipv4.neigh.default.gc_thresh1 = 32 + +# Adjust to arp table gc to clean-up more often +net.ipv4.neigh.default.gc_interval = 30 + +# Increase TCP queue length +net.ipv4.neigh.default.proxy_qlen = 96 +net.ipv4.neigh.default.unres_qlen = 6 + +# Enable Explicit Congestion Notification (RFC 3168), disable it if it doesn't work for you +net.ipv4.tcp_ecn = 1 +net.ipv4.tcp_reordering = 3 + +# How many times to retry killing an alive TCP connection +net.ipv4.tcp_retries2 = 15 +net.ipv4.tcp_retries1 = 3 + +# Avoid falling back to slow start after a connection goes idle +# keeps our cwnd large with the keep alive connections (kernel > 3.6) +net.ipv4.tcp_slow_start_after_idle = 0 + +# Allow the TCP fastopen flag to be used, beware some firewalls do not like TFO! (kernel > 3.7) +net.ipv4.tcp_fastopen = 3 + +# This will enusre that immediatly subsequent connections use the new values +net.ipv4.route.flush = 1 +net.ipv6.route.flush = 1 From b0671c0e7492d09f40967aa58305b320e4f4be06 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Sat, 27 Apr 2019 03:02:26 +0200 Subject: [PATCH 09/45] Update wordops version automatically --- wo/cli/plugins/stack.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 1f2b330..d9e56f3 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -378,10 +378,12 @@ class WOStackController(CementBaseController): self.app.render((data), 'locations.mustache', out=wo_nginx) wo_nginx.close() + if not os.path.isfile("/etc/nginx/common/release"): with open("/etc/nginx/common/release", "a") as release_file: - release_file.write("v3.9.5") + release_file.write("v{0}" + .format(WOVariables.wo_version)) release_file.close() # Nginx-Plus does not have nginx From 490f2c80dfac8a9aa68629b79877a83c1a4937f6 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Sun, 28 Apr 2019 21:28:13 +0200 Subject: [PATCH 10/45] compress mysqldump with pigz during site update --- wo/cli/plugins/site_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index c18581c..807716d 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -697,7 +697,7 @@ def sitebackup(self, data): if data['wo_db_name']: Log.info(self, 'Backing up database \t\t', end='') try: - if not WOShellExec.cmd_exec(self, "mysqldump {0} > {1}/{0}.sql" + if not WOShellExec.cmd_exec(self, "mysqldump --single-transaction {0} | pigz -9 -p\"$(nproc)\" > {1}/{0}.gz" .format(data['wo_db_name'], backup_path)): Log.info(self, From 8a29383ea8e0f14926a2a5a4413015db51c1089f Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Sun, 28 Apr 2019 22:04:18 +0200 Subject: [PATCH 11/45] move return ssl --- wo/cli/plugins/site_functions.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 807716d..cb20254 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1147,7 +1147,7 @@ def detSitePar(opts): def generate_random(): wo_random10 = (''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase + - string.digits, 16))) + string.digits, 24))) return wo_random10 @@ -1408,8 +1408,6 @@ def setupLetsEncryptSubdomain(self, wo_domain_name): "\n to allow it to verify the site automatically.") # letsencrypt cert renewal - - def renewLetsEncrypt(self, wo_domain_name): ssl = WOShellExec.cmd_exec( @@ -1642,4 +1640,4 @@ def archivedCertificateHandle(self, domain): '/var/www/{0}/conf/nginx/ssl.conf.bak' .format(domain)) - return ssl + return ssl From 264d014c5d071b61854f1ae86ad20eae0e8a2f17 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 29 Apr 2019 00:45:02 +0200 Subject: [PATCH 12/45] reformat code * add security stack for futur usage * fix pep8 formatting issues --- CHANGELOG.md | 2 ++ README.md | 3 ++- install | 2 +- setup.py | 2 +- wo/cli/plugins/site_functions.py | 4 +++- wo/cli/plugins/stack.py | 2 +- wo/core/variables.py | 10 +++++----- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ead24bb..360a141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - MySQL monitoring with Netdata - WordOps-dashboard on 22222 - Extplorer filemanager +- Enable OSCP Stapling with Let's Encrypt +- Compress database backup with pigz before updating sites #### Changed diff --git a/README.md b/README.md index e379646..8c028b7 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ build MIT Commits -GitHub release +GitHub release +

diff --git a/install b/install index e7e6cf7..1dbc233 100755 --- a/install +++ b/install @@ -178,7 +178,7 @@ wo_install_dep() { if [ "$wo_linux_distro" == "Ubuntu" ]; then DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confmiss" -o Dpkg::Options::="--force-confold" -y install build-essential curl gzip python3 python3-apt python3-setuptools python3-dev sqlite3 git tar software-properties-common pigz gnupg2 cron ccze rsync tree haveged ufw > /dev/null 2>&1 else - wget -qO /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg + [ -d /etc/apt/trusted.gpg.d ] && { wget -qO /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg; } DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confmiss" -o Dpkg::Options::="--force-confold" -y install build-essential curl gzip dirmngr sudo python3 python3-apt python3-setuptools python3-dev ca-certificates sqlite3 git tar software-properties-common pigz apt-transport-https gnupg2 cron ccze rsync tree haveged ufw > /dev/null 2>&1 fi diff --git a/setup.py b/setup.py index 82c3cde..c302674 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ except Exception as e: print("Your informations will ONLY be stored locally") wo_user = input("Enter your name: ") - while wo_user is "": + while wo_user == "": print("Unfortunately, this can't be left blank") wo_user = input("Enter your name: ") diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index cb20254..693fbab 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -697,7 +697,9 @@ def sitebackup(self, data): if data['wo_db_name']: Log.info(self, 'Backing up database \t\t', end='') try: - if not WOShellExec.cmd_exec(self, "mysqldump --single-transaction {0} | pigz -9 -p\"$(nproc)\" > {1}/{0}.gz" + if not WOShellExec.cmd_exec(self, "mysqldump --single-transaction " + "{0} | pigz -9 -p\"$(nproc)\" " + "> {1}/{0}.gz" .format(data['wo_db_name'], backup_path)): Log.info(self, diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index d9e56f3..e4b2459 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1159,7 +1159,7 @@ class WOStackController(CementBaseController): WOFileUtils.searchreplace(self, "{0}22222/htdocs/index.php" .format(WOVariables.wo_webroot), "eth0", - "{0}".format(WOVariables.wo_wan_interface)) + "{0}".format(WOVariables.wo_wan)) Log.debug(self, "Setting Privileges to " "{0}22222/htdocs" diff --git a/wo/core/variables.py b/wo/core/variables.py index fd12917..1fae267 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -22,11 +22,11 @@ class WOVariables(): wo_wpcli_path = '/usr/local/bin/wp ' # get wan network interface name - wo_wan_interface = os.popen("ip -4 route get 8.8.8.8 | " - "grep -oP \"dev [^[:space:]]+ \" " - "| cut -d ' ' -f 2").read() - if wo_wan_interface == '': - wo_wan_interface = 'eth0' + wo_wan = os.popen("/sbin/ip -4 route get 8.8.8.8 | " + "grep -oP \"dev [^[:space:]]+ \" " + "| cut -d ' ' -f 2").read() + if wo_wan == '': + wo_wan = 'eth0' # Current date and time of System wo_date = datetime.datetime.now().strftime('%d%b%Y%H%M%S') From 0508592d2a27497b8b741b6bddc60bb9db8f8ff5 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 29 Apr 2019 00:54:37 +0200 Subject: [PATCH 13/45] fix wo_wan variable --- wo/cli/plugins/stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index e4b2459..732fbea 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1155,7 +1155,7 @@ class WOStackController(CementBaseController): WOExtract.extract(self, '/tmp/wo-dashboard.tar.gz', '{0}22222/htdocs' .format(WOVariables.wo_webroot)) - if WOVariables.wo_wan_interface != 'eth0': + if WOVariables.wo_wan != 'eth0': WOFileUtils.searchreplace(self, "{0}22222/htdocs/index.php" .format(WOVariables.wo_webroot), "eth0", From 9de9ba8637d0ffd3fac7313d3f4f61ae29f52c73 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 29 Apr 2019 02:06:32 +0200 Subject: [PATCH 14/45] reformat code according to pep8 --- wo/cli/plugins/debug.py | 88 ++++++++++++++++----------------- wo/cli/plugins/log.py | 3 +- wo/cli/plugins/stack_upgrade.py | 3 +- wo/core/cron.py | 9 ++-- wo/core/mysql.py | 2 +- wo/core/services.py | 3 +- 6 files changed, 57 insertions(+), 51 deletions(-) diff --git a/wo/cli/plugins/debug.py b/wo/cli/plugins/debug.py index af1cfda..51178ae 100644 --- a/wo/cli/plugins/debug.py +++ b/wo/cli/plugins/debug.py @@ -191,22 +191,22 @@ class WODebugController(CementBaseController): nc.savef('/etc/nginx/conf.d/upstream.conf') # Enable xdebug - WOFileUtils.searchreplace(self, "/etc/{0}/mods-available/".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php/7.2") + + WOFileUtils.searchreplace(self, "/etc/{0}/" + "mods-available/".format("php/7.2") + "xdebug.ini", ";zend_extension", "zend_extension") # Fix slow log is not enabled default in PHP5.6 config = configparser.ConfigParser() - config.read('/etc/{0}/fpm/pool.d/debug.conf'.format( - "php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5")) - config['debug']['slowlog'] = '/var/log/{0}/slow.log'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5") + config.read('/etc/{0}/fpm/pool.d/debug.conf'.format("php/7.2")) + config['debug']['slowlog'] = '/var/log/{0}/slow.log'.format( + "php/7.2") config['debug']['request_slowlog_timeout'] = '10s' - with open('/etc/{0}/fpm/pool.d/debug.conf'.format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5"), + with open('/etc/{0}/fpm/pool.d/debug.conf'.format("php/7.2"), encoding='utf-8', mode='w') as confifile: Log.debug(self, "Writting debug.conf configuration into " - "/etc/{0}/fpm/pool.d/debug.conf".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5")) + "/etc/{0}/fpm/pool.d/debug.conf".format("php/7.2")) config.write(confifile) self.trigger_php = True @@ -214,8 +214,7 @@ class WODebugController(CementBaseController): else: Log.info(self, "PHP debug is already enabled") - self.msg = self.msg + ['/var/log/{0}/slow.log'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5")] + self.msg = self.msg + ['/var/log/{0}/slow.log'.format("php/7.2")] # PHP global debug stop elif (self.app.pargs.php == 'off' and not self.app.pargs.site_name): @@ -231,7 +230,8 @@ class WODebugController(CementBaseController): nc.savef('/etc/nginx/conf.d/upstream.conf') # Disable xdebug - WOFileUtils.searchreplace(self, "/etc/{0}/mods-available/".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5") + + WOFileUtils.searchreplace(self, "/etc/{0}/" + "mods-available/".format("php/7.2") + "xdebug.ini", "zend_extension", ";zend_extension") @@ -247,43 +247,41 @@ class WODebugController(CementBaseController): # PHP5-FPM start global debug if (self.app.pargs.fpm == 'on' and not self.app.pargs.site_name): if not WOShellExec.cmd_exec(self, "grep \"log_level = debug\" " - "/etc/{0}/fpm/php-fpm.conf".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5")): + "/etc/{0}/" + "fpm/php-fpm.conf".format("php/7.2")): Log.info(self, "Setting up PHP5-FPM log_level = debug") config = configparser.ConfigParser() - config.read('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5")) + config.read('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2")) config.remove_option('global', 'include') config['global']['log_level'] = 'debug' - config['global']['include'] = '/etc/{0}/fpm/pool.d/*.conf'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5") - with open('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5"), + config['global']['include'] = '/etc/{0}/fpm/pool.d/*.conf'.format( + "php/7.2") + with open('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2"), encoding='utf-8', mode='w') as configfile: Log.debug(self, "Writting php5-FPM configuration into " - "/etc/{0}/fpm/php-fpm.conf".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5")) + "/etc/{0}/fpm/php-fpm.conf".format("php/7.2")) config.write(configfile) self.trigger_php = True else: Log.info(self, "PHP5-FPM log_level = debug already setup") - self.msg = self.msg + ['/var/log/{0}/fpm.log'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5")] + self.msg = self.msg + ['/var/log/{0}/fpm.log'.format("php/7.2")] # PHP5-FPM stop global debug elif (self.app.pargs.fpm == 'off' and not self.app.pargs.site_name): if WOShellExec.cmd_exec(self, "grep \"log_level = debug\" " - "/etc/{0}/fpm/php-fpm.conf".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5")): + "/etc/{0}/fpm/php-fpm.conf".format("php/7.2")): Log.info(self, "Disabling PHP5-FPM log_level = debug") config = configparser.ConfigParser() - config.read('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5")) + config.read('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2")) config.remove_option('global', 'include') config['global']['log_level'] = 'notice' - config['global']['include'] = '/etc/{0}/fpm/pool.d/*.conf'.format("php/7.2" if ( - WOVariables.wo_platform_distro == 'ubuntu') else "php5") - with open('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5"), + config['global']['include'] = '/etc/{0}/fpm/pool.d/*.conf'.format( + "php/7.2") + with open('/etc/{0}/fpm/php-fpm.conf'.format("php/7.2"), encoding='utf-8', mode='w') as configfile: Log.debug(self, "writting php5 configuration into " - "/etc/{0}/fpm/php-fpm.conf".format("php/7.2" if (WOVariables.wo_platform_distro == 'ubuntu') else "php5")) + "/etc/{0}/fpm/php-fpm.conf".format("php/7.2")) config.write(configfile) self.trigger_php = True @@ -335,7 +333,8 @@ class WODebugController(CementBaseController): # PHP global debug stop elif (self.app.pargs.php73 == 'off' and not self.app.pargs.site_name): - if WOShellExec.cmd_exec(self, " sed -n \"/upstream php72 {/,/}/p\" " + if WOShellExec.cmd_exec(self, " sed -n \"/upstream " + "php72 {/,/}/p\" " "/etc/nginx/conf.d/upstream.conf " "| grep 9172"): Log.info(self, "Disabling PHP 7.2 debug") @@ -399,7 +398,8 @@ class WODebugController(CementBaseController): config.write(configfile) self.trigger_php = True else: - Log.info(self, "PHP7.3-FPM log_level = debug already disabled") + Log.info(self, "PHP7.3-FPM log_level " + "= debug already disabled") @expose(hide=True) def debug_mysql(self): @@ -536,8 +536,8 @@ class WODebugController(CementBaseController): self.msg = self.msg + ['/var/log/nginx/*.error.log'] # Stop Nginx rewrite debug globally - elif (self.app.pargs.rewrite == 'off' - and not self.app.pargs.site_name): + elif (self.app.pargs.rewrite == 'off' and + not self.app.pargs.site_name): if WOShellExec.cmd_exec(self, "grep \"rewrite_log on;\" " "/etc/nginx/nginx.conf"): Log.info(self, "Disabling Nginx rewrite logs") @@ -644,10 +644,10 @@ class WODebugController(CementBaseController): (not self.app.pargs.fpm73) and (not self.app.pargs.mysql) and (not self.app.pargs.wp) and (not self.app.pargs.rewrite) and (not self.app.pargs.all) and (not self.app.pargs.site_name) and - (not self.app.pargs.import_slow_log) - and (not self.app.pargs.interval)): + (not self.app.pargs.import_slow_log) and + (not self.app.pargs.interval)): if self.app.pargs.stop or self.app.pargs.start: - print("--start/stop option is deprecated since ee v3.0.5") + print("--start/stop option is deprecated since wo v3.0.5") self.app.args.print_help() else: self.app.args.print_help() @@ -778,8 +778,8 @@ class WODebugController(CementBaseController): if len(self.msg) > 0: if not self.app.pargs.interactive: disp_msg = ' '.join(self.msg) - Log.info(self, "Use following command to check debug logs:\n" - + Log.ENDC + "tail -f {0}".format(disp_msg)) + Log.info(self, "Use following command to check debug logs:\n" + + Log.ENDC + "tail -f {0}".format(disp_msg)) else: signal.signal(signal.SIGINT, self.signal_handler) watch_list = [] @@ -797,18 +797,18 @@ class WODebugController(CementBaseController): # Get Anemometer user name and password Log.info(self, "Importing MySQL slow log to Anemometer") host = os.popen("grep -e \"\'host\'\" {0}22222/htdocs/" - .format(WOVariables.wo_webroot) - + "db/anemometer/conf/config.inc.php " + .format(WOVariables.wo_webroot) + + "db/anemometer/conf/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() user = os.popen("grep -e \"\'user\'\" {0}22222/htdocs/" - .format(WOVariables.wo_webroot) - + "db/anemometer/conf/config.inc.php " + .format(WOVariables.wo_webroot) + + "db/anemometer/conf/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() password = os.popen("grep -e \"\'password\'\" {0}22222/" - .format(WOVariables.wo_webroot) - + "htdocs/db/anemometer/conf" + .format(WOVariables.wo_webroot) + + "htdocs/db/anemometer/conf" "/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() @@ -836,9 +836,9 @@ class WODebugController(CementBaseController): " so not imported slow logs") else: Log.error(self, "Anemometer is not installed." + - Log.ENDC + "\n Install Anemometer with:" - + Log.BOLD + "\n `wo stack install --utils`" - + Log.ENDC) + Log.ENDC + "\n Install Anemometer with:" + + Log.BOLD + "\n `wo stack install --utils`" + + Log.ENDC) def load(app): diff --git a/wo/cli/plugins/log.py b/wo/cli/plugins/log.py index 5f7436f..5b08189 100644 --- a/wo/cli/plugins/log.py +++ b/wo/cli/plugins/log.py @@ -444,7 +444,8 @@ class WOLogMailController(CementBaseController): (['--nginx'], dict(help='Mail Nginx Error logs file', action='store_true')), (['--php'], - dict(help='Mail PHP 7.2 Error logs file', action='store_true')), + dict(help='Mail PHP 7.2 Error logs file', + action='store_true')), (['--fpm'], dict(help='Mail PHP 7.2-fpm slow logs file', action='store_true')), diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index 0e844aa..43250f8 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -107,7 +107,8 @@ class WOStackUpgradeController(CementBaseController): if self.app.pargs.php: if WOAptGet.is_installed(self, 'php7.2-fpm'): if not WOAptGet.is_installed(self, 'php7.3-fpm'): - apt_packages = apt_packages + WOVariables.wo_php + WOVariables.wo_php_extra + apt_packages = apt_packages + WOVariables.wo_php + \ + WOVariables.wo_php_extra else: apt_packages = apt_packages + WOVariables.wo_php else: diff --git a/wo/core/cron.py b/wo/core/cron.py index abd3bd6..02e9e81 100644 --- a/wo/core/cron.py +++ b/wo/core/cron.py @@ -7,8 +7,10 @@ Set CRON on LINUX system. class WOCron(): - def setcron_weekly(self, cmd, comment='Cron set by WordOps', user='root', min=0, hour=12): - if not WOShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)): + def setcron_weekly(self, cmd, comment='Cron set by WordOps', user='root', + min=0, hour=12): + if not WOShellExec.cmd_exec(self, "crontab -l " + "| grep -q \'{0}\'".format(cmd)): WOShellExec.cmd_exec(self, "/bin/bash -c \"crontab -l " "2> /dev/null | {{ cat; echo -e" @@ -20,7 +22,8 @@ class WOCron(): Log.debug(self, "Cron set") def remove_cron(self, cmd): - if WOShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)): + if WOShellExec.cmd_exec(self, "crontab -l " + "| grep -q \'{0}\'".format(cmd)): if not WOShellExec.cmd_exec(self, "/bin/bash -c " "\"crontab " "-l | sed '/{0}/d'" diff --git a/wo/core/mysql.py b/wo/core/mysql.py index 6b1f115..af2d638 100644 --- a/wo/core/mysql.py +++ b/wo/core/mysql.py @@ -112,7 +112,7 @@ class WOMysql(): " --single-transaction".format(dbs), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - p2 = subprocess.Popen("gzip -c > /var/wo-mysqlbackup/{0}{1}.s" + p2 = subprocess.Popen("pigz -c > /var/wo-mysqlbackup/{0}{1}.s" "ql.gz".format(dbs, WOVariables.wo_date), stdin=p1.stdout, shell=True) diff --git a/wo/core/services.py b/wo/core/services.py index c028880..a6e4c04 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -116,7 +116,8 @@ class WOService(): try: is_exist = subprocess.getstatusoutput('which {0}' .format(service_name)) - if is_exist[0] == 0 or service_name in ['php7.2-fpm', 'php7.3-fpm']: + if is_exist[0] == 0 or service_name in ['php7.2-fpm', + 'php7.3-fpm']: retcode = subprocess.getstatusoutput('service {0} status' .format(service_name)) if retcode[0] == 0: From 7cf6d440865aa0b6095a34e9a7388273f8439424 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 29 Apr 2019 13:13:44 +0200 Subject: [PATCH 15/45] Add support for Ubuntu 19.04 Disco --- CHANGELOG.md | 1 + README.md | 17 ++++++++++------- install | 4 ++-- wo/cli/plugins/stack.py | 31 ++++++++++++++++--------------- wo/core/variables.py | 5 ++++- 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 360a141..8df5576 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Extplorer filemanager - Enable OSCP Stapling with Let's Encrypt - Compress database backup with pigz before updating sites +- Add support for Ubuntu 19.04 disco #### Changed diff --git a/README.md b/README.md index 8c028b7..17df59f 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,14 @@

-build +build MIT Commits -GitHub release - +GitHub release +
+Badge Twitter +Badge Slack +

@@ -27,10 +30,9 @@ License

- WordOps site • -Documentation • -Community forum • -Slack + WordOps.net • +Documentation • +Community forum

@@ -53,6 +55,7 @@ - Ubuntu 16.04 LTS (Xenial) - Ubuntu 18.04 LTS (Bionic) +- Ubuntu 19.04 (Disco) - Debian 8 (Jessie) - Debian 9 (Stretch) diff --git a/install b/install index 1dbc233..1eb57b4 100755 --- a/install +++ b/install @@ -139,9 +139,9 @@ if [ -z "$wo_force_install" ]; then wo_lib_echo_fail "other Linux distributions and perhaps even Unix deratives." exit 100 else - check_wo_linux_distro=$(lsb_release -sc | grep -E "trusty|xenial|bionic|jessie|stretch") + check_wo_linux_distro=$(lsb_release -sc | grep -E "trusty|xenial|bionic|disco|jessie|stretch") if [ -z "$check_wo_linux_distro" ]; then - wo_lib_echo_fail "WordOps (wo) only supports Ubuntu 14.04/16.04/18.04, Debian 8.x and Debian 9.x" + wo_lib_echo_fail "WordOps (wo) only supports Ubuntu 14.04/16.04/18.04/19.04 LTS, Debian 8.x and Debian 9.x" exit 100 fi fi diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 732fbea..8eafe59 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -92,21 +92,22 @@ class WOStackController(CementBaseController): """Pre settings to do before installation packages""" if set(WOVariables.wo_mysql).issubset(set(apt_packages)): - Log.info(self, "Adding repository for MySQL, please wait...") - mysql_pref = ("Package: *\nPin: origin " - "sfo1.mirrors.digitalocean.com" - "\nPin-Priority: 1000\n") - with open('/etc/apt/preferences.d/' - 'MariaDB.pref', 'w') as mysql_pref_file: - mysql_pref_file.write(mysql_pref) - WORepo.add(self, repo_url=WOVariables.wo_mysql_repo) - Log.debug(self, 'Adding key for {0}' - .format(WOVariables.wo_mysql_repo)) - WORepo.add_key(self, '0xcbcb082a1bb943db', - keyserver="keyserver.ubuntu.com") - WORepo.add_key(self, '0xF1656F24C74CD1D8', - keyserver="keyserver.ubuntu.com") - chars = ''.join(random.sample(string.ascii_letters, 16)) + if (WOVariables.wo_platform_codename != 'disco'): + Log.info(self, "Adding repository for MySQL, please wait...") + mysql_pref = ("Package: *\nPin: origin " + "sfo1.mirrors.digitalocean.com" + "\nPin-Priority: 1000\n") + with open('/etc/apt/preferences.d/' + 'MariaDB.pref', 'w') as mysql_pref_file: + mysql_pref_file.write(mysql_pref) + WORepo.add(self, repo_url=WOVariables.wo_mysql_repo) + Log.debug(self, 'Adding key for {0}' + .format(WOVariables.wo_mysql_repo)) + WORepo.add_key(self, '0xcbcb082a1bb943db', + keyserver="keyserver.ubuntu.com") + WORepo.add_key(self, '0xF1656F24C74CD1D8', + keyserver="keyserver.ubuntu.com") + chars = ''.join(random.sample(string.ascii_letters, 24)) Log.debug(self, "Pre-seeding MySQL") Log.debug(self, "echo \"mariadb-server-10.3 " "mysql-server/root_password " diff --git a/wo/core/variables.py b/wo/core/variables.py index 1fae267..293d79a 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -13,7 +13,7 @@ class WOVariables(): # WordOps version wo_version = "3.9.5" # WordOps packages versions - wo_wp_cli = "2.1.0" + wo_wp_cli = "2.2.0" wo_adminer = "4.7.1" # Get WPCLI path @@ -102,6 +102,9 @@ class WOVariables(): elif wo_platform_codename == 'bionic': wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" "/virtubox:/WordOps/xUbuntu_18.04/ /") + elif wo_platform_codename == 'disco': + wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" + "/virtubox:/WordOps/xUbuntu_19.04/ /") elif wo_platform_codename == 'jessie': wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" "/virtubox:/WordOps/Debian_8.0/ /") From e16c61113b1b66f565e627c4f4c26c0d9b2f89f2 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 29 Apr 2019 16:09:18 +0200 Subject: [PATCH 16/45] fix proxy webroot --- wo/cli/plugins/site.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 86ecb10..a21c198 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -147,10 +147,6 @@ class WOSiteController(CementBaseController): wo_db_user = siteinfo.db_user wo_db_pass = siteinfo.db_password wo_db_host = siteinfo.db_host - if sitetype == "proxy": - access_log = "/var/log/nginx/{0}.access.log".format(wo_domain) - error_log = "/var/log/nginx/{0}.error.log".format(wo_domain) - wo_site_webroot = '' php_version = siteinfo.php_version From cb84089e51877f5807ccca0ea66b3d49a0956a62 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 14:39:55 +0200 Subject: [PATCH 17/45] extract phpmemcachedadmin in the proper folder --- wo/cli/plugins/stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 8eafe59..1cd236a 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1200,7 +1200,7 @@ class WOStackController(CementBaseController): " {0}22222/htdocs/cache/memcached " .format(WOVariables.wo_webroot)) WOExtract.extract(self, '/tmp/memcached.tar.gz', - '{0}22222/htdocs/cache/memcached' + '{0}22222/htdocs/cache/memcached/' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " "{0}22222/htdocs/cache/memcached file" From 9a55d394f120dbca54d877ca50a6d47c31ff7a7e Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 16:05:02 +0200 Subject: [PATCH 18/45] Add certificate removal --- wo/cli/plugins/site_functions.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 693fbab..f8fa3d9 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1221,6 +1221,19 @@ def removeNginxConf(self, domain): .format(domain)) +def removeAcmeConf(self, domain): + if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)): + Log.debug(self, "Removing Acme configuration") + WOFileUtils.rm(self, '/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)) + WOFileUtils.rm(self, '/etc/letsencrypt/live/{0}' + .format(domain)) + WOGit.add(self, ["/etc/letsencrypt"], + msg="Deleted {0} " + .format(domain)) + + def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='', dbhost=''): """ From f8f73fd28ab3bbad7f48f839802032def5a1c160 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 16:06:16 +0200 Subject: [PATCH 19/45] add acme removal action --- wo/cli/plugins/site_functions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index f8fa3d9..e23ee87 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1245,6 +1245,10 @@ def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='', if os.path.isfile('/etc/nginx/sites-available/{0}' .format(domain)): removeNginxConf(self, domain) + if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)): + removeAcmeConf(self, domain) + if webroot: deleteWebRoot(self, webroot) @@ -1423,6 +1427,8 @@ def setupLetsEncryptSubdomain(self, wo_domain_name): "\n to allow it to verify the site automatically.") # letsencrypt cert renewal + + def renewLetsEncrypt(self, wo_domain_name): ssl = WOShellExec.cmd_exec( From 98cd8f349d729a854a9842023b9320eabb94a344 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 16:55:14 +0200 Subject: [PATCH 20/45] Fix acme.sh migration and backup cert before update/upgrade --- install | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/install b/install index 1eb57b4..37bfa17 100755 --- a/install +++ b/install @@ -354,7 +354,7 @@ wo_update_wp_cli() { wo_install_acme_sh() { # check if acme.sh is already installed - if [ ! -d /opt/acme.sh ]; then + if [ ! -x /etc/letsencrypt/acme.sh ]; then { # clone the git repository git clone https://github.com/Neilpang/acme.sh.git /opt/acme.sh -q @@ -388,7 +388,6 @@ wo_install_acme_sh() { --exclude="dnsapi" \ --exclude="http.header" \ --exclude="ca" \ - --del \ "$HOME/.acme.sh/" \ /etc/letsencrypt/renewal/ @@ -621,11 +620,11 @@ wo_git_init() { } wo_backup_ee() { - tar -I pigz -cf "$EE_BACKUP_FILE" /etc/nginx /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee >> /var/log/wo/install.log 2>&1 + tar -I pigz -cf "$EE_BACKUP_FILE" /etc/nginx /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee /etc/letsencrypt >> /var/log/wo/install.log 2>&1 } wo_backup_wo() { - tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx/ /usr/local/lib/python3.6/dist-packages/wo-*.egg /etc/wo /var/lib/wo >> /var/log/wo/install.log 2>&1 + tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx/ /usr/local/lib/python3.6/dist-packages/wo-*.egg /etc/wo /var/lib/wo /etc/letsencrypt >> /var/log/wo/install.log 2>&1 } wo_clean_ee() { From 573b1a0665d8078c6a2205aa3d1b5c6555ed8116 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 18:44:35 +0200 Subject: [PATCH 21/45] Several fix and improvements * fix acme.sh migration with previous install * add support for raspbian (testing) * fix memcache folder in WordOps dashboard * improve install code quality --- install | 54 ++++++++++++++++++++++++++++------------- wo/cli/plugins/stack.py | 34 +++++++++++++++++--------- 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/install b/install index 37bfa17..a534f34 100755 --- a/install +++ b/install @@ -133,15 +133,15 @@ fi # 1 - Checking linux distro ### if [ -z "$wo_force_install" ]; then - if [ "$wo_linux_distro" != "Ubuntu" ] && [ "$wo_linux_distro" != "Debian" ]; then - wo_lib_echo_fail "WordOps (wo) only supports Ubuntu and Debian at the moment." + if [ "$wo_linux_distro" != "Ubuntu" ] && [ "$wo_linux_distro" != "Debian" ] && [ "$wo_linux_distro" != "Raspbian" ]; then + wo_lib_echo_fail "WordOps (wo) only supports Ubuntu, Debian & Raspbian at the moment." wo_lib_echo_fail "If you are feeling adventurous, you are free to fork WordOps to support" wo_lib_echo_fail "other Linux distributions and perhaps even Unix deratives." exit 100 else check_wo_linux_distro=$(lsb_release -sc | grep -E "trusty|xenial|bionic|disco|jessie|stretch") if [ -z "$check_wo_linux_distro" ]; then - wo_lib_echo_fail "WordOps (wo) only supports Ubuntu 14.04/16.04/18.04/19.04 LTS, Debian 8.x and Debian 9.x" + wo_lib_echo_fail "WordOps (wo) only supports Ubuntu 14.04/16.04/18.04/19.04 LTS, Debian 8.x, Debian 9.x and Raspbian 9.x" exit 100 fi fi @@ -357,7 +357,11 @@ wo_install_acme_sh() { if [ ! -x /etc/letsencrypt/acme.sh ]; then { # clone the git repository - git clone https://github.com/Neilpang/acme.sh.git /opt/acme.sh -q + if [ -d /opt/acme.sh/.git ]; then + git -C /opt/acme.sh pull origin master + else + git clone https://github.com/Neilpang/acme.sh.git /opt/acme.sh -q + fi cd /opt/acme.sh || exit 1 # create conf directories [ ! -d /etc/letsencrypt/config ] && { @@ -379,8 +383,11 @@ wo_install_acme_sh() { } >> "$wo_install_log" 2>&1 fi - if [ -d "$HOME/.acme.sh" ]; then + if [ -x "$HOME/.acme.sh/acme.sh" ]; then { + # backup acme.sh folder + /bin/tar -I pigz -cf /var/lib/wo-backup/acme.sh.tar.gz "$HOME/.acme.sh" + # rsync previous certificates to new acme.sh location /usr/bin/rsync -rltgoDpz --exclude="account.conf" \ --exclude="acme.sh" \ --exclude="acme.sh.env" \ @@ -390,6 +397,11 @@ wo_install_acme_sh() { --exclude="ca" \ "$HOME/.acme.sh/" \ /etc/letsencrypt/renewal/ + # remove previous acme.sh folder + rm -rf "$HOME/.acme.sh" + # create acme.sh.env file inlcuded in .bashrc to avoid error when logging in + mkdir -p "$HOME/.acme.sh" + echo '' > "$HOME/.acme.sh/acme.sh.env" } >> "$wo_install_log" 2>&1 fi @@ -546,7 +558,7 @@ wo_update_latest() { if [ -f /etc/ImageMagick/policy.xml ]; then if [ ! -f /etc/ImageMagick/patch.txt ]; then - echo -e "\t\n\t\n\t\n\t\n\t" >> /etc/ImageMagick/patch.txt + echo -e "\t\n\t\n\t\n\t\n\t" >> /etc/ImageMagick/patch.txt sed -i '//r /etc/ImageMagick/patch.txt' /etc/ImageMagick/policy.xml fi fi @@ -576,10 +588,10 @@ wo_update_latest() { # Fix Redis-server security issue # http://redis.io/topics/security if [ -f /etc/redis/redis.conf ]; then - grep -0 -v "#" /etc/redis/redis.conf | grep 'bind' >> /dev/null 2>&1 + CHECK_REDIS_BIND=$(grep -0 -v "#" /etc/redis/redis.conf | grep 'bind' >> /dev/null 2>&1) - if [ "$?" -ne 0 ]; then - sed -i '$ a bind 127.0.0.1' /etc/redis/redis.conf & + if [ -z "$CHECK_REDIS_BIND" ]; then + echo 'bind 127.0.0.1 ::1' >> /etc/redis/redis.conf service redis-server restart > /dev/null 2>&1 @@ -593,9 +605,9 @@ wo_git_init() { # Nginx under git version control [ -d /etc/nginx ] && { cd /etc/nginx || exit 1 - if [ ! -d /etc/nginx/.git ]; then + [ ! -d /etc/nginx/.git ] && { git init - fi + } git add -A . git commit -am "Updated Nginx" } >> /var/log/wo/install.log 2>&1 @@ -611,20 +623,20 @@ wo_git_init() { # PHP under git version control [ -d /etc/php ] && { cd /etc/php || exit 1 - if [ ! -d /etc/php/.git ]; then + [ ! -d /etc/php/.git ] && { git init - fi + } git add -A . git commit -am "Updated PHP" } >> /var/log/wo/install.log 2>&1 } wo_backup_ee() { - tar -I pigz -cf "$EE_BACKUP_FILE" /etc/nginx /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee /etc/letsencrypt >> /var/log/wo/install.log 2>&1 + /bin/tar -I pigz -cf "$EE_BACKUP_FILE" /etc/nginx /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee /etc/letsencrypt >> /var/log/wo/install.log 2>&1 } wo_backup_wo() { - tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx/ /usr/local/lib/python3.6/dist-packages/wo-*.egg /etc/wo /var/lib/wo /etc/letsencrypt >> /var/log/wo/install.log 2>&1 + /bin/tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx /usr/local/lib/python3.6/dist-packages/wo-*.egg /etc/wo /var/lib/wo /etc/letsencrypt >> /var/log/wo/install.log 2>&1 } wo_clean_ee() { @@ -655,7 +667,11 @@ if [ -x /usr/local/bin/wo ]; then wo_lib_echo "Syncing WO database" | tee -ai $wo_install_log secure_wo_db | tee -ai $wo_install_log wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log - wo_install >> wo_install_log 2>&1 + if [ -f "$HOME/.gitconfig" ]; then + wo_install >> wo_install_log 2>&1 + else + wo_install | tee -ai $wo_install_log + fi if [ -x "$(command -v nginx)" ]; then wo_lib_echo "Upgrading Nginx" | tee -ai $wo_install_log wo_upgrade_nginx | tee -ai $wo_install_log @@ -685,7 +701,11 @@ else wo_sync_db | tee -ai $wo_install_log secure_wo_db | tee -ai $wo_install_log wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log - wo_install >> wo_install_log 2>&1 + if [ -f "$HOME/.gitconfig" ]; then + wo_install >> wo_install_log 2>&1 + else + wo_install | tee -ai $wo_install_log + fi if [ -x "$(command -v nginx)" ]; then wo_lib_echo "Upgrading Nginx" | tee -ai $wo_install_log wo_upgrade_nginx | tee -ai $wo_install_log diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 1cd236a..f14a24a 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -92,7 +92,9 @@ class WOStackController(CementBaseController): """Pre settings to do before installation packages""" if set(WOVariables.wo_mysql).issubset(set(apt_packages)): - if (WOVariables.wo_platform_codename != 'disco'): + # add mariadb repository excepted on raspbian and ubuntu 19.04 + if (not WOVariables.wo_platform_codename == 'disco') and + (not WOVariables.wo_platform_distro == 'raspbian'): Log.info(self, "Adding repository for MySQL, please wait...") mysql_pref = ("Package: *\nPin: origin " "sfo1.mirrors.digitalocean.com" @@ -107,7 +109,9 @@ class WOStackController(CementBaseController): keyserver="keyserver.ubuntu.com") WORepo.add_key(self, '0xF1656F24C74CD1D8', keyserver="keyserver.ubuntu.com") + # generate random 24 characters root password chars = ''.join(random.sample(string.ascii_letters, 24)) + # configure MySQL non-interactive install Log.debug(self, "Pre-seeding MySQL") Log.debug(self, "echo \"mariadb-server-10.3 " "mysql-server/root_password " @@ -136,7 +140,7 @@ class WOStackController(CementBaseController): log=False) except CommandExecutionError as e: Log.error("Failed to initialize MySQL package") - + # generate my.cnf root credentials mysql_config = """ [client] user = root @@ -153,12 +157,14 @@ class WOStackController(CementBaseController): Log.debug(self, 'Setting my.cnf permission') WOFileUtils.chmod(self, "/etc/mysql/conf.d/my.cnf", 0o600) + # add nginx repository if set(WOVariables.wo_nginx).issubset(set(apt_packages)): Log.info(self, "Adding repository for NGINX, please wait...") WORepo.add(self, repo_url=WOVariables.wo_nginx_repo) Log.debug(self, 'Adding repository for Nginx') WORepo.add_key(self, WOVariables.wo_nginx_key) + # add php repository if (set(WOVariables.wo_php73).issubset(set(apt_packages)) or set(WOVariables.wo_php).issubset(set(apt_packages))): if (WOVariables.wo_platform_distro == 'ubuntu'): @@ -172,7 +178,7 @@ class WOStackController(CementBaseController): WORepo.add(self, repo_url=WOVariables.wo_php_repo) Log.debug(self, 'Adding deb.sury GPG key') WORepo.add_key(self, WOVariables.wo_php_key) - + # add redis repository if set(WOVariables.wo_redis).issubset(set(apt_packages)): Log.info(self, "Adding repository for Redis, please wait...") if WOVariables.wo_platform_distro == 'ubuntu': @@ -644,7 +650,7 @@ class WOStackController(CementBaseController): "/var/run/php/php73-fpm.sock;\n}\n" "upstream debug73 {\nserver " "127.0.0.1:9173;\n}\n") - + # create nginx configuration for redis if set(WOVariables.wo_redis).issubset(set(apt_packages)): if (os.path.isfile("/etc/nginx/nginx.conf") and not os.path.isfile("/etc/nginx/common/" @@ -994,6 +1000,7 @@ class WOStackController(CementBaseController): WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") WOService.restart_service(self, 'php7.3-fpm') + # create mysql config if it doesn't exist if set(WOVariables.wo_mysql).issubset(set(apt_packages)): if not os.path.isfile("/etc/mysql/my.cnf"): config = ("[mysqld]\nwait_timeout = 30\n" @@ -1019,6 +1026,7 @@ class WOStackController(CementBaseController): WOGit.add(self, ["/etc/mysql"], msg="Adding MySQL into Git") WOService.reload_service(self, 'mysql') + # create fail2ban configuration files if set(WOVariables.wo_fail2ban).issubset(set(apt_packages)): if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"): data = dict() @@ -1197,13 +1205,13 @@ class WOStackController(CementBaseController): if any('/tmp/memcached.tar.gz' == x[1] for x in packages): Log.debug(self, "Extracting memcached.tar.gz to location" - " {0}22222/htdocs/cache/memcached " + " {0}22222/htdocs/cache/memcache " .format(WOVariables.wo_webroot)) WOExtract.extract(self, '/tmp/memcached.tar.gz', - '{0}22222/htdocs/cache/memcached/' + '{0}22222/htdocs/cache/memcache/' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " - "{0}22222/htdocs/cache/memcached file" + "{0}22222/htdocs/cache/memcache file" .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222' .format(WOVariables.wo_webroot), @@ -1309,7 +1317,7 @@ class WOStackController(CementBaseController): if any('/usr/bin/pt-query-advisor' == x[1] for x in packages): WOFileUtils.chmod(self, "/usr/bin/pt-query-advisor", 0o775) - # ph + # phpredisadmin if any('/tmp/pra.tar.gz' == x[1] for x in packages): if not os.path.exists('{0}22222/htdocs/cache/redis' @@ -1479,8 +1487,10 @@ class WOStackController(CementBaseController): packages = packages + [["https://github.com/phpmyadmin/" "phpmyadmin/archive/STABLE.tar.gz", "/tmp/pma.tar.gz", "phpMyAdmin"], - ["https://getcomposer.org/installer", - "/tmp/composer-install", "Composer"]] + ["https://getcomposer.org/" + "installer", + "/tmp/composer-install", + "Composer"]] else: packages = packages + [["https://github.com/phpmyadmin/" "phpmyadmin/archive/STABLE.tar.gz", @@ -1759,7 +1769,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot), '{0}22222/htdocs/cache/nginx/' 'clean.php'.format(WOVariables.wo_webroot), - '{0}22222/htdocs/cache/memcached' + '{0}22222/htdocs/cache/memcache' .format(WOVariables.wo_webroot), '/usr/bin/pt-query-advisor', '{0}22222/htdocs/db/anemometer' @@ -1891,7 +1901,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot), '{0}22222/htdocs/cache/nginx/' 'clean.php'.format(WOVariables.wo_webroot), - '{0}22222/htdocs/cache/memcached' + '{0}22222/htdocs/cache/memcache' .format(WOVariables.wo_webroot), '/usr/bin/pt-query-advisor', '{0}22222/htdocs/db/anemometer' From 3e454e66f248e7a11361b80d83782c610745207a Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 18:50:30 +0200 Subject: [PATCH 22/45] remove "len" usage in stack --- wo/cli/plugins/stack.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index f14a24a..2512bf2 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -190,7 +190,7 @@ class WOStackController(CementBaseController): @expose(hide=True) def post_pref(self, apt_packages, packages): """Post activity after installation of packages""" - if len(apt_packages): + if (apt_packages): if set(WOVariables.wo_nginx).issubset(set(apt_packages)): if set(["nginx"]).issubset(set(apt_packages)): @@ -1044,7 +1044,7 @@ class WOStackController(CementBaseController): out=wo_fail2ban) wo_fail2ban.close() - if len(packages): + if (packages): if any('/usr/local/bin/wp' == x[1] for x in packages): Log.debug(self, "Setting Privileges" " to /usr/local/bin/wp file ") @@ -1601,16 +1601,16 @@ class WOStackController(CementBaseController): except Exception as e: pass - if len(apt_packages) or len(packages): + if (apt_packages) or (packages): Log.debug(self, "Calling pre_pref") self.pre_pref(apt_packages) - if len(apt_packages): + if (apt_packages): WOSwap.add(self) Log.info(self, "Updating apt-cache, please wait...") WOAptGet.update(self) Log.info(self, "Installing packages, please wait...") WOAptGet.install(self, apt_packages) - if len(packages): + if (packages): Log.debug(self, "Downloading following: {0}".format(packages)) WODownload.download(self, packages) Log.debug(self, "Calling post_pref") @@ -1657,7 +1657,7 @@ class WOStackController(CementBaseController): "/etc/redis/redis.conf") WOService.restart_service(self, 'redis-server') if disp_msg: - if len(self.msg): + if (self.msg): for msg in self.msg: Log.info(self, Log.ENDC + msg) Log.info(self, "Successfully installed packages") @@ -1775,7 +1775,7 @@ class WOStackController(CementBaseController): '{0}22222/htdocs/db/anemometer' .format(WOVariables.wo_webroot)] - if len(packages) or len(apt_packages): + if (packages) or (apt_packages): wo_prompt = input('Are you sure you to want to' ' remove from server.' '\nPackage configuration will remain' @@ -1789,11 +1789,11 @@ class WOStackController(CementBaseController): if (set(["nginx-custom"]).issubset(set(apt_packages))): WOService.stop_service(self, 'nginx') - if len(packages): + if (packages): WOFileUtils.remove(self, packages) WOAptGet.auto_remove(self) - if len(apt_packages): + if (apt_packages): Log.debug(self, "Removing apt_packages") Log.info(self, "Removing packages, please wait...") WOAptGet.remove(self, apt_packages) @@ -1908,7 +1908,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot) ] - if len(packages) or len(apt_packages): + if (packages) or (apt_packages): wo_prompt = input('Are you sure you to want to purge ' 'from server ' 'along with their configuration' @@ -1921,12 +1921,12 @@ class WOStackController(CementBaseController): if (set(["nginx-custom"]).issubset(set(apt_packages))): WOService.stop_service(self, 'nginx') - if len(apt_packages): + if (apt_packages): Log.info(self, "Purging packages, please wait...") WOAptGet.remove(self, apt_packages, purge=True) WOAptGet.auto_remove(self) - if len(packages): + if (packages): WOFileUtils.remove(self, packages) WOAptGet.auto_remove(self) From 8c21974f0e9a5c074d6ad47aa2ba3cedc6db7654 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 18:51:42 +0200 Subject: [PATCH 23/45] fix identation --- wo/cli/plugins/stack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 2512bf2..715d0a7 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -93,8 +93,8 @@ class WOStackController(CementBaseController): if set(WOVariables.wo_mysql).issubset(set(apt_packages)): # add mariadb repository excepted on raspbian and ubuntu 19.04 - if (not WOVariables.wo_platform_codename == 'disco') and - (not WOVariables.wo_platform_distro == 'raspbian'): + if ((not WOVariables.wo_platform_codename == 'disco') and + (not WOVariables.wo_platform_distro == 'raspbian')): Log.info(self, "Adding repository for MySQL, please wait...") mysql_pref = ("Package: *\nPin: origin " "sfo1.mirrors.digitalocean.com" From 09e764cba7330f9bcc848857141d2c5429c00712 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 19:00:14 +0200 Subject: [PATCH 24/45] improve code quality according to codacy --- wo/cli/plugins/info.py | 20 ++++++++++---------- wo/cli/plugins/stack.py | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/wo/cli/plugins/info.py b/wo/cli/plugins/info.py index d20d5a6..2d57e31 100644 --- a/wo/cli/plugins/info.py +++ b/wo/cli/plugins/info.py @@ -41,7 +41,7 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_nginx(self): """Display Nginx information""" - version = os.popen("nginx -v 2>&1 | awk -F '/' '{print $2}' | " + version = os.popen("/usr/sbin/nginx -v 2>&1 | awk -F '/' '{print $2}' | " "awk -F ' ' '{print $1}' | tr '\n' ' '").read() allow = os.popen("grep ^allow /etc/nginx/common/acl.conf | " "cut -d' ' -f2 | cut -d';' -f1 | tr '\n' ' '").read() @@ -66,7 +66,7 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_php(self): """Display PHP information""" - version = os.popen("php7.2 -v 2>/dev/null | head -n1 | cut -d' ' -f2 |" + version = os.popen("/usr/bin/php7.2 -v 2>/dev/null | head -n1 | cut -d' ' -f2 |" " cut -d'+' -f1 | tr -d '\n'").read config = configparser.ConfigParser() config.read('/etc/{0}/fpm/php.ini'.format("php/7.2")) @@ -140,7 +140,7 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_php73(self): """Display PHP information""" - version = os.popen("php7.3 -v 2>/dev/null | head -n1 | cut -d' ' -f2 |" + version = os.popen("/usr/bin/php7.3 -v 2>/dev/null | head -n1 | cut -d' ' -f2 |" " cut -d'+' -f1 | tr -d '\n'").read config = configparser.ConfigParser() config.read('/etc/php/7.3/fpm/php.ini') @@ -214,23 +214,23 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_mysql(self): """Display MySQL information""" - version = os.popen("mysql -V | awk '{print($5)}' | cut -d ',' " + version = os.popen("/usr/bin/mysql -V | awk '{print($5)}' | cut -d ',' " "-f1 | tr -d '\n'").read() host = "localhost" - port = os.popen("mysql -e \"show variables\" | grep ^port | awk " + port = os.popen("/usr/bin/mysql -e \"show variables\" | grep ^port | awk " "'{print($2)}' | tr -d '\n'").read() - wait_timeout = os.popen("mysql -e \"show variables\" | grep " + wait_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " "^wait_timeout | awk '{print($2)}' | " "tr -d '\n'").read() - interactive_timeout = os.popen("mysql -e \"show variables\" | grep " + interactive_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " "^interactive_timeout | awk " "'{print($2)}' | tr -d '\n'").read() - max_used_connections = os.popen("mysql -e \"show global status\" | " + max_used_connections = os.popen("/usr/bin/mysql -e \"show global status\" | " "grep Max_used_connections | awk " "'{print($2)}' | tr -d '\n'").read() - datadir = os.popen("mysql -e \"show variables\" | grep datadir | awk" + datadir = os.popen("/usr/bin/mysql -e \"show variables\" | grep datadir | awk" " '{print($2)}' | tr -d '\n'").read() - socket = os.popen("mysql -e \"show variables\" | grep \"^socket\" | " + socket = os.popen("/usr/bin/mysql -e \"show variables\" | grep \"^socket\" | " "awk '{print($2)}' | tr -d '\n'").read() data = dict(version=version, host=host, port=port, wait_timeout=wait_timeout, diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 715d0a7..f0dbfc3 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -16,7 +16,6 @@ from wo.core.git import WOGit from wo.core.checkfqdn import check_fqdn from pynginxconfig import NginxConfig from wo.core.services import WOService -from wo.core.variables import WOVariables import random import string import configparser From b1e6f22e319634d37540613bffe10f2bfa90f892 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 19:05:54 +0200 Subject: [PATCH 25/45] [skip travis] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df5576..d9365a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Enable OSCP Stapling with Let's Encrypt - Compress database backup with pigz before updating sites - Add support for Ubuntu 19.04 disco +- Add support for Raspbian +- backup letsencrypt certificate before upgrade #### Changed @@ -70,6 +72,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - phpredisadmin setup - --hsts flag with basic html site - hsts flag on site not secure with letsencrypt +- fix import of previous acme.sh certificate ### v3.9.4 - 2019-03-15 From b6542bbb34e2edc9c6ae952a98a5ec42e31d6ae4 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 30 Apr 2019 19:55:55 +0200 Subject: [PATCH 26/45] improve code quality according to codacy --- wo/cli/plugins/info.py | 27 ++++++++++++++++++--------- wo/core/apt_repo.py | 16 ++++++++-------- wo/core/aptget.py | 24 ++++++++++++++++-------- wo/core/mysql.py | 10 ++++++---- wo/core/sslutils.py | 6 ++++-- wo/core/variables.py | 5 +++-- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/wo/cli/plugins/info.py b/wo/cli/plugins/info.py index 2d57e31..9e071d7 100644 --- a/wo/cli/plugins/info.py +++ b/wo/cli/plugins/info.py @@ -41,7 +41,8 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_nginx(self): """Display Nginx information""" - version = os.popen("/usr/sbin/nginx -v 2>&1 | awk -F '/' '{print $2}' | " + version = os.popen("/usr/sbin/nginx -v 2>&1 | " + "awk -F '/' '{print $2}' | " "awk -F ' ' '{print $1}' | tr '\n' ' '").read() allow = os.popen("grep ^allow /etc/nginx/common/acl.conf | " "cut -d' ' -f2 | cut -d';' -f1 | tr '\n' ' '").read() @@ -66,7 +67,8 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_php(self): """Display PHP information""" - version = os.popen("/usr/bin/php7.2 -v 2>/dev/null | head -n1 | cut -d' ' -f2 |" + version = os.popen("/usr/bin/php7.2 -v 2>/dev/null | " + "head -n1 | cut -d' ' -f2 |" " cut -d'+' -f1 | tr -d '\n'").read config = configparser.ConfigParser() config.read('/etc/{0}/fpm/php.ini'.format("php/7.2")) @@ -140,7 +142,8 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_php73(self): """Display PHP information""" - version = os.popen("/usr/bin/php7.3 -v 2>/dev/null | head -n1 | cut -d' ' -f2 |" + version = os.popen("/usr/bin/php7.3 -v 2>/dev/null | " + "head -n1 | cut -d' ' -f2 |" " cut -d'+' -f1 | tr -d '\n'").read config = configparser.ConfigParser() config.read('/etc/php/7.3/fpm/php.ini') @@ -214,23 +217,29 @@ class WOInfoController(CementBaseController): @expose(hide=True) def info_mysql(self): """Display MySQL information""" - version = os.popen("/usr/bin/mysql -V | awk '{print($5)}' | cut -d ',' " + version = os.popen("/usr/bin/mysql -V | awk '{print($5)}' | " + "cut -d ',' " "-f1 | tr -d '\n'").read() host = "localhost" - port = os.popen("/usr/bin/mysql -e \"show variables\" | grep ^port | awk " + port = os.popen("/usr/bin/mysql -e \"show variables\" | " + "grep ^port | awk " "'{print($2)}' | tr -d '\n'").read() wait_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " "^wait_timeout | awk '{print($2)}' | " "tr -d '\n'").read() - interactive_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " + interactive_timeout = os.popen("/usr/bin/mysql -e " + "\"show variables\" | grep " "^interactive_timeout | awk " "'{print($2)}' | tr -d '\n'").read() - max_used_connections = os.popen("/usr/bin/mysql -e \"show global status\" | " + max_used_connections = os.popen("/usr/bin/mysql -e " + "\"show global status\" | " "grep Max_used_connections | awk " "'{print($2)}' | tr -d '\n'").read() - datadir = os.popen("/usr/bin/mysql -e \"show variables\" | grep datadir | awk" + datadir = os.popen("/usr/bin/mysql -e \"show variables\" | " + "grep datadir | awk" " '{print($2)}' | tr -d '\n'").read() - socket = os.popen("/usr/bin/mysql -e \"show variables\" | grep \"^socket\" | " + socket = os.popen("/usr/bin/mysql -e \"show variables\" | " + "grep \"^socket\" | " "awk '{print($2)}' | tr -d '\n'").read() data = dict(version=version, host=host, port=port, wait_timeout=wait_timeout, diff --git a/wo/core/apt_repo.py b/wo/core/apt_repo.py index 4c89dae..cfd1f22 100644 --- a/wo/core/apt_repo.py +++ b/wo/core/apt_repo.py @@ -23,8 +23,8 @@ class WORepo(): """ if repo_url is not None: - repo_file_path = ("/etc/apt/sources.list.d/" - + WOVariables().wo_repo_file) + repo_file_path = ("/etc/apt/sources.list.d/" + + WOVariables().wo_repo_file) try: if not os.path.isfile(repo_file_path): with open(repo_file_path, @@ -62,8 +62,8 @@ class WORepo(): "--remove '{ppa_name}'" .format(ppa_name=ppa)) elif repo_url: - repo_file_path = ("/etc/apt/sources.list.d/" - + WOVariables().wo_repo_file) + repo_file_path = ("/etc/apt/sources.list.d/" + + WOVariables().wo_repo_file) try: repofile = open(repo_file_path, "w+") @@ -84,8 +84,8 @@ class WORepo(): """ WOShellExec.cmd_exec(self, "gpg --keyserver {serv}" .format(serv=(keyserver or - "hkp://keyserver.ubuntu.com")) - + " --recv-keys {key}".format(key=keyids)) + "hkp://keyserver.ubuntu.com")) + + " --recv-keys {key}".format(key=keyids)) WOShellExec.cmd_exec(self, "gpg -a --export --armor {0}" - .format(keyids) - + " | apt-key add - ") + .format(keyids) + + " | apt-key add - ") diff --git a/wo/core/aptget.py b/wo/core/aptget.py index bacaef4..a480202 100644 --- a/wo/core/aptget.py +++ b/wo/core/aptget.py @@ -51,7 +51,8 @@ class WOAptGet(): Log.info(self, Log.FAIL + "Whoops, something went wrong...") Log.error(self, "Check the WordOps log for more details " - "`tail /var/log/wo/wordops.log` and please try again...") + "`tail /var/log/wo/wordops.log` " + "and please try again...") except Exception as e: Log.error(self, "apt-get update exited with error") @@ -98,7 +99,8 @@ class WOAptGet(): Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " - "`tail /var/log/wo/wordops.log` and please try again...") + "`tail /var/log/wo/wordops.log` " + "and please try again...") except Exception as e: Log.error(self, "Error while installing packages, " "apt-get exited with error") @@ -124,13 +126,15 @@ class WOAptGet(): Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " - "`tail /var/log/wo/wordops.log` and please try again...") + "`tail /var/log/wo/wordops.log` " + "and please try again...") except Exception as e: Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " - "`tail /var/log/wo/wordops.log` and please try again...") + "`tail /var/log/wo/wordops.log` " + "and please try again...") def remove(self, packages, auto=False, purge=False): all_packages = ' '.join(packages) @@ -153,7 +157,8 @@ class WOAptGet(): Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " - "`tail /var/log/wo/wordops.log` and please try again...") + "`tail /var/log/wo/wordops.log` " + "and please try again...") except Exception as e: Log.error(self, "Error while installing packages, " @@ -186,7 +191,8 @@ class WOAptGet(): def is_installed(self, package_name): """ - Checks if package is available in cache and is installed or not + Checks if package is available in cache " + "and is installed or not returns True if installed otherwise returns False """ apt_cache = apt.cache.Cache() @@ -209,7 +215,8 @@ class WOAptGet(): WORepo.add(self, repo_url=repo_url) if repo_key is not None: WORepo.add_key(self, repo_key) - proc = subprocess.Popen("apt-get update && DEBIAN_FRONTEND=noninteractive " + proc = subprocess.Popen("apt-get update && " + "DEBIAN_FRONTEND=noninteractive " "apt-get install -o " "Dpkg::Options::=\"--force-confdef\"" " -o " @@ -224,7 +231,8 @@ class WOAptGet(): return True else: Log.error( - self, "Error in fetching dpkg package.\nReverting changes ..", False) + self, "Error in fetching dpkg package.\n" + "Reverting changes ..", False) if repo_url is not None: WORepo.remove(self, repo_url=repo_url) return False diff --git a/wo/core/mysql.py b/wo/core/mysql.py index af2d638..c289405 100644 --- a/wo/core/mysql.py +++ b/wo/core/mysql.py @@ -100,20 +100,22 @@ class WOMysql(): '/var/wo-mysqlbackup') os.makedirs('/var/wo-mysqlbackup') - db = subprocess.check_output(["mysql -Bse \'show databases\'"], + db = subprocess.check_output(["/usr/bin/mysql " + "-Bse \'show databases\'"], universal_newlines=True, shell=True).split('\n') for dbs in db: if dbs == "": continue Log.info(self, "Backing up {0} database".format(dbs)) - p1 = subprocess.Popen("mysqldump {0}" + p1 = subprocess.Popen("/usr/bin/mysqldump {0}" " --max_allowed_packet=1024M" " --single-transaction".format(dbs), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - p2 = subprocess.Popen("pigz -c > /var/wo-mysqlbackup/{0}{1}.s" - "ql.gz".format(dbs, WOVariables.wo_date), + p2 = subprocess.Popen("/usr/bin/pigz -c > " + "/var/wo-mysqlbackup/{0}{1}.sql.gz" + .format(dbs, WOVariables.wo_date), stdin=p1.stdout, shell=True) diff --git a/wo/core/sslutils.py b/wo/core/sslutils.py index 161a484..98f33d5 100644 --- a/wo/core/sslutils.py +++ b/wo/core/sslutils.py @@ -19,7 +19,8 @@ class SSL: current_date = WOShellExec.cmd_exec_stdout(self, "date -d \"now\" +%s") expiration_date = WOShellExec.cmd_exec_stdout(self, "date -d \"" - "`openssl x509 -in " + "`/usr/bin/openssl " + "x509 -in " "/etc/letsencrypt/live/" "{0}/cert.pem" " -text -noout|grep " @@ -45,7 +46,8 @@ class SSL: "`tail /var/log/wo/wordops.log` and please try again...") expiration_date = WOShellExec.cmd_exec_stdout(self, "date -d " - "\"`openssl x509 -in " + "\"`/usr/bin/openssl " + "x509 -in " "/etc/letsencrypt/live/" "{0}/cert.pem" " -text -noout|grep " diff --git a/wo/core/variables.py b/wo/core/variables.py index 293d79a..c43002f 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -69,8 +69,9 @@ class WOVariables(): except Exception as e: wo_user = input("Enter your name: ") wo_email = input("Enter your email: ") - os.system("git config --global user.name {0}".format(wo_user)) - os.system("git config --global user.email {0}".format(wo_email)) + os.system("/usr/bin/git config --global user.name {0}".format(wo_user)) + os.system( + "/usr/bin/git config --global user.email {0}".format(wo_email)) # Get System RAM and SWAP details wo_ram = psutil.virtual_memory().total / (1024 * 1024) From 702647587c05c96491fcff8361fd8066f3e268b4 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 00:16:46 +0200 Subject: [PATCH 27/45] fix install on raspbian --- wo/cli/plugins/stack.py | 84 ++++++++++++++++++++++++++++------------- wo/core/variables.py | 46 +++++++++++++--------- 2 files changed, 85 insertions(+), 45 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index f0dbfc3..5cfffdd 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -111,34 +111,64 @@ class WOStackController(CementBaseController): # generate random 24 characters root password chars = ''.join(random.sample(string.ascii_letters, 24)) # configure MySQL non-interactive install - Log.debug(self, "Pre-seeding MySQL") - Log.debug(self, "echo \"mariadb-server-10.3 " - "mysql-server/root_password " - "password \" | " - "debconf-set-selections") - try: - WOShellExec.cmd_exec(self, "echo \"mariadb-server-10.3 " - "mysql-server/root_password " - "password {chars}\" | " - "debconf-set-selections" - .format(chars=chars), - log=False) - except CommandExecutionError as e: - Log.error("Failed to initialize MySQL package") + if (not WOVariables.wo_platform_distro == 'raspbian'): + Log.debug(self, "Pre-seeding MySQL") + Log.debug(self, "echo \"mariadb-server-10.3 " + "mysql-server/root_password " + "password \" | " + "debconf-set-selections") + try: + WOShellExec.cmd_exec(self, "echo \"mariadb-server-10.3 " + "mysql-server/root_password " + "password {chars}\" | " + "debconf-set-selections" + .format(chars=chars), + log=False) + except CommandExecutionError as e: + Log.error("Failed to initialize MySQL package") - Log.debug(self, "echo \"mariadb-server-10.3 " - "mysql-server/root_password_again " - "password \" | " - "debconf-set-selections") - try: - WOShellExec.cmd_exec(self, "echo \"mariadb-server-10.3 " - "mysql-server/root_password_again " - "password {chars}\" | " - "debconf-set-selections" - .format(chars=chars), - log=False) - except CommandExecutionError as e: - Log.error("Failed to initialize MySQL package") + Log.debug(self, "echo \"mariadb-server-10.3 " + "mysql-server/root_password_again " + "password \" | " + "debconf-set-selections") + try: + WOShellExec.cmd_exec(self, "echo \"mariadb-server-10.3 " + "mysql-server/root_password_again " + "password {chars}\" | " + "debconf-set-selections" + .format(chars=chars), + log=False) + except CommandExecutionError as e: + Log.error("Failed to initialize MySQL package") + else: + Log.debug(self, "Pre-seeding MySQL") + Log.debug(self, "echo \"mariadb-server-10.1 " + "mysql-server/root_password " + "password \" | " + "debconf-set-selections") + try: + WOShellExec.cmd_exec(self, "echo \"mariadb-server-10.1 " + "mysql-server/root_password " + "password {chars}\" | " + "debconf-set-selections" + .format(chars=chars), + log=False) + except CommandExecutionError as e: + Log.error("Failed to initialize MySQL package") + + Log.debug(self, "echo \"mariadb-server-10.1 " + "mysql-server/root_password_again " + "password \" | " + "debconf-set-selections") + try: + WOShellExec.cmd_exec(self, "echo \"mariadb-server-10.1 " + "mysql-server/root_password_again " + "password {chars}\" | " + "debconf-set-selections" + .format(chars=chars), + log=False) + except CommandExecutionError as e: + Log.error("Failed to initialize MySQL package") # generate my.cnf root credentials mysql_config = """ [client] diff --git a/wo/core/variables.py b/wo/core/variables.py index c43002f..eb7ea80 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -94,24 +94,35 @@ class WOVariables(): # WordOps stack installation variables # Nginx repo and packages - if wo_platform_codename == 'trusty': + if wo_platform_distro == 'ubuntu': + if wo_platform_codename == 'trusty': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/xUbuntu_14.04/ /") + elif wo_platform_codename == 'xenial': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/xUbuntu_16.04/ /") + elif wo_platform_codename == 'bionic': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/xUbuntu_18.04/ /") + else: + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/xUbuntu_19.04/ /") + elif wo_platform_distro == 'debian': + if wo_platform_codename == 'jessie': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/Debian_8.0/ /") + elif wo_platform_codename == 'stretch': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/Debian_9.0/ /") + else: wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/xUbuntu_14.04/ /") - elif wo_platform_codename == 'xenial': - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/xUbuntu_16.04/ /") - elif wo_platform_codename == 'bionic': - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/xUbuntu_18.04/ /") - elif wo_platform_codename == 'disco': - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/xUbuntu_19.04/ /") - elif wo_platform_codename == 'jessie': - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/Debian_8.0/ /") - elif wo_platform_codename == 'stretch': - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/Debian_9.0/ /") + "/virtubox:/WordOps/Raspbian_9.0/ /") wo_nginx = ["nginx-custom", "nginx-wo"] wo_nginx_key = '188C9FB063F0247A' @@ -161,7 +172,6 @@ class WOVariables(): "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/debian {codename} main" .format(codename=wo_platform_codename)) - wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] wo_fail2ban = "fail2ban" From e85b4c4b23a302c19d714a10bb4597bee16b154f Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 00:38:09 +0200 Subject: [PATCH 28/45] fix raspbian detection --- wo/core/variables.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wo/core/variables.py b/wo/core/variables.py index eb7ea80..86057cd 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -32,7 +32,8 @@ class WOVariables(): wo_date = datetime.datetime.now().strftime('%d%b%Y%H%M%S') # WordOps core variables - wo_platform_distro = platform.linux_distribution()[0].lower() + wo_platform_distro = os.popen("lsb_release -si " + "| tr -d \'\\n\'").read().lower() wo_platform_version = platform.linux_distribution()[1] wo_platform_codename = os.popen("lsb_release -sc | tr -d \'\\n\'").read() From e19bb32d20665938c70228a21faa134d3f72db47 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 00:44:28 +0200 Subject: [PATCH 29/45] fix php packages on raspbian --- wo/core/variables.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wo/core/variables.py b/wo/core/variables.py index 86057cd..86156a3 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -144,7 +144,7 @@ class WOVariables(): wo_php_extra = ["php-memcached", "php-imagick", "memcached", "graphviz", "php-xdebug", "php-msgpack", "php-redis"] wo_php_key = '' - elif wo_platform_distro == 'debian': + else: wo_php_repo = ( "deb https://packages.sury.org/php/ {codename} main" .format(codename=wo_platform_codename)) @@ -160,6 +160,7 @@ class WOVariables(): "php7.3-zip", "php7.3-xml", "php7.3-soap"] wo_php_extra = ["php-memcached", "php-imagick", "memcached", "graphviz", "php-xdebug", "php-msgpack", "php-redis"] + wo_php_key = 'AC0E47584A7A714D' # MySQL repo and packages From 157546a554520a2259b2e2bcc1de197a2a4ec963 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 01:35:51 +0200 Subject: [PATCH 30/45] Update variable and changelog --- CHANGELOG.md | 4 ++-- wo/core/variables.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9365a7..932df22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,8 +47,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - letsencrypt validation with webroot folder - hardened nginx ssl_ecdh_curve - Update phpredisadmin -- Increase MySQL root password size to 16 characters -- Increase MySQL users password size to 16 characters +- Increase MySQL root password size to 24 characters +- Increase MySQL users password size to 24 characters - Nginx locations template is the same for php7.2 & 7.3 - backend SSL configuration now stored in /var/www/22222/conf/nginx/ssl.conf - Install Netdata with static pre-built binaries instead of having to compile it from source diff --git a/wo/core/variables.py b/wo/core/variables.py index 86156a3..d3af7bd 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -169,7 +169,7 @@ class WOVariables(): "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/ubuntu {codename} main" .format(codename=wo_platform_codename)) - elif wo_platform_distro == 'debian': + else: wo_mysql_repo = ("deb [arch=amd64,ppc64el] " "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/debian {codename} main" From 06dcf5d156fb4a1ffc478c7010059e5324154a7a Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 12:06:39 +0200 Subject: [PATCH 31/45] replace /tmp for security according to codacy --- README.md | 1 + install | 15 +++----- wo/cli/plugins/stack.py | 80 ++++++++++++++++++++--------------------- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 17df59f..5a17cb2 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ - Ubuntu 19.04 (Disco) - Debian 8 (Jessie) - Debian 9 (Stretch) +- Raspbian 9 (Stretch) ### Ports requirements diff --git a/install b/install index a534f34..0b552c3 100755 --- a/install +++ b/install @@ -113,6 +113,7 @@ if [ -z "$wo_branch" ]; then fi readonly wo_log_dir=/var/log/wo/ readonly wo_backup_dir=/var/lib/wo-backup/ +readonly wo_tmp_dir=/var/lib/wo/tmp readonly wo_install_log=/var/log/wo/install.log readonly wo_linux_distro=$(lsb_release -is) readonly wo_distro_version=$(lsb_release -sc) @@ -152,21 +153,13 @@ fi ### if [ ! -d "$wo_log_dir" ]; then - wo_lib_echo "Creating WordOps log directory, just a second..." - mkdir -p "$wo_log_dir" || wo_lib_error "Whoops - seems we are unable to create the log directory $wo_log_dir, exit status " $? + wo_lib_echo "Creating WordOps backup, tmp & log directory, just a second..." + mkdir -p "$wo_backup_dir" || wo_lib_error "Whoops - seems we are unable to create the log directory $wo_log_dir, exit status " $? # create wordops log files touch /var/log/wo/{wordops.log,install.log} - chmod -R 700 /var/log/wo || wo_lib_error "Whoops, there was an error setting the permissions on the WordOps log folder, exit status " $? -fi - -if [ ! -d "$wo_backup_dir" ]; then - - wo_lib_echo "Creating WordOps backup directory, just a second..." - mkdir -p "$wo_backup_dir" || wo_lib_error "Whoops - seems we are unable to create the backup directory $wo_backup_dir, exit status " $? - chmod -R 600 "$wo_backup_dir" - + chmod -R 600 "$wo_log_dir" "$wo_backup_dir" "$wo_tmp_dir" || wo_lib_error "Whoops, there was an error setting the permissions on the WordOps log folder, exit status " $? fi ### diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 5cfffdd..8d5bac5 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1079,11 +1079,11 @@ class WOStackController(CementBaseController): " to /usr/local/bin/wp file ") WOFileUtils.chmod(self, "/usr/local/bin/wp", 0o775) - if any('/tmp/pma.tar.gz' == x[1] + if any('/var/lib/wo/tmp/pma.tar.gz' == x[1] for x in packages): - WOExtract.extract(self, '/tmp/pma.tar.gz', '/tmp/') - Log.debug(self, 'Extracting file /tmp/pma.tar.gz to ' - 'location /tmp/') + WOExtract.extract(self, '/var/lib/wo/tmp/pma.tar.gz', '/var/lib/wo/tmp/') + Log.debug(self, 'Extracting file /var/lib/wo/tmp/pma.tar.gz to ' + 'location /var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/db' .format(WOVariables.wo_webroot)): Log.debug(self, "Creating new directory " @@ -1093,7 +1093,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot)) if not os.path.exists('{0}22222/htdocs/db/pma/' .format(WOVariables.wo_webroot)): - shutil.move('/tmp/phpmyadmin-STABLE/', + shutil.move('/var/lib/wo/tmp/phpmyadmin-STABLE/', '{0}22222/htdocs/db/pma/' .format(WOVariables.wo_webroot)) shutil.copyfile('{0}22222/htdocs/db/pma' @@ -1137,12 +1137,12 @@ class WOStackController(CementBaseController): recursive=True) # composer install and phpmyadmin update - if any('/tmp/composer-install' == x[1] + if any('/var/lib/wo/tmp/composer-install' == x[1] for x in packages): Log.info(self, "Installing composer, please wait...") - WOShellExec.cmd_exec(self, "php -q /tmp/composer-install " - "--install-dir=/tmp/") - shutil.copyfile('/tmp/composer.phar', + WOShellExec.cmd_exec(self, "php -q /var/lib/wo/tmp/composer-install " + "--install-dir=/var/lib/wo/tmp/") + shutil.copyfile('/var/lib/wo/tmp/composer.phar', '/usr/local/bin/composer') WOFileUtils.chmod(self, "/usr/local/bin/composer", 0o775) Log.info(self, "Updating phpMyAdmin, please wait...") @@ -1150,12 +1150,12 @@ class WOStackController(CementBaseController): "update -n --no-dev -d " "/var/www/22222/htdocs/db/pma/") # netdata install - if any('/tmp/kickstart.sh' == x[1] + if any('/var/lib/wo/tmp/kickstart.sh' == x[1] for x in packages): if ((not os.path.exists('/opt/netdata')) and (not os.path.exists('/etc/netdata'))): Log.info(self, "Installing Netdata, please wait...") - WOShellExec.cmd_exec(self, "bash /tmp/kickstart.sh " + WOShellExec.cmd_exec(self, "bash /var/lib/wo/tmp/kickstart.sh " "--dont-wait") # disable mail notifications WOFileUtils.searchreplace(self, "/opt/netdata/usr/" @@ -1183,14 +1183,14 @@ class WOStackController(CementBaseController): WOService.restart_service(self, 'netdata') # WordOps Dashboard - if any('/tmp/wo-dashboard.tar.gz' == x[1] + if any('/var/lib/wo/tmp/wo-dashboard.tar.gz' == x[1] for x in packages): if not os.path.isfile('{0}22222/htdocs/index.php' .format(WOVariables.wo_webroot)): Log.debug(self, "Extracting wo-dashboard.tar.gz " "to location {0}22222/htdocs/" .format(WOVariables.wo_webroot)) - WOExtract.extract(self, '/tmp/wo-dashboard.tar.gz', + WOExtract.extract(self, '/var/lib/wo/tmp/wo-dashboard.tar.gz', '{0}22222/htdocs' .format(WOVariables.wo_webroot)) if WOVariables.wo_wan != 'eth0': @@ -1209,16 +1209,16 @@ class WOStackController(CementBaseController): recursive=True) # Extplorer FileManager - if any('/tmp/extplorer.tar.gz' == x[1] + if any('/var/lib/wo/tmp/extplorer.tar.gz' == x[1] for x in packages): if not os.path.exists('{0}22222/htdocs/files' .format(WOVariables.wo_webroot)): Log.debug(self, "Extracting explorer.tar.gz " "to location {0}22222/htdocs/files" .format(WOVariables.wo_webroot)) - WOExtract.extract(self, '/tmp/extplorer.tar.gz', - '/tmp/') - shutil.move('/tmp/extplorer-2.1.11/', + WOExtract.extract(self, '/var/lib/wo/tmp/extplorer.tar.gz', + '/var/lib/wo/tmp/') + shutil.move('/var/lib/wo/tmp/extplorer-2.1.11/', '{0}22222/htdocs/files' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " @@ -1231,12 +1231,12 @@ class WOStackController(CementBaseController): recursive=True) # phpmemcachedadmin - if any('/tmp/memcached.tar.gz' == x[1] + if any('/var/lib/wo/tmp/memcached.tar.gz' == x[1] for x in packages): Log.debug(self, "Extracting memcached.tar.gz to location" " {0}22222/htdocs/cache/memcache " .format(WOVariables.wo_webroot)) - WOExtract.extract(self, '/tmp/memcached.tar.gz', + WOExtract.extract(self, '/var/lib/wo/tmp/memcached.tar.gz', '{0}22222/htdocs/cache/memcache/' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " @@ -1248,11 +1248,11 @@ class WOStackController(CementBaseController): WOVariables.wo_php_user, recursive=True) # webgrind - if any('/tmp/webgrind.tar.gz' == x[1] + if any('/var/lib/wo/tmp/webgrind.tar.gz' == x[1] for x in packages): Log.debug(self, "Extracting file webgrind.tar.gz to " - "location /tmp/ ") - WOExtract.extract(self, '/tmp/webgrind.tar.gz', '/tmp/') + "location /var/lib/wo/tmp/ ") + WOExtract.extract(self, '/var/lib/wo/tmp/webgrind.tar.gz', '/var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/php' .format(WOVariables.wo_webroot)): Log.debug(self, "Creating directroy " @@ -1262,7 +1262,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot)) if not os.path.exists('{0}22222/htdocs/php/webgrind' .format(WOVariables.wo_webroot)): - shutil.move('/tmp/webgrind-master/', + shutil.move('/var/lib/wo/tmp/webgrind-master/', '{0}22222/htdocs/php/webgrind' .format(WOVariables.wo_webroot)) @@ -1290,11 +1290,11 @@ class WOStackController(CementBaseController): WOVariables.wo_php_user, recursive=True) # anemometer - if any('/tmp/anemometer.tar.gz' == x[1] + if any('/var/lib/wo/tmp/anemometer.tar.gz' == x[1] for x in packages): Log.debug(self, "Extracting file anemometer.tar.gz to " - "location /tmp/ ") - WOExtract.extract(self, '/tmp/anemometer.tar.gz', '/tmp/') + "location /var/lib/wo/tmp/ ") + WOExtract.extract(self, '/var/lib/wo/tmp/anemometer.tar.gz', '/var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/db/' .format(WOVariables.wo_webroot)): Log.debug(self, "Creating directory") @@ -1302,7 +1302,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot)) if not os.path.exists('{0}22222/htdocs/db/anemometer' .format(WOVariables.wo_webroot)): - shutil.move('/tmp/Anemometer-master', + shutil.move('/var/lib/wo/tmp/Anemometer-master', '{0}22222/htdocs/db/anemometer' .format(WOVariables.wo_webroot)) chars = ''.join(random.sample(string.ascii_letters, 8)) @@ -1347,7 +1347,7 @@ class WOStackController(CementBaseController): for x in packages): WOFileUtils.chmod(self, "/usr/bin/pt-query-advisor", 0o775) # phpredisadmin - if any('/tmp/pra.tar.gz' == x[1] + if any('/var/lib/wo/tmp/pra.tar.gz' == x[1] for x in packages): if not os.path.exists('{0}22222/htdocs/cache/redis' .format(WOVariables.wo_webroot)): @@ -1515,29 +1515,29 @@ class WOStackController(CementBaseController): if (not self.app.pargs.composer): packages = packages + [["https://github.com/phpmyadmin/" "phpmyadmin/archive/STABLE.tar.gz", - "/tmp/pma.tar.gz", "phpMyAdmin"], + "/var/lib/wo/tmp/pma.tar.gz", "phpMyAdmin"], ["https://getcomposer.org/" "installer", - "/tmp/composer-install", + "/var/lib/wo/tmp/composer-install", "Composer"]] else: packages = packages + [["https://github.com/phpmyadmin/" "phpmyadmin/archive/STABLE.tar.gz", - "/tmp/pma.tar.gz", "phpMyAdmin"]] + "/var/lib/wo/tmp/pma.tar.gz", "phpMyAdmin"]] # Composer if self.app.pargs.composer: Log.debug(self, "Setting packages variable for Composer ") packages = packages + [["https://getcomposer.org/installer", - "/tmp/composer-install", "Composer"]] + "/var/lib/wo/tmp/composer-install", "Composer"]] # PHPREDISADMIN if self.app.pargs.phpredisadmin: Log.debug(self, "Setting packages variable for phpRedisAdmin") packages = packages + [["https://github.com/ErikDubbelboer/" "phpRedisAdmin/archive/master.tar.gz", - "/tmp/pra.tar.gz", "phpRedisAdmin"], + "/var/lib/wo/tmp/pra.tar.gz", "phpRedisAdmin"], ["https://github.com/nrk/predis/" "archive/v1.1.1.tar.gz", - "/tmp/predis.tar.gz", "Predis"]] + "/var/lib/wo/tmp/predis.tar.gz", "Predis"]] # ADMINER if self.app.pargs.adminer: Log.debug(self, "Setting packages variable for Adminer ") @@ -1562,7 +1562,7 @@ class WOStackController(CementBaseController): if not os.path.exists('/opt/netdata'): packages = packages + [['https://my-netdata.io/' 'kickstart-static64.sh', - '/tmp/kickstart.sh', + '/var/lib/wo/tmp/kickstart.sh', 'Netdata']] # WordOps Dashboard @@ -1572,11 +1572,11 @@ class WOStackController(CementBaseController): [["https://github.com/WordOps/" "wordops-dashboard/releases/" "download/v1.0/wo-dashboard.tar.gz", - "/tmp/wo-dashboard.tar.gz", + "/var/lib/wo/tmp/wo-dashboard.tar.gz", "WordOps Dashboard"], ["https://github.com/soerennb/" "extplorer/archive/v2.1.11.tar.gz", - "/tmp/extplorer.tar.gz", + "/var/lib/wo/tmp/extplorer.tar.gz", "eXtplorer"]] # UTILS @@ -1585,7 +1585,7 @@ class WOStackController(CementBaseController): packages = packages + [["https://github.com/elijaa/" "phpmemcachedadmin/archive/" "1.3.0.tar.gz", - '/tmp/memcached.tar.gz', + '/var/lib/wo/tmp/memcached.tar.gz', 'phpMemcachedAdmin'], ["https://raw.githubusercontent.com" "/rtCamp/eeadmin/master/cache/nginx/" @@ -1615,7 +1615,7 @@ class WOStackController(CementBaseController): "OCP.php"], ["https://github.com/jokkedk/webgrind/" "archive/master.tar.gz", - '/tmp/webgrind.tar.gz', 'Webgrind'], + '/var/lib/wo/tmp/webgrind.tar.gz', 'Webgrind'], ["http://bazaar.launchpad.net/~" "percona-toolkit-dev/percona-toolkit/" "2.1/download/head:/ptquerydigest-" @@ -1625,7 +1625,7 @@ class WOStackController(CementBaseController): "pt-query-advisor"], ["https://github.com/box/Anemometer/" "archive/master.tar.gz", - '/tmp/anemometer.tar.gz', 'Anemometer'] + '/var/lib/wo/tmp/anemometer.tar.gz', 'Anemometer'] ] except Exception as e: pass From 6765c16e953c6e3153f794539db286167c5ba170 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 13:21:25 +0200 Subject: [PATCH 32/45] fix wo log dir --- install | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/install b/install index 0b552c3..839564b 100755 --- a/install +++ b/install @@ -151,15 +151,15 @@ fi ### # 1 - To prevent errors or unexpected behaviour, create the log and ACL it ### -if [ ! -d "$wo_log_dir" ]; then +if [ ! -d "$wo_log_dir" ] || [ ! -d "$wo_backup_dir" ] || [ ! -d "$wo_tmp_dir" ]; then wo_lib_echo "Creating WordOps backup, tmp & log directory, just a second..." - mkdir -p "$wo_backup_dir" || wo_lib_error "Whoops - seems we are unable to create the log directory $wo_log_dir, exit status " $? + mkdir -p "$wo_backup_dir" "$wo_log_dir" "$wo_tmp_dir" || wo_lib_error "Whoops - seems we are unable to create the log directory $wo_log_dir, exit status " $? # create wordops log files touch /var/log/wo/{wordops.log,install.log} - chmod -R 600 "$wo_log_dir" "$wo_backup_dir" "$wo_tmp_dir" || wo_lib_error "Whoops, there was an error setting the permissions on the WordOps log folder, exit status " $? + chmod -R 700 "$wo_log_dir" "$wo_backup_dir" "$wo_tmp_dir" || wo_lib_error "Whoops, there was an error setting the permissions on the WordOps log folder, exit status " $? fi ### @@ -670,7 +670,7 @@ if [ -x /usr/local/bin/wo ]; then wo_upgrade_nginx | tee -ai $wo_install_log fi wo_update_latest | tee -ai $wo_install_log - wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log + wo_lib_echo "Updating acme.sh" | tee -ai $wo_install_log wo_install_acme_sh | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log From 81e6eadb438374922ab0398110686049f83643ac Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 13:46:39 +0200 Subject: [PATCH 33/45] add vhostonly option --- wo/cli/plugins/site.py | 16 +++++++++++----- wo/cli/plugins/site_functions.py | 8 +++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index a21c198..e6e90b0 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -404,12 +404,14 @@ class WOSiteCreateController(CementBaseController): "{0} already exists".format(wo_domain)) if stype == 'proxy': - data['site_name'] = wo_domain - data['www_domain'] = wo_www_domain + data = dict(site_name=wo_domain, www_domain=wo_www_domain, + static=True, basic=False, php73=False, wp=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=wo_site_webroot) data['proxy'] = True data['host'] = host data['port'] = port - wo_site_webroot = WOVariables.wo_webroot + wo_domain + data['basic'] = True if self.app.pargs.php73: data = dict(site_name=wo_domain, www_domain=wo_www_domain, @@ -418,6 +420,9 @@ class WOSiteCreateController(CementBaseController): wpsubdir=False, webroot=wo_site_webroot) data['basic'] = True + if self.app.pargs.vhostonly: + data['vhostonly'] = True + if stype in ['html', 'php']: data = dict(site_name=wo_domain, www_domain=wo_www_domain, static=True, basic=False, php73=False, wp=False, @@ -583,11 +588,12 @@ class WOSiteCreateController(CementBaseController): "and please try again") # Setup WordPress if Wordpress site - if data['wp']: + if (data['wp'] and (not data['vhostonly'])): try: wo_wp_creds = setupwordpress(self, data) # Add database information for site into database - updateSiteInfo(self, wo_domain, db_name=data['wo_db_name'], + updateSiteInfo(self, wo_domain, + db_name=data['wo_db_name'], db_user=data['wo_db_user'], db_password=data['wo_db_pass'], db_host=data['wo_db_host']) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index e23ee87..716dd0e 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -49,8 +49,7 @@ def pre_run_checks(self): def check_domain_exists(self, domain): if getSiteInfo(self, domain): return True - else: - return False + return False def setupdomain(self, data): @@ -1202,9 +1201,8 @@ def deleteWebRoot(self, webroot): Log.debug(self, "Removing {0}".format(webroot)) WOFileUtils.rm(self, webroot) return True - else: - Log.debug(self, "{0} does not exist".format(webroot)) - return False + Log.debug(self, "{0} does not exist".format(webroot)) + return False def removeNginxConf(self, domain): From 2bffb50b8db51583306060f118c90ccd7955fbd6 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 1 May 2019 16:26:27 +0200 Subject: [PATCH 34/45] add php-fpm emergency restart --- wo/cli/plugins/site_functions.py | 8 +++++--- wo/cli/templates/php-fpm.mustache | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 716dd0e..39cb072 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -59,7 +59,7 @@ def setupdomain(self, data): # print (key, value) wo_domain_name = data['site_name'] - wo_site_webroot = data['webroot'] if 'webroot' in data.keys() else '' + wo_site_webroot = data['webroot'] # Check if nginx configuration already exists # if os.path.isfile('/etc/nginx/sites-available/{0}' @@ -312,10 +312,12 @@ def setupwordpress(self, data): "--dbname=\'{0}\' --dbprefix=\'{1}\' " "--dbuser=\'{2}\' --dbhost=\'{3}\' " .format(data['wo_db_name'], wo_wp_prefix, - data['wo_db_user'], data['wo_db_host'] + data['wo_db_user'], + data['wo_db_host'] ) + "--dbpass=\'{0}\' " - "--extra-php< Date: Wed, 1 May 2019 16:39:22 +0200 Subject: [PATCH 35/45] use read -r instead of read -p --- install | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/install b/install index 839564b..99e976e 100755 --- a/install +++ b/install @@ -651,8 +651,8 @@ if [ -x /usr/local/bin/wo ]; then if ! { wo -v 2>&1 | grep $wo_version_new }; then - read -p "Update WordOps to $wo_version_new (y/n): " wo_ans - if [ "$wo_ans" = "y" ] || [ "$wo_ans" = "Y" ]; then + echo -e "Update WordOps to $wo_version_new (y/n): " && read -r WO_ANSWER + if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log wo_install_dep | tee -ai $wo_install_log wo_lib_echo "Backing-up WO install" | tee -ai $wo_install_log @@ -684,8 +684,8 @@ if [ -x /usr/local/bin/wo ]; then else # 2 - Migration from EEv3 if [ -x /usr/local/bin/ee ]; then - read -p "Migrate from EasyEngine to WordOps (y/n): " wo_ans - if [ "$wo_ans" = "y" ] || [ "$wo_ans" = "Y" ]; then + echo -e "Migrate from EasyEngine to WordOps (y/n): " && read -r WO_ANSWER + if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log wo_install_dep | tee -ai $wo_install_log wo_lib_echo "Backing-up EE install" | tee -ai $wo_install_log From c2da42df3bcbfc885f257128e60769254f54900b Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 10:07:37 +0200 Subject: [PATCH 36/45] testing open_basedir --- CHANGELOG.md | 6 ++++-- install | 10 +--------- wo/cli/plugins/stack.py | 19 ++++++++++++++++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 932df22..51c1dde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,9 +37,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Extplorer filemanager - Enable OSCP Stapling with Let's Encrypt - Compress database backup with pigz before updating sites -- Add support for Ubuntu 19.04 disco -- Add support for Raspbian +- Support for Ubuntu 19.04 (disco) - few php extensions missing +- Support for Raspbian 9 (stretch) - tested on Raspberry Pi 3b+ - backup letsencrypt certificate before upgrade +- directives emergency_restart_threshold & emergency_restart_interval to restart php-fpm in case of failure #### Changed @@ -73,6 +74,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - --hsts flag with basic html site - hsts flag on site not secure with letsencrypt - fix import of previous acme.sh certificate +- fix proxy webroot folder creation ### v3.9.4 - 2019-03-15 diff --git a/install b/install index 99e976e..7d875b8 100755 --- a/install +++ b/install @@ -357,15 +357,7 @@ wo_install_acme_sh() { fi cd /opt/acme.sh || exit 1 # create conf directories - [ ! -d /etc/letsencrypt/config ] && { - mkdir -p /etc/letsencrypt/config - } - [ ! -d /etc/letsencrypt/live ] && { - mkdir -p /etc/letsencrypt/live - } - [ ! -d /etc/letsencrypt/renewal ] && { - mkdir -p /etc/letsencrypt/renewal - } + mkdir -p /etc/letsencrypt/{config,live,renewal} # install acme.sh ./acme.sh --install \ --home /etc/letsencrypt \ diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 8d5bac5..7f7901b 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -787,6 +787,11 @@ class WOStackController(CementBaseController): "/etc/php/7.2/fpm/pool.d/www.conf") config.write(configfile) + with open("/etc/php/7.2/fpm/pool.d/www.conf", + encoding='utf-8', mode='a') as myfile: + myfile.write("\nphp_admin_value[open_basedir] " + "= \"/var/www:/tmp/:/var/run/nginx-cache\"\n") + # Generate /etc/php/7.2/fpm/pool.d/www-two.conf WOFileUtils.copyfile(self, "/etc/php/7.2/fpm/pool.d/www.conf", "/etc/php/7.2/fpm/pool.d/www-two.conf") @@ -942,6 +947,11 @@ class WOStackController(CementBaseController): "/etc/php/7.3/fpm/pool.d/www.conf") config.write(configfile) + with open("/etc/php/7.3/fpm/pool.d/www.conf", + encoding='utf-8', mode='a') as myfile: + myfile.write("\nphp_admin_value[open_basedir] " + "= \"/var/www:/tmp/:/var/run/nginx-cache\"\n") + # Generate /etc/php/7.3/fpm/pool.d/www-two.conf WOFileUtils.copyfile(self, "/etc/php/7.3/fpm/pool.d/www.conf", "/etc/php/7.3/fpm/pool.d/www-two.conf") @@ -1081,7 +1091,8 @@ class WOStackController(CementBaseController): if any('/var/lib/wo/tmp/pma.tar.gz' == x[1] for x in packages): - WOExtract.extract(self, '/var/lib/wo/tmp/pma.tar.gz', '/var/lib/wo/tmp/') + WOExtract.extract( + self, '/var/lib/wo/tmp/pma.tar.gz', '/var/lib/wo/tmp/') Log.debug(self, 'Extracting file /var/lib/wo/tmp/pma.tar.gz to ' 'location /var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/db' @@ -1252,7 +1263,8 @@ class WOStackController(CementBaseController): for x in packages): Log.debug(self, "Extracting file webgrind.tar.gz to " "location /var/lib/wo/tmp/ ") - WOExtract.extract(self, '/var/lib/wo/tmp/webgrind.tar.gz', '/var/lib/wo/tmp/') + WOExtract.extract( + self, '/var/lib/wo/tmp/webgrind.tar.gz', '/var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/php' .format(WOVariables.wo_webroot)): Log.debug(self, "Creating directroy " @@ -1294,7 +1306,8 @@ class WOStackController(CementBaseController): for x in packages): Log.debug(self, "Extracting file anemometer.tar.gz to " "location /var/lib/wo/tmp/ ") - WOExtract.extract(self, '/var/lib/wo/tmp/anemometer.tar.gz', '/var/lib/wo/tmp/') + WOExtract.extract( + self, '/var/lib/wo/tmp/anemometer.tar.gz', '/var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/db/' .format(WOVariables.wo_webroot)): Log.debug(self, "Creating directory") From 1edd099e8d836437f9dd4b41d7856f8ed854b789 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 11:18:05 +0200 Subject: [PATCH 37/45] fix vhostonly --- wo/cli/plugins/site.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index e6e90b0..a5c6db6 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -420,9 +420,6 @@ class WOSiteCreateController(CementBaseController): wpsubdir=False, webroot=wo_site_webroot) data['basic'] = True - if self.app.pargs.vhostonly: - data['vhostonly'] = True - if stype in ['html', 'php']: data = dict(site_name=wo_domain, www_domain=wo_www_domain, static=True, basic=False, php73=False, wp=False, From 9bac60304a30e23d740b6de7e2266bec4798385d Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 11:24:37 +0200 Subject: [PATCH 38/45] another fix for vhost only --- wo/cli/plugins/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index a5c6db6..3deb9fe 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -585,7 +585,7 @@ class WOSiteCreateController(CementBaseController): "and please try again") # Setup WordPress if Wordpress site - if (data['wp'] and (not data['vhostonly'])): + if (data['wp'] and (not self.app.pargs.vhostonly)): try: wo_wp_creds = setupwordpress(self, data) # Add database information for site into database From 21efc1262237780e40d5a1905c8da8ded538aa50 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 11:46:27 +0200 Subject: [PATCH 39/45] fix wo_wp_creds --- wo/cli/plugins/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 3deb9fe..c22e156 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -657,7 +657,7 @@ class WOSiteCreateController(CementBaseController): for msg in wo_auth: Log.info(self, Log.ENDC + msg, log=False) - if data['wp']: + if data['wp'] and (not self.app.pargs.vhostonly): Log.info(self, Log.ENDC + "WordPress admin user :" " {0}".format(wo_wp_creds['wp_user']), log=False) Log.info(self, Log.ENDC + "WordPress admin user password : {0}" From 05bd3c85319c66a75d8d9fdcb289ec6c0c437f40 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 12:28:44 +0200 Subject: [PATCH 40/45] add database creation with --vhostonly --- wo/cli/plugins/site.py | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index c22e156..6c27262 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -610,6 +610,60 @@ class WOSiteCreateController(CementBaseController): "`tail /var/log/wo/wordops.log` " "and please try again") + if (data['wp'] and (self.app.pargs.vhostonly)): + try: + data = setupdatabase(self, data) + # Add database information for site into database + updateSiteInfo(self, wo_domain, db_name=data['wo_db_name'], + db_user=data['wo_db_user'], + db_password=data['wo_db_pass'], + db_host=data['wo_db_host']) + except SiteError as e: + # call cleanup actions on failure + Log.debug(self, str(e)) + Log.info(self, Log.FAIL + + "There was a serious error encountered...") + Log.info(self, Log.FAIL + "Cleaning up afterwards...") + doCleanupAction(self, domain=wo_domain, + webroot=data['webroot'], + dbname=data['wo_db_name'], + dbuser=data['wo_db_user'], + dbhost=data['wo_db_host']) + deleteSiteInfo(self, wo_domain) + Log.error(self, "Check the log for details: " + "`tail /var/log/wo/wordops.log` " + "and please try again") + try: + wodbconfig = open("{0}/wo-config.php" + .format(wo_site_webroot), + encoding='utf-8', mode='w') + wodbconfig.write("" + .format(data['wo_db_name'], + data['wo_db_user'], + data['wo_db_pass'], + data['wo_db_host'])) + wodbconfig.close() + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "wo-config.php") + Log.info(self, Log.FAIL + + "There was a serious error encountered...") + Log.info(self, Log.FAIL + "Cleaning up afterwards...") + doCleanupAction(self, domain=wo_domain, + webroot=data['webroot'], + dbname=data['wo_db_name'], + dbuser=data['wo_db_user'], + dbhost=data['wo_db_host']) + deleteSiteInfo(self, wo_domain) + Log.error(self, "Check the log for details: " + "`tail /var/log/wo/wordops.log` " + "and please try again") + # Service Nginx Reload call cleanup if failed to reload nginx if not WOService.reload_service(self, 'nginx'): Log.info(self, Log.FAIL + From 92cf52c69cc3b6b5ef9c32228428dbf37cb511c7 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 13:45:45 +0200 Subject: [PATCH 41/45] fix phpmemcached admin & eXtplorer --- .travis.yml | 3 +-- wo/cli/plugins/stack.py | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index ecad218..7fd6ba8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,8 +51,7 @@ script: - sudo wo site create 1.com --html && sudo wo site create 2.com --php && sudo wo site create 3.com --mysql || sudo tail -n50 /var/log/wo/wordops.log - sudo wo site update 1.com --wp && sudo wo site update 2.com --php73 && sudo wo site update 3.com --php73 && sudo wo site update 1.com --wpfc && sudo wo site update 1.com --wpsc && sudo wo site update 1.com --wpredis || sudo tail -n50 /var/log/wo/wordops.log - - sudo ls /var/www/ - - sudo ls /var/www/22222/htdocs/ - sudo wp --allow-root --info - sudo wo info || sudo tail -n50 /var/log/wo/wordops.log - sudo tree -L 2 /etc/nginx + - sudo tree -L 2 /var/www/22222/htdocs/ diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 7f7901b..16f5656 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1229,7 +1229,7 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot)) WOExtract.extract(self, '/var/lib/wo/tmp/extplorer.tar.gz', '/var/lib/wo/tmp/') - shutil.move('/var/lib/wo/tmp/extplorer-2.1.11/', + shutil.move('/var/lib/wo/tmp/extplorer-2.1.11', '{0}22222/htdocs/files' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " @@ -1248,7 +1248,7 @@ class WOStackController(CementBaseController): " {0}22222/htdocs/cache/memcache " .format(WOVariables.wo_webroot)) WOExtract.extract(self, '/var/lib/wo/tmp/memcached.tar.gz', - '{0}22222/htdocs/cache/memcache/' + '{0}22222/htdocs/cache/memcache' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " "{0}22222/htdocs/cache/memcache file" @@ -1528,7 +1528,8 @@ class WOStackController(CementBaseController): if (not self.app.pargs.composer): packages = packages + [["https://github.com/phpmyadmin/" "phpmyadmin/archive/STABLE.tar.gz", - "/var/lib/wo/tmp/pma.tar.gz", "phpMyAdmin"], + "/var/lib/wo/tmp/pma.tar.gz", + "phpMyAdmin"], ["https://getcomposer.org/" "installer", "/var/lib/wo/tmp/composer-install", @@ -1536,21 +1537,25 @@ class WOStackController(CementBaseController): else: packages = packages + [["https://github.com/phpmyadmin/" "phpmyadmin/archive/STABLE.tar.gz", - "/var/lib/wo/tmp/pma.tar.gz", "phpMyAdmin"]] + "/var/lib/wo/tmp/pma.tar.gz", + "phpMyAdmin"]] # Composer if self.app.pargs.composer: Log.debug(self, "Setting packages variable for Composer ") packages = packages + [["https://getcomposer.org/installer", - "/var/lib/wo/tmp/composer-install", "Composer"]] + "/var/lib/wo/tmp/composer-install", + "Composer"]] # PHPREDISADMIN if self.app.pargs.phpredisadmin: Log.debug(self, "Setting packages variable for phpRedisAdmin") packages = packages + [["https://github.com/ErikDubbelboer/" "phpRedisAdmin/archive/master.tar.gz", - "/var/lib/wo/tmp/pra.tar.gz", "phpRedisAdmin"], + "/var/lib/wo/tmp/pra.tar.gz", + "phpRedisAdmin"], ["https://github.com/nrk/predis/" "archive/v1.1.1.tar.gz", - "/var/lib/wo/tmp/predis.tar.gz", "Predis"]] + "/var/lib/wo/tmp/predis.tar.gz", + "Predis"]] # ADMINER if self.app.pargs.adminer: Log.debug(self, "Setting packages variable for Adminer ") @@ -1628,7 +1633,8 @@ class WOStackController(CementBaseController): "OCP.php"], ["https://github.com/jokkedk/webgrind/" "archive/master.tar.gz", - '/var/lib/wo/tmp/webgrind.tar.gz', 'Webgrind'], + '/var/lib/wo/tmp/webgrind.tar.gz', + 'Webgrind'], ["http://bazaar.launchpad.net/~" "percona-toolkit-dev/percona-toolkit/" "2.1/download/head:/ptquerydigest-" @@ -1638,7 +1644,8 @@ class WOStackController(CementBaseController): "pt-query-advisor"], ["https://github.com/box/Anemometer/" "archive/master.tar.gz", - '/var/lib/wo/tmp/anemometer.tar.gz', 'Anemometer'] + '/var/lib/wo/tmp/anemometer.tar.gz', + 'Anemometer'] ] except Exception as e: pass From 080a874c3266af5783a7125d3eac07e3684763e3 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 14:38:18 +0200 Subject: [PATCH 42/45] add kernel tweaks and ee cron removal --- CHANGELOG.md | 2 ++ install | 44 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51c1dde..d9c0bc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Support for Raspbian 9 (stretch) - tested on Raspberry Pi 3b+ - backup letsencrypt certificate before upgrade - directives emergency_restart_threshold & emergency_restart_interval to restart php-fpm in case of failure +- EasyEngine cronjob removal during install +- Kernel tweaks via systctl.conf #### Changed diff --git a/install b/install index 7d875b8..0d5e9b7 100755 --- a/install +++ b/install @@ -7,7 +7,7 @@ # Copyright (c) 2019 - WordOps # This script is licensed under M.I.T # ------------------------------------------------------------------------- -# Version 3.9.5 - 2019-04-26 +# Version 3.9.5 - 2019-05-02 # ------------------------------------------------------------------------- readonly wo_version_old="2.2.3" readonly wo_version_new="3.9.5" @@ -123,6 +123,7 @@ TIME=$(date +"$TIME_FORMAT") NGINX_BACKUP_FILE="/var/lib/wo-backup/nginx-backup.$TIME.tar.gz" EE_BACKUP_FILE="/var/lib/wo-backup/ee-backup.$TIME.tar.gz" WO_BACKUP_FILE="/var/lib/wo-backup/wo-backup.$TIME.tar.gz" +WO_ARCH="$(uname -m)" if [ -x /usr/local/bin/ee ]; then ee_migration=1 @@ -628,11 +629,34 @@ wo_clean_ee() { rm -f /usr/local/bin/ee /etc/bash_completion.d/ee_auto.rc /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee >> /var/log/wo/install.log 2>&1 } -# wo_tweak_kernel() { -# if [ ! -f /etc/sysctl.d/60-ubuntu-nginx-web-server.conf ]; then +wo_remove_ee_cron() { -# fi -# } + crontab -l | sed '/ee site update --le=renew --all 2> \/dev\/null/d' | crontab - + +} + +wo_tweak_kernel() { + + if [ ! -f /etc/sysctl.d/60-wo-tweaks.conf ]; then + if [ "$WO_ARCH" = "x86_64" ]; then + rm -f /etc/sysctl.d/60-ubuntu-nginx-web-server.conf + wget -qO /etc/sysctl.d/60-wo-tweaks.conf https://raw.githubusercontent.com/WordOps/WordOps/updating-configuration/wo/cli/templates/sysctl.mustache + if [ "$wo_distro_version" = "bionic" ] || [ "$wo_distro_version" = "disco" ]; then + modprobe tcp_bbr && echo 'tcp_bbr' >> /etc/modules-load.d/bbr.conf + echo -e '\nnet.ipv4.tcp_congestion_control = bbr\nnet.ipv4.tcp_notsent_lowat = 16384' >> /etc/sysctl.d/60-wo-tweaks.conf + else + modprobe tcp_htcp && echo 'tcp_htcp' >> /etc/modules-load.d/htcp.conf + echo 'net.ipv4.tcp_congestion_control = htcp' >> /etc/sysctl.d/60-wo-tweaks.conf + fi + + fi + LIMIT_CHECK=$(grep "500000" /etc/security/limits.conf) + if [ -z "$LIMIT_CHECK" ]; then + echo -e "* hard nofile 500000\n* soft nofile 500000\nroot hard nofile 500000\nroot soft nofile 500000\n" >> /etc/security/limits.conf + fi + fi + +} ### # 4 - WO MAIN SETUP @@ -643,7 +667,7 @@ if [ -x /usr/local/bin/wo ]; then if ! { wo -v 2>&1 | grep $wo_version_new }; then - echo -e "Update WordOps to $wo_version_new (y/n): " && read -r WO_ANSWER + echo -e "Update WordOps to $wo_version_new (y/n): " && read -r WO_ANSWER if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log wo_install_dep | tee -ai $wo_install_log @@ -664,6 +688,8 @@ if [ -x /usr/local/bin/wo ]; then wo_update_latest | tee -ai $wo_install_log wo_lib_echo "Updating acme.sh" | tee -ai $wo_install_log wo_install_acme_sh | tee -ai $wo_install_log + wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log + wo_tweak_kernel | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log @@ -682,6 +708,8 @@ else wo_install_dep | tee -ai $wo_install_log wo_lib_echo "Backing-up EE install" | tee -ai $wo_install_log wo_backup_ee | tee -ai $wo_install_log + wo_lib_echo "Removing EasyEngine cronjob" | tee -ai $wo_install_log + wo_remove_ee_cron | tee -ai $wo_install_log wo_lib_echo "Syncing WO database" | tee -ai $wo_install_log wo_sync_db | tee -ai $wo_install_log secure_wo_db | tee -ai $wo_install_log @@ -698,6 +726,8 @@ else wo_update_latest | tee -ai $wo_install_log wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log wo_install_acme_sh | tee -ai $wo_install_log + wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log + wo_tweak_kernel | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log @@ -712,6 +742,8 @@ else wo_install_dep | tee -ai $wo_install_log wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log wo_install | tee -ai $wo_install_log + wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log + wo_tweak_kernel | tee -ai $wo_install_log wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log wo_install_acme_sh | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log From 462dc715656bea4c932aa07a7649c69655d3bb7b Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 14:52:05 +0200 Subject: [PATCH 43/45] update travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7fd6ba8..2ee76d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,4 +54,4 @@ script: - sudo wp --allow-root --info - sudo wo info || sudo tail -n50 /var/log/wo/wordops.log - sudo tree -L 2 /etc/nginx - - sudo tree -L 2 /var/www/22222/htdocs/ + - sudo tree -L 3 /var/www/22222/htdocs/ From a1f5041968ea36e3f5d1efbd90f7455b2ea49bb8 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 15:12:26 +0200 Subject: [PATCH 44/45] fix access to /usr/share/php --- wo/cli/plugins/stack.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 16f5656..14cb867 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -790,7 +790,8 @@ class WOStackController(CementBaseController): with open("/etc/php/7.2/fpm/pool.d/www.conf", encoding='utf-8', mode='a') as myfile: myfile.write("\nphp_admin_value[open_basedir] " - "= \"/var/www:/tmp/:/var/run/nginx-cache\"\n") + "= \"/var/www/:/usr/share/php/:" + "/tmp/:/var/run/nginx-cache/\"\n") # Generate /etc/php/7.2/fpm/pool.d/www-two.conf WOFileUtils.copyfile(self, "/etc/php/7.2/fpm/pool.d/www.conf", @@ -950,7 +951,8 @@ class WOStackController(CementBaseController): with open("/etc/php/7.3/fpm/pool.d/www.conf", encoding='utf-8', mode='a') as myfile: myfile.write("\nphp_admin_value[open_basedir] " - "= \"/var/www:/tmp/:/var/run/nginx-cache\"\n") + "= \"/var/www/:/usr/share/php/:" + "/tmp/:/var/run/nginx-cache/\"\n") # Generate /etc/php/7.3/fpm/pool.d/www-two.conf WOFileUtils.copyfile(self, "/etc/php/7.3/fpm/pool.d/www.conf", From 147369bc7533da4e597c131a865358b208a3e0b0 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Thu, 2 May 2019 18:41:07 +0200 Subject: [PATCH 45/45] prepare for release --- CHANGELOG.md | 16 ++++++++++------ README.md | 3 +-- wo/cli/templates/fastcgi.mustache | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c0bc5..ab727f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), --- -### v3.9.5 - [Unreleased] +### v3.9.6 - [Unreleased] + +### v3.9.5 - 2019-05-02 #### Added @@ -28,21 +30,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Support for Netdata on backend : https://server.hostname:22222/netdata/ - New Stacks : composer and netdata - additional argument for letsencrypt : --hsts -- Theme for adminer +- Clean Theme for adminer - Credits for tools shipped with WordOps - Cache exception for Easy Digital Download -- Additional cache exception for Woocommerce +- Additional cache exceptions for Woocommerce - MySQL monitoring with Netdata -- WordOps-dashboard on 22222 -- Extplorer filemanager +- WordOps-dashboard on 22222, can be installed with `wo stack install` +- Extplorer filemanager in WordOps backend - Enable OSCP Stapling with Let's Encrypt -- Compress database backup with pigz before updating sites +- Compress database backup with pigz (faster than gzip) before updating sites - Support for Ubuntu 19.04 (disco) - few php extensions missing - Support for Raspbian 9 (stretch) - tested on Raspberry Pi 3b+ - backup letsencrypt certificate before upgrade - directives emergency_restart_threshold & emergency_restart_interval to restart php-fpm in case of failure - EasyEngine cronjob removal during install - Kernel tweaks via systctl.conf +- open_basedir on php-fpm process to forbid access with php outside of /var/www & /run/nginx-cache #### Changed @@ -56,6 +59,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - backend SSL configuration now stored in /var/www/22222/conf/nginx/ssl.conf - Install Netdata with static pre-built binaries instead of having to compile it from source - Nginx updated to new stable release (1.16.0) +- New packages (phpmyadmin, adminer, composer) are not download in /tmp anymore #### Fixed diff --git a/README.md b/README.md index 5a17cb2..12dd5c6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ build MIT Commits -GitHub release +GitHub release
Badge Twitter Badge Slack @@ -33,7 +33,6 @@ WordOps.netDocumentationCommunity forum -

--- diff --git a/wo/cli/templates/fastcgi.mustache b/wo/cli/templates/fastcgi.mustache index 72cd66b..271e751 100644 --- a/wo/cli/templates/fastcgi.mustache +++ b/wo/cli/templates/fastcgi.mustache @@ -1,4 +1,4 @@ -# FastCGI cache settings - WO v3.9.5 +# FastCGI cache settings fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:50m inactive=60m max_size=256M; fastcgi_cache_key "$scheme$request_method$host$request_uri"; fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503;