v3.11.0 (#211)
- PHP 7.4 support - Improved Webp images support with Cloudflare (Issue [#95](https://github.com/WordOps/WordOps/issues/95)). Nginx will not serve webp images alternative with Cloudflare IP ranges. - Stack upgrade for adminer - Check acme.sh installation and setup acme.sh if needed before issuing certificate - Add `--ufw` to `wo stack status` - Add Nginx directive `gzip_static on;` to serve precompressed assets with Cache-Enabler or WP-Rocket. (Issue [#207](https://github.com/WordOps/WordOps/issues/207)) - Previous `--php73` & `--php73=off` flags are replaced by `--php72`, `--php73`, `--php74` to switch site's php version - phpMyAdmin updated to v4.9.2 - Adminer updated to v4.7.5 - Replace dot and dashes by underscores in database names (Issue [#206](https://github.com/WordOps/WordOps/issues/206)) - Increased database name length to 32 characters from domain name + 8 random characters - typo error in motd-news script (Issue [#204](https://github.com/WordOps/WordOps/issues/204)) - Install Nginx before ngxblocker - WordOps install/update script text color - Issue with MySQL stack on Raspbian 9/10 - Typo error (PR [#205](https://github.com/WordOps/WordOps/pull/205)) - php version in `wo debug` (PR [#209](https://github.com/WordOps/WordOps/pull/209)) - SSL certificates expiration display with shared wildcard certificates
This commit is contained in:
@@ -16,8 +16,41 @@ class WOAcme:
|
||||
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
|
||||
"'/etc/letsencrypt/config'")
|
||||
|
||||
def check_acme(self):
|
||||
"""
|
||||
Check if acme.sh is properly installed,
|
||||
and install it if required
|
||||
"""
|
||||
if not os.path.exists('/etc/letsencrypt/acme.sh'):
|
||||
if os.path.exists('/opt/acme.sh'):
|
||||
WOFileUtils.rm(self, '/opt/acme.sh')
|
||||
WOGit.clone(
|
||||
self, 'https://github.com/Neilpang/acme.sh.git',
|
||||
'/opt/acme.sh', branch='master')
|
||||
WOFileUtils.mkdir(self, '/etc/letsencrypt/config')
|
||||
WOFileUtils.mkdir(self, '/etc/letsencrypt/renewal')
|
||||
WOFileUtils.mkdir(self, '/etc/letsencrypt/live')
|
||||
try:
|
||||
WOFileUtils.chdir(self, '/opt/acme.sh')
|
||||
WOShellExec.cmd_exec(
|
||||
self, './acme.sh --install --home /etc/letsencrypt'
|
||||
'--config-home /etc/letsencrypt/config'
|
||||
'--cert-home /etc/letsencrypt/renewal'
|
||||
)
|
||||
WOShellExec.cmd_exec(
|
||||
self, "{0} --upgrade --auto-upgrade"
|
||||
.format(WOAcme.wo_acme_exec)
|
||||
)
|
||||
except CommandExecutionError as e:
|
||||
Log.debug(self, str(e))
|
||||
Log.error(self, "acme.sh installation failed")
|
||||
if not os.path.exists('/etc/letsencrypt/acme.sh'):
|
||||
Log.error(self, 'acme.sh ')
|
||||
|
||||
def export_cert(self):
|
||||
"""Export acme.sh csv certificate list"""
|
||||
# check acme.sh is installed
|
||||
WOAcme.check_acme(self)
|
||||
if not WOShellExec.cmd_exec(
|
||||
self, "{0} ".format(WOAcme.wo_acme_exec) +
|
||||
"--list --listraw > /var/lib/wo/cert.csv"):
|
||||
@@ -26,6 +59,9 @@ class WOAcme:
|
||||
|
||||
def setupletsencrypt(self, acme_domains, acmedata):
|
||||
"""Issue SSL certificates with acme.sh"""
|
||||
# check acme.sh is installed
|
||||
WOAcme.check_acme(self)
|
||||
# define variables
|
||||
all_domains = '\' -d \''.join(acme_domains)
|
||||
wo_acme_dns = acmedata['acme_dns']
|
||||
keylenght = acmedata['keylength']
|
||||
@@ -74,6 +110,8 @@ class WOAcme:
|
||||
|
||||
def deploycert(self, wo_domain_name):
|
||||
"""Deploy Let's Encrypt certificates with acme.sh"""
|
||||
# check acme.sh is installed
|
||||
WOAcme.check_acme(self)
|
||||
if not os.path.isfile('/etc/letsencrypt/renewal/{0}_ecc/fullchain.cer'
|
||||
.format(wo_domain_name)):
|
||||
Log.error(self, 'Certificate not found. Deployment canceled')
|
||||
@@ -135,6 +173,8 @@ class WOAcme:
|
||||
|
||||
def renew(self, domain):
|
||||
"""Renew letsencrypt certificate with acme.sh"""
|
||||
# check acme.sh is installed
|
||||
WOAcme.check_acme(self)
|
||||
try:
|
||||
WOShellExec.cmd_exec(
|
||||
self, "{0} ".format(WOAcme.wo_acme_exec) +
|
||||
@@ -158,7 +198,10 @@ class WOAcme:
|
||||
response = requests.get(url, headers=headers).json()
|
||||
domain_ip = response["Answer"][0]['data']
|
||||
except requests.RequestException:
|
||||
Log.error(self, 'Resolving domain IP failed')
|
||||
Log.error(
|
||||
self, 'Resolving domain IP failed.\n'
|
||||
'The domain {0} do not exist or a DNS record is missing'
|
||||
.format(domain))
|
||||
if(not domain_ip == server_ip):
|
||||
Log.warn(
|
||||
self, "{0}".format(domain) +
|
||||
@@ -202,6 +245,8 @@ class WOAcme:
|
||||
.format(WOVar.wo_ssl_live, domain),
|
||||
'/etc/letsencrypt/shared/{0}.conf'.format(domain)]
|
||||
wo_domain = domain
|
||||
# check acme.sh is installed
|
||||
WOAcme.check_acme(self)
|
||||
if WOAcme.cert_check(self, wo_domain):
|
||||
Log.info(self, "Removing Acme configuration")
|
||||
Log.debug(self, "Removing Acme configuration")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""WordOps package installation using apt-get module."""
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
from sh import ErrorReturnCode, apt_get
|
||||
|
||||
@@ -222,6 +223,29 @@ class WOAptGet():
|
||||
# apt_cache.close()
|
||||
return False
|
||||
|
||||
def is_exec(self, package_name):
|
||||
"""
|
||||
Check if package is available by looking
|
||||
for an executable or a systemd service related
|
||||
to this package
|
||||
"""
|
||||
exec_path = ["/bin", "/usr/bin", "/usr/local/bin",
|
||||
"/usr/sbin", "/usr/local/sbin"]
|
||||
for path in exec_path:
|
||||
if os.path.exists('{0}/{1}'.format(path, package_name)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_selected(self, package_name, packages_list):
|
||||
"""
|
||||
Check if package is selected for install/removal/purge
|
||||
in packages_list
|
||||
"""
|
||||
for package in packages_list:
|
||||
if package_name == package[2]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def download_only(self, package_name, repo_url=None, repo_key=None):
|
||||
"""
|
||||
Similar to `apt-get install --download-only PACKAGE_NAME`
|
||||
|
||||
@@ -252,10 +252,7 @@ class WOFileUtils():
|
||||
Check if file exist on given path
|
||||
"""
|
||||
try:
|
||||
if os.path.exists(path):
|
||||
return (True)
|
||||
else:
|
||||
return (False)
|
||||
return bool(os.path.exists(path))
|
||||
except OSError as e:
|
||||
Log.debug(self, "{0}".format(e.strerror))
|
||||
Log.error(self, "Unable to check path {0}".format(path))
|
||||
@@ -369,3 +366,22 @@ class WOFileUtils():
|
||||
except IOError as e:
|
||||
Log.debug(self, "{0}".format(e))
|
||||
Log.error(self, "Unable to append content in {0}".format(path))
|
||||
|
||||
def enabledisable(self, path, enable=True):
|
||||
"""Switch conf from .conf.disabled to .conf or vice-versa"""
|
||||
if enable:
|
||||
Log.debug(self, "Check if disabled file exist")
|
||||
if os.path.exists('{0}.disabled'.format(path)):
|
||||
Log.debug(self, "Moving .disabled file")
|
||||
shutil.move('{0}.disabled'.format(path), path)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
Log.debug(self, "Check if .conf file exist")
|
||||
if os.path.exists(path):
|
||||
Log.debug(self, "Moving .conf file")
|
||||
shutil.move(path, '{0}.disabled'.format(path))
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -18,25 +18,24 @@ class WOGit:
|
||||
"""
|
||||
for path in paths:
|
||||
global git
|
||||
git = git.bake("--git-dir={0}/.git".format(path),
|
||||
"--work-tree={0}".format(path))
|
||||
wogit = git.bake("-C", "{0}".format(path))
|
||||
if os.path.isdir(path):
|
||||
if not os.path.isdir(path + "/.git"):
|
||||
try:
|
||||
Log.debug(self, "WOGit: git init at {0}"
|
||||
.format(path))
|
||||
git.init(path)
|
||||
wogit.init(path)
|
||||
except ErrorReturnCode as e:
|
||||
Log.debug(self, "{0}".format(e))
|
||||
Log.error(self, "Unable to git init at {0}"
|
||||
.format(path))
|
||||
status = git.status("-s")
|
||||
status = wogit.status("-s")
|
||||
if len(status.splitlines()) > 0:
|
||||
try:
|
||||
Log.debug(self, "WOGit: git commit at {0}"
|
||||
.format(path))
|
||||
git.add("--all")
|
||||
git.commit("-am {0}".format(msg))
|
||||
wogit.add("--all")
|
||||
wogit.commit("-am {0}".format(msg))
|
||||
except ErrorReturnCode as e:
|
||||
Log.debug(self, "{0}".format(e))
|
||||
Log.error(self, "Unable to git commit at {0} "
|
||||
@@ -49,9 +48,8 @@ class WOGit:
|
||||
Checks status of file, If its tracked or untracked.
|
||||
"""
|
||||
global git
|
||||
git = git.bake("--git-dir={0}/.git".format(repo),
|
||||
"--work-tree={0}".format(repo))
|
||||
status = git.status("-s", "{0}".format(filepath))
|
||||
wogit = git.bake("-C", "{0}".format(repo))
|
||||
status = wogit.status("-s", "{0}".format(filepath))
|
||||
if len(status.splitlines()) > 0:
|
||||
return True
|
||||
else:
|
||||
@@ -64,8 +62,7 @@ class WOGit:
|
||||
"""
|
||||
for path in paths:
|
||||
global git
|
||||
git = git.bake("--git-dir={0}/.git".format(path),
|
||||
"--work-tree={0}".format(path))
|
||||
wogit = git.bake("-C", "{0}".format(path))
|
||||
if os.path.isdir(path):
|
||||
if not os.path.isdir(path + "/.git"):
|
||||
Log.error(
|
||||
@@ -75,8 +72,8 @@ class WOGit:
|
||||
Log.debug(
|
||||
self, "WOGit: git stash --include-untracked at {0}"
|
||||
.format(path))
|
||||
git.stash("push", "--include-untracked", "-m {0}"
|
||||
.format(msg))
|
||||
wogit.stash("push", "--include-untracked", "-m {0}"
|
||||
.format(msg))
|
||||
except ErrorReturnCode as e:
|
||||
Log.debug(self, "{0}".format(e))
|
||||
Log.error(self, "Unable to git reset at {0} "
|
||||
|
||||
19
wo/core/nginx.py
Normal file
19
wo/core/nginx.py
Normal file
@@ -0,0 +1,19 @@
|
||||
"""WordOps Nginx Manager"""
|
||||
import subprocess
|
||||
|
||||
from wo.core.logging import Log
|
||||
|
||||
|
||||
def check_config(self):
|
||||
"""Check Nginx configuration and return boolean"""
|
||||
Log.debug(self, "Testing Nginx configuration ")
|
||||
# Check Nginx configuration before executing command
|
||||
sub = subprocess.Popen('nginx -t', stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, shell=True)
|
||||
output, error_output = sub.communicate()
|
||||
if 'emerg' in str(error_output):
|
||||
Log.debug(self, "Nginx configuration check failed")
|
||||
return False
|
||||
else:
|
||||
Log.debug(self, "Nginx configuration check was successful")
|
||||
return True
|
||||
@@ -20,15 +20,17 @@ class WOService():
|
||||
# Check Nginx configuration before executing command
|
||||
sub = subprocess.Popen('nginx -t', stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, shell=True)
|
||||
output, error_output = sub.communicate()
|
||||
if 'emerg' not in str(error_output):
|
||||
output = sub.communicate()
|
||||
if 'emerg' not in str(output):
|
||||
Log.valide(self, "Testing Nginx configuration ")
|
||||
Log.wait(self, "Starting Nginx ")
|
||||
Log.wait(self, "Starting Nginx")
|
||||
service_cmd = ('service {0} start'.format(service_name))
|
||||
retcode = subprocess.getstatusoutput(service_cmd)
|
||||
if retcode[0] == 0:
|
||||
Log.valide(self, "Starting Nginx ")
|
||||
return True
|
||||
else:
|
||||
Log.failed(self, "Starting Nginx")
|
||||
else:
|
||||
Log.failed(self, "Testing Nginx configuration ")
|
||||
return False
|
||||
@@ -129,15 +131,15 @@ class WOService():
|
||||
output, error_output = sub.communicate()
|
||||
if 'emerg' not in str(error_output):
|
||||
Log.valide(self, "Testing Nginx configuration ")
|
||||
Log.wait(self, "Reloading Nginx ")
|
||||
Log.wait(self, "Reloading Nginx")
|
||||
service_cmd = ('service {0} reload'.format(service_name))
|
||||
retcode = subprocess.getstatusoutput(service_cmd)
|
||||
if retcode[0] == 0:
|
||||
Log.valide(self, "Reloading Nginx ")
|
||||
Log.valide(self, "Reloading Nginx")
|
||||
return True
|
||||
else:
|
||||
Log.failed(self, "Testing Nginx configuration ")
|
||||
return False
|
||||
else:
|
||||
Log.failed(self, "Testing Nginx configuration ")
|
||||
return False
|
||||
else:
|
||||
service_cmd = ('service {0} reload'.format(service_name))
|
||||
Log.wait(self, "Reloading {0:10}".format(
|
||||
@@ -160,10 +162,11 @@ class WOService():
|
||||
def get_service_status(self, service_name):
|
||||
|
||||
try:
|
||||
is_exist = subprocess.getstatusoutput('which {0}'
|
||||
is_exist = subprocess.getstatusoutput('command -v {0}'
|
||||
.format(service_name))
|
||||
if is_exist[0] == 0 or service_name in ['php7.2-fpm',
|
||||
'php7.3-fpm']:
|
||||
'php7.3-fpm',
|
||||
'php7.4-fpm']:
|
||||
retcode = subprocess.getstatusoutput('service {0} status'
|
||||
.format(service_name))
|
||||
if retcode[0] == 0:
|
||||
|
||||
@@ -37,27 +37,6 @@ class WOShellExec():
|
||||
Log.debug(self, str(e))
|
||||
raise CommandExecutionError
|
||||
|
||||
def cmd_exist(self, command):
|
||||
"""Check if a command exist with command -v"""
|
||||
try:
|
||||
Log.debug(self, "Testing command: {0}".format(command))
|
||||
testing_command = ("command -v {0}".format(command))
|
||||
with subprocess.Popen([testing_command], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, shell=True) as proc:
|
||||
(cmd_stdout_bytes, cmd_stderr_bytes) = proc.communicate()
|
||||
(cmd_stdout, cmd_stderr) = (
|
||||
cmd_stdout_bytes.decode('utf-8', "replace"),
|
||||
cmd_stderr_bytes.decode('utf-8', "replace"))
|
||||
Log.debug(self, "Command Output: {0}, \nCommand Error: {1}"
|
||||
.format(cmd_stdout, cmd_stderr))
|
||||
return bool(proc.returncode == 0)
|
||||
except OSError as e:
|
||||
Log.debug(self, str(e))
|
||||
raise CommandExecutionError
|
||||
except Exception as e:
|
||||
Log.debug(self, str(e))
|
||||
raise CommandExecutionError
|
||||
|
||||
def invoke_editor(self, filepath, errormsg=''):
|
||||
"""
|
||||
Open files using sensible editor
|
||||
|
||||
@@ -6,26 +6,39 @@ from wo.core.fileutils import WOFileUtils
|
||||
from wo.core.logging import Log
|
||||
from wo.core.shellexec import WOShellExec
|
||||
from wo.core.variables import WOVar
|
||||
from wo.core.acme import WOAcme
|
||||
|
||||
|
||||
class SSL:
|
||||
|
||||
def getexpirationdays(self, domain, returnonerror=False):
|
||||
# check if exist
|
||||
if not os.path.isfile('/etc/letsencrypt/live/{0}/cert.pem'
|
||||
if not os.path.exists('/etc/letsencrypt/live/{0}/cert.pem'
|
||||
.format(domain)):
|
||||
Log.error(self, 'File Not Found: '
|
||||
'/etc/letsencrypt/live/{0}/cert.pem'
|
||||
.format(domain), False)
|
||||
if returnonerror:
|
||||
return -1
|
||||
Log.error(self, "Check the WordOps log for more details "
|
||||
"`tail /var/log/wo/wordops.log` and please try again...")
|
||||
Log.debug(self, "cert not found for {0}".format(domain))
|
||||
|
||||
split_domain = domain.split('.')
|
||||
root_domain = ('.').join(split_domain[1:])
|
||||
|
||||
Log.debug(self, "trying with {0}".format(root_domain))
|
||||
if os.path.exists('/etc/letsencrypt/live/{0}/cert.pem'
|
||||
.format(root_domain)):
|
||||
domain = root_domain
|
||||
else:
|
||||
Log.error(self, 'File Not Found: '
|
||||
'/etc/letsencrypt/live/{0}/cert.pem'
|
||||
.format(domain), False)
|
||||
Log.error(
|
||||
self, "Check the WordOps log for more details "
|
||||
"`tail /var/log/wo/wordops.log` "
|
||||
"and please try again...")
|
||||
Log.debug(
|
||||
self,
|
||||
"Getting expiration of /etc/letsencrypt/live/{0}/cert.pem"
|
||||
.format(domain))
|
||||
current_date = WOShellExec.cmd_exec_stdout(self, "date -d \"now\" +%s")
|
||||
expiration_date = WOShellExec.cmd_exec_stdout(
|
||||
self, "date -d \""
|
||||
"$(openssl x509 -in /etc/letsencrypt/live/"
|
||||
self, "date -d \"$(openssl x509 -in /etc/letsencrypt/live/"
|
||||
"{0}/cert.pem -text -noout | grep \"Not After\" "
|
||||
"| cut -c 25-)\" +%s"
|
||||
.format(domain))
|
||||
@@ -39,23 +52,27 @@ class SSL:
|
||||
|
||||
def getexpirationdate(self, domain):
|
||||
# check if exist
|
||||
if os.path.islink('/var/www/{0}/conf/nginx/ssl.conf'):
|
||||
split_domain = domain.split('.')
|
||||
domain = ('.').join(split_domain[1:])
|
||||
if not os.path.isfile('/etc/letsencrypt/live/{0}/cert.pem'
|
||||
.format(domain)):
|
||||
Log.error(self, 'File Not Found: /etc/letsencrypt/'
|
||||
'live/{0}/cert.pem'
|
||||
.format(domain), False)
|
||||
Log.error(self, "Check the WordOps log for more details "
|
||||
"`tail /var/log/wo/wordops.log` and please try again...")
|
||||
if os.path.exists('/var/www/{0}/conf/nginx/ssl.conf'):
|
||||
split_domain = domain.split('.')
|
||||
check_domain = ('.').join(split_domain[1:])
|
||||
else:
|
||||
Log.error(
|
||||
self, 'File Not Found: /etc/letsencrypt/'
|
||||
'live/{0}/cert.pem'
|
||||
.format(domain), False)
|
||||
Log.error(
|
||||
self, "Check the WordOps log for more details "
|
||||
"`tail /var/log/wo/wordops.log` and please try again...")
|
||||
else:
|
||||
check_domain = domain
|
||||
|
||||
expiration_date = WOShellExec.cmd_exec_stdout(
|
||||
return WOShellExec.cmd_exec_stdout(
|
||||
self, "date -d \"$(/usr/bin/openssl x509 -in "
|
||||
"/etc/letsencrypt/live/{0}/cert.pem -text -noout | grep "
|
||||
"\"Not After\" | cut -c 25-)\" "
|
||||
.format(domain))
|
||||
return expiration_date
|
||||
.format(check_domain))
|
||||
|
||||
def siteurlhttps(self, domain):
|
||||
wo_site_webroot = ('/var/www/{0}'.format(domain))
|
||||
@@ -93,8 +110,8 @@ class SSL:
|
||||
Log.valide(self, "Updating site url with https")
|
||||
|
||||
# check if a wildcard exist to secure a new subdomain
|
||||
|
||||
def checkwildcardexist(self, wo_domain_name):
|
||||
"""Check if a wildcard certificate exist for a domain"""
|
||||
|
||||
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
|
||||
"'/etc/letsencrypt/config'")
|
||||
@@ -110,31 +127,44 @@ class SSL:
|
||||
reader = csv.reader(certfile, 'acmeconf')
|
||||
wo_wildcard_domain = ("*.{0}".format(wo_domain_name))
|
||||
for row in reader:
|
||||
if wo_wildcard_domain in row[2]:
|
||||
if not row[2] == "":
|
||||
iswildcard = True
|
||||
break
|
||||
else:
|
||||
iswildcard = False
|
||||
if wo_wildcard_domain == row[2]:
|
||||
if not row[3] == "":
|
||||
return True
|
||||
certfile.close()
|
||||
return False
|
||||
|
||||
return iswildcard
|
||||
def setuphsts(self, wo_domain_name, enable=True):
|
||||
"""Enable or disable htsts for a site"""
|
||||
if enable:
|
||||
if WOFileUtils.enabledisable(
|
||||
self, '/var/www/{0}/conf/nginx/hsts.conf'
|
||||
):
|
||||
return 0
|
||||
else:
|
||||
Log.info(
|
||||
self, "Adding /var/www/{0}/conf/nginx/hsts.conf"
|
||||
.format(wo_domain_name))
|
||||
|
||||
def setuphsts(self, wo_domain_name):
|
||||
Log.info(
|
||||
self, "Adding /var/www/{0}/conf/nginx/hsts.conf"
|
||||
.format(wo_domain_name))
|
||||
|
||||
hstsconf = open("/var/www/{0}/conf/nginx/hsts.conf"
|
||||
.format(wo_domain_name),
|
||||
encoding='utf-8', mode='w')
|
||||
hstsconf.write("more_set_headers "
|
||||
"\"Strict-Transport-Security: "
|
||||
"max-age=31536000; "
|
||||
"includeSubDomains; "
|
||||
"preload\";")
|
||||
hstsconf.close()
|
||||
return 0
|
||||
hstsconf = open("/var/www/{0}/conf/nginx/hsts.conf"
|
||||
.format(wo_domain_name),
|
||||
encoding='utf-8', mode='w')
|
||||
hstsconf.write("more_set_headers "
|
||||
"\"Strict-Transport-Security: "
|
||||
"max-age=31536000; "
|
||||
"includeSubDomains; "
|
||||
"preload\";")
|
||||
hstsconf.close()
|
||||
return 0
|
||||
else:
|
||||
if WOFileUtils.enabledisable(
|
||||
self, '/var/www/{0}/conf/nginx/hsts.conf',
|
||||
enable=False
|
||||
):
|
||||
Log.info(self, "HSTS disabled")
|
||||
return 0
|
||||
else:
|
||||
Log.info(self, "HSTS is not enabled")
|
||||
return 0
|
||||
|
||||
def selfsignedcert(self, proftpd=False, backend=False):
|
||||
"""issue a self-signed certificate"""
|
||||
@@ -197,3 +227,100 @@ class SSL:
|
||||
"/etc/proftpd/ssl/proftpd.crt")
|
||||
# remove self-signed tmp directory
|
||||
WOFileUtils.rm(self, selfs_tmp)
|
||||
|
||||
def httpsredirect(self, wo_domain_name, acme_domains, redirect=True):
|
||||
"""Create Nginx redirection from http to https"""
|
||||
wo_acme_domains = ' '.join(acme_domains)
|
||||
if redirect:
|
||||
Log.wait(self, "Adding HTTPS redirection")
|
||||
if WOFileUtils.enabledisable(
|
||||
self, '/etc/nginx/conf.d/force-ssl-{0}.conf'
|
||||
.format(wo_domain_name), enable=True):
|
||||
Log.valide(self, "Adding HTTPS redirection")
|
||||
return 0
|
||||
else:
|
||||
try:
|
||||
sslconf = open(
|
||||
"/etc/nginx/conf.d/force-ssl-{0}.conf"
|
||||
.format(wo_domain_name),
|
||||
encoding='utf-8', mode='w')
|
||||
sslconf.write(
|
||||
"server {\n"
|
||||
"\tlisten 80;\n" +
|
||||
"\tlisten [::]:80;\n" +
|
||||
"\tserver_name {0};\n"
|
||||
.format(wo_acme_domains) +
|
||||
"\treturn 301 https://$host"
|
||||
"$request_uri;\n}")
|
||||
sslconf.close()
|
||||
except IOError as e:
|
||||
Log.debug(self, str(e))
|
||||
Log.debug(
|
||||
self, "Error occured while generating "
|
||||
"/etc/nginx/conf.d/force-ssl-{0}.conf"
|
||||
.format(wo_domain_name))
|
||||
return 1
|
||||
Log.valide(self, "Adding HTTPS redirection")
|
||||
return 0
|
||||
else:
|
||||
if WOFileUtils.enabledisable(
|
||||
self, "/etc/nginx/conf.d/force-ssl-{0}.conf"
|
||||
.format(wo_domain_name), enable=False):
|
||||
Log.info(
|
||||
self, "Disabled HTTPS Force Redirection for site "
|
||||
"{0}".format(wo_domain_name))
|
||||
else:
|
||||
Log.info(
|
||||
self, "HTTPS redirection already disabled for site"
|
||||
"{0}".format(wo_domain_name)
|
||||
)
|
||||
return 0
|
||||
|
||||
def archivedcertificatehandle(self, domain, acme_domains):
|
||||
Log.warn(
|
||||
self, "You already have an existing certificate "
|
||||
"for the domain requested.\n"
|
||||
"(ref: {0}/"
|
||||
"{1}_ecc/{1}.conf)".format(WOVar.wo_ssl_archive, domain) +
|
||||
"\nPlease select an option from below?"
|
||||
"\n\t1: Reinstall existing certificate"
|
||||
"\n\t2: Issue a new certificate to replace "
|
||||
"the current one (limit ~5 per 7 days)"
|
||||
"")
|
||||
check_prompt = input(
|
||||
"\nType the appropriate number [1-2] or any other key to cancel: ")
|
||||
if not os.path.isfile("{0}/{1}/fullchain.pem"
|
||||
.format(WOVar.wo_ssl_live, domain)):
|
||||
Log.debug(
|
||||
self, "{0}/{1}/fullchain.pem file is missing."
|
||||
.format(WOVar.wo_ssl_live, domain))
|
||||
check_prompt = "2"
|
||||
|
||||
if check_prompt == "1":
|
||||
Log.info(self, "Reinstalling SSL cert with acme.sh")
|
||||
ssl = WOAcme.deploycert(self, domain)
|
||||
if ssl:
|
||||
SSL.httpsredirect(self, domain, acme_domains)
|
||||
|
||||
elif (check_prompt == "2"):
|
||||
Log.info(self, "Issuing new SSL cert with acme.sh")
|
||||
ssl = WOShellExec.cmd_exec(
|
||||
self, "/etc/letsencrypt/acme.sh "
|
||||
"--config-home '/etc/letsencrypt/config' "
|
||||
"--renew -d {0} --ecc --force"
|
||||
.format(domain))
|
||||
|
||||
if ssl:
|
||||
WOAcme.deploycert(self, domain)
|
||||
else:
|
||||
Log.error(self, "Operation cancelled by user.")
|
||||
|
||||
if os.path.isfile("{0}/conf/nginx/ssl.conf"
|
||||
.format(domain)):
|
||||
Log.info(self, "Existing ssl.conf . Backing it up ..")
|
||||
WOFileUtils.mvfile(self, "/var/www/{0}/conf/nginx/ssl.conf"
|
||||
.format(domain),
|
||||
'/var/www/{0}/conf/nginx/ssl.conf.bak'
|
||||
.format(domain))
|
||||
|
||||
return ssl
|
||||
|
||||
50
wo/core/stackconf.py
Normal file
50
wo/core/stackconf.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
|
||||
from wo.core.logging import Log
|
||||
from wo.core.template import WOTemplate
|
||||
from wo.core.variables import WOVar
|
||||
|
||||
|
||||
class WOConf():
|
||||
"""wo stack configuration utilities"""
|
||||
def __init__():
|
||||
pass
|
||||
|
||||
def nginxcommon(self):
|
||||
"""nginx common configuration deployment"""
|
||||
wo_php_version = ["php72", "php73", "php74"]
|
||||
ngxcom = '/etc/nginx/common'
|
||||
for wo_php in wo_php_version:
|
||||
if not os.path.exists(ngxcom):
|
||||
os.mkdir(ngxcom)
|
||||
Log.debug(self, 'deploying templates for {0}'.format(wo_php))
|
||||
data = dict(upstream="{0}".format(wo_php),
|
||||
release=WOVar.wo_version)
|
||||
WOTemplate.deploy(self,
|
||||
'{0}/{1}.conf'
|
||||
.format(ngxcom, wo_php),
|
||||
'php.mustache', data)
|
||||
|
||||
WOTemplate.deploy(
|
||||
self, '{0}/redis-{1}.conf'.format(ngxcom, wo_php),
|
||||
'redis.mustache', data)
|
||||
|
||||
WOTemplate.deploy(
|
||||
self, '{0}/wpcommon-{1}.conf'.format(ngxcom, wo_php),
|
||||
'wpcommon.mustache', data)
|
||||
|
||||
WOTemplate.deploy(
|
||||
self, '{0}/wpfc-{1}.conf'.format(ngxcom, wo_php),
|
||||
'wpfc.mustache', data)
|
||||
|
||||
WOTemplate.deploy(
|
||||
self, '{0}/wpsc-{1}.conf'.format(ngxcom, wo_php),
|
||||
'wpsc.mustache', data)
|
||||
|
||||
WOTemplate.deploy(
|
||||
self, '{0}/wprocket-{1}.conf'.format(ngxcom, wo_php),
|
||||
'wprocket.mustache', data)
|
||||
|
||||
WOTemplate.deploy(
|
||||
self, '{0}/wpce-{1}.conf'.format(ngxcom, wo_php),
|
||||
'wpce.mustache', data)
|
||||
@@ -14,11 +14,11 @@ class WOVar():
|
||||
"""Intialization of core variables"""
|
||||
|
||||
# WordOps version
|
||||
wo_version = "3.10.3"
|
||||
wo_version = "3.11.0"
|
||||
# WordOps packages versions
|
||||
wo_wp_cli = "2.3.0"
|
||||
wo_adminer = "4.7.3"
|
||||
wo_phpmyadmin = "4.9.1"
|
||||
wo_wp_cli = "2.4.0"
|
||||
wo_adminer = "4.7.5"
|
||||
wo_phpmyadmin = "4.9.2"
|
||||
wo_extplorer = "2.1.13"
|
||||
wo_dashboard = "1.2"
|
||||
|
||||
@@ -133,16 +133,23 @@ class WOVar():
|
||||
wo_nginx = ["nginx-custom", "nginx-wo"]
|
||||
wo_nginx_key = '188C9FB063F0247A'
|
||||
|
||||
wo_php = ["php7.2-fpm", "php7.2-curl", "php7.2-gd", "php7.2-imap",
|
||||
"php7.2-readline", "php7.2-common", "php7.2-recode",
|
||||
"php7.2-cli", "php7.2-mbstring", "php7.2-intl",
|
||||
"php7.2-bcmath", "php7.2-mysql", "php7.2-opcache",
|
||||
"php7.2-zip", "php7.2-xml", "php7.2-soap"]
|
||||
wo_php73 = ["php7.3-fpm", "php7.3-curl", "php7.3-gd", "php7.3-imap",
|
||||
"php7.3-readline", "php7.3-common", "php7.3-recode",
|
||||
"php7.3-cli", "php7.3-mbstring", "php7.3-intl",
|
||||
"php7.3-bcmath", "php7.3-mysql", "php7.3-opcache",
|
||||
"php7.3-zip", "php7.3-xml", "php7.3-soap"]
|
||||
wo_module = ["fpm", "curl", "gd", "imap",
|
||||
"readline", "common",
|
||||
"cli", "mbstring", "intl",
|
||||
"bcmath", "mysql", "opcache",
|
||||
"zip", "xml", "soap"]
|
||||
wo_php72 = []
|
||||
for module in wo_module:
|
||||
wo_php72 = wo_php72 + ["php7.2-{0}".format(module),
|
||||
"php7.2-recode"]
|
||||
wo_php73 = []
|
||||
for module in wo_module:
|
||||
wo_php73 = wo_php73 + ["php7.3-{0}".format(module),
|
||||
"php7.3-recode"]
|
||||
wo_php74 = []
|
||||
for module in wo_module:
|
||||
wo_php74 = wo_php74 + ["php7.4-{0}".format(module)]
|
||||
|
||||
wo_php_extra = ["php-memcached", "php-imagick",
|
||||
"graphviz", "php-xdebug", "php-msgpack", "php-redis"]
|
||||
|
||||
|
||||
17
wo/core/wpcli.py
Normal file
17
wo/core/wpcli.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""WordPress utilities for WordOps"""
|
||||
from wo.core.logging import Log
|
||||
from wo.core.shellexec import WOShellExec
|
||||
from wo.core.variables import WOVar
|
||||
|
||||
|
||||
class WOWp:
|
||||
"""WordPress utilities for WordOps"""
|
||||
|
||||
def wpcli(self, command):
|
||||
"""WP-CLI wrapper"""
|
||||
try:
|
||||
WOShellExec.cmd_exec(
|
||||
self, '{0} --allow-root '.format(WOVar.wo_wpcli_path) +
|
||||
'{0}'.format(command))
|
||||
except Exception:
|
||||
Log.error(self, "WP-CLI command failed")
|
||||
Reference in New Issue
Block a user