Merge pull request #157 from WordOps/updating-configuration

Updating configuration
This commit is contained in:
VirtuBox
2019-09-24 03:25:48 +02:00
committed by GitHub
38 changed files with 972 additions and 640 deletions

View File

@@ -1,5 +1,5 @@
sudo: required
dist: bionic
dist: xenial
language: bash
@@ -21,10 +21,11 @@ before_install:
before_script:
- sudo rm -rf /etc/mysql
- sudo bash -c 'echo example.com > /etc/hostname'
- sudo apt-get -qq purge mysql* graphviz* redis*
- sudo apt-get -qq autoremove --purge
- unset LANG
- sudo apt-get install --assume-yes --quiet git python3-setuptools python3-dev python3-apt ccze tree
- sudo apt-get -qq purge mysql* graphviz* redis*
- sudo apt-get install -qq git python3-setuptools python3-dev python3-apt ccze tree
- sudo apt-get -qq autoremove --purge
after_script:
- sudo cat /etc/nginx/nginx.conf | ccze -A
@@ -37,11 +38,7 @@ script:
- lsb_release -a
- sudo bash -c 'echo -e "[user]\n\tname = abc\n\temail = root@localhost.com" > /home/travis/.gitconfig'
- sudo echo "Travis Banch = $TRAVIS_BRANCH"
- sed -i 's/# "nose"/"nose"/g' setup.py
- sed -i 's/# "coverage"/"coverage"/g' setup.py
- sed -i 's/# "Sphinx >= 1.0"/"Sphinx >= 1.0"/g' setup.py
- sudo time bash install --travis -b "$TRAVIS_BRANCH"
- sudo time bash tests/travis.sh
- sudo wo update --travis
- sudo wo stack status

View File

@@ -8,6 +8,33 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### v3.9.x - [Unreleased]
### v3.9.9 - 2019-09-24
#### Added
- [STACK] UFW now available as a stack with flag `--ufw`
- [SECURE] `wo stack secure --ssh` to harden ssh security
- [SECURE] `wo stack secure --sshport` to change ssh port
- [SITE] check domain DNS records before issuing a new certificate without DNS API
- [STACK] Acme challenge with DNS Alias mode [acme.sh wiki](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode)
#### Changed
- [APP] WordOps dashboard updated to v1.2, shipped as a html file, it can be used without PHP stack
- [STACK] Refactor Let's Encrypt with acme.sh
- [STACK] Log error improved with acme.sh depending on the acme challenge (DNS API or Webroot)
- [INSTALL] Removed UFW setup from install script
- [APP] phpMyAdmin updated to v4.9.1
- [STACK] Commit possible Nginx configuration changes into Git before and after performing tasks (in `wo secure` for example)
- [CORE] Update deprecated handlers and hooks registration
#### Fixed
- [STACK] `wo stack purge --all` failure if mysql isn't installed
- [INSTALL] Fix EEv3 files cleanup
- [SECURE] Incorrect variable usage in `wo secure --port`
- [INSTALL] Fix backup_ee function in install script
### v3.9.8.12 - 2019-09-20
#### Changed

View File

@@ -47,7 +47,7 @@ _wo_complete()
"secure")
COMPREPLY=( $(compgen \
-W "--auth --port --ip" \
-W "--auth --port --ip --ssh --sshport" \
-- $cur) )
;;
@@ -74,17 +74,17 @@ _wo_complete()
# HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE
"install" | "purge" | "remove" )
COMPREPLY=( $(compgen \
-W "--recommended --web --admin --security --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --redis --phpredisadmin --composer --netdata --fail2ban --dashboard --proftpd --clamav --mysqlclient --mysqltuner --extplorer --all" \
-W "--web --admin --security --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --redis --phpredisadmin --composer --netdata --fail2ban --ufw --dashboard --proftpd --clamav --mysqlclient --mysqltuner --extplorer --all --force" \
-- $cur) )
;;
"upgrade" )
COMPREPLY=( $(compgen \
-W "--web --admin --utils --nginx --php --php73 --mysql --all --netdata --composer --phpmyadmin --dashboard --no-prompt --mysqtuner --wpcli" \
-W "--web --admin --utils --nginx --php --php73 --mysql --all --netdata --composer --phpmyadmin --dashboard --no-prompt --mysqtuner --wpcli --force" \
-- $cur) )
;;
"start" | "stop" | "reload" | "restart" | "status")
COMPREPLY=( $(compgen \
-W "--nginx --php --php73 --mysql --redis --fail2ban --netdata -proftpd" \
-W "--nginx --php --php73 --mysql --redis --fail2ban --ufw --netdata -proftpd" \
-- $cur) )
;;
"list")
@@ -267,11 +267,11 @@ _wo_complete()
-- $cur) )
;;
"--web" | "--admin" | "--nginx" | "--php" | "--php73" | "--mysql" | "--wpcli" | "--phpmyadmin" | "--adminer" | "--utils" | "--fail2ban" | "--redis | --phpredisadmin | --netdata")
"--web" | "--admin" | "--nginx" | "--php" | "--php73" | "--mysql" | "--wpcli" | "--phpmyadmin" | "--adminer" | "--utils" | "--fail2ban" | "--ufw" | "--redis | --phpredisadmin | --netdata")
if [[ "${COMP_WORDS[2]}" == "install" || "${COMP_WORDS[2]}" == "purge" || "${COMP_WORDS[2]}" == "remove" ]]; then
retlist="--web --admin --security --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --redis --fail2ban --phpredisadmin --netdata -f --force"
retlist="--web --admin --security --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --redis --fail2ban --ufw --phpredisadmin --netdata --force"
elif [[ "${COMP_WORDS[2]}" == "start" || "${COMP_WORDS[2]}" == "reload" || "${COMP_WORDS[2]}" == "restart" || "${COMP_WORDS[2]}" == "stop" ]]; then
retlist="--nginx --php --php73 --mysql --redis --netdata"
retlist="--nginx --php --php73 --mysql --redis --netdata --fail2ban --ufw"
elif [[ "${COMP_WORDS[1]}" == "debug" ]]; then
retlist="--start --nginx --php --php73 --fpm --fpm7 --mysql -i --interactive -stop --import-slow-log --import-slow-log-interval= -"
if [[ $prev == '--mysql' ]]; then

View File

@@ -11,9 +11,9 @@ wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php |
.TP
wo site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ]
.TP
wo site create example.com [ --html | --php | --php73 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis | --letsencrypt/-le/--letsencrypt=subdomain/wildcard][--dns/--dns=dns_cf/dns_do]]
wo site create example.com [ --html | --php | --php73 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis | --letsencrypt/-le/--letsencrypt=wildcard][--dns/--dns=dns_cf/dns_do]]
.TP
wo site update example.com [ --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ] [--password] [-le/--letsencrypt/--letsencrypt=on/off/subdomain/renew/wildcard/clean/purge] [--dns/--dns=dns_cf/dns_do]]
wo site update example.com [ --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ] [--password] [-le/--letsencrypt/--letsencrypt=on/off/wildcard/clean/purge] [--dns/--dns=dns_cf/dns_do]]
.TP
wo site delete example.com [--db | --files | --all | --no-prompt | --force/-f ]
.TP

61
install
View File

@@ -623,58 +623,21 @@ wo_update_latest() {
}
# Do git intialisation
wo_git_init() {
# Nginx under git version control
[ -d /etc/nginx ] && {
cd /etc/nginx || exit 1
[ ! -d /etc/nginx/.git ] && {
git init
}
git add -A .
git commit -am "Updated Nginx"
}
# WordOps under git version control
[ -d /etc/wo ] && {
cd /etc/wo || exit 1
[ ! -d /etc/wo/.git ] && {
git init
}
git add -A .
git commit -am "Installed/Updated to WordOps"
}
# PHP under git version control
[ -d /etc/php ] && {
cd /etc/php || exit 1
[ ! -d /etc/php/.git ] && {
git init
}
git add -A .
git commit -am "Updated PHP"
}
}
wo_backup_ee() {
if [ -d /etc/nginx ]; then
local EE_NGINX="/etc/nginx"
else
local EE_NGINX=""
fi
if [ -d /etc/letsencrypt ]; then
local EE_LE="/etc/letsencrypt"
else
local EE_LE=""
fi
/bin/tar -I pigz -cf "$EE_BACKUP_FILE" "$EE_NGINX" /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.*/dist-packages/ee-*.egg /etc/ee /var/lib/ee "$EE_LE"
local BACKUP_EE=""
[ -d /etc/nginx ] && { BACKUP_EE="$BACKUP_EE /etc/nginx"; }
[ -d /etc/letsencrypt ] && { BACKUP_EE="$BACKUP_EE /etc/letsencrypt"; }
/bin/tar -I pigz -cf "$EE_BACKUP_FILE" /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.*/dist-packages/ee-*.egg /etc/ee /var/lib/ee "$BACKUP_EE"
return 0
}
wo_backup_wo() {
/bin/tar -I pigz -cf "$WO_BACKUP_FILE" "$WO_NGINX" /etc/wo /var/lib/wo "$WO_LE"
/bin/tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx /etc/wo /var/lib/wo "$WO_LE"
return 0
}
wo_clean_ee() {
rm -f /usr/local/bin/ee /etc/bash_completion.d/ee_auto.rc /usr/lib/ee/templates /usr/local/lib/python3.*/dist-packages/ee-*.egg /etc/ee /var/lib/ee
rm -rf /usr/local/bin/ee /etc/bash_completion.d/ee_auto.rc /usr/lib/ee/templates /usr/local/lib/python3.*/dist-packages/ee-*.egg /etc/ee /var/lib/ee
return 0
}
@@ -856,13 +819,13 @@ else
fi
_run wo_install_dep "Installing wo dependencies"
_run wo_timesync
if [ "$ufw" = "y" ]; then
_run wo_ufw_setup "Configuring UFW"
fi
#if [ "$ufw" = "y" ]; then
# _run wo_ufw_setup "Configuring UFW"
#fi
# skip steps if travis
if [ -z "$wo_travis" ]; then
_run wo_dist_upgrade
_run wo_download "Downloading WordOps"
_run wo_dist_upgrade
wo_git_config
_run wo_install "Installing WordOps"
else
@@ -908,7 +871,7 @@ else
wo_lib_echo "WordOps (wo) installed successfully"
echo
wo_lib_echo "To enable bash-completion, just use the command:"
wo_lib_echo_info "bash"
wo_lib_echo_info "bash -l"
echo
wo_lib_echo "To install WordOps recommended stacks, you can use the command:"
wo_lib_echo_info "wo stack install"

21
requirements-dev-py3.txt Normal file
View File

@@ -0,0 +1,21 @@
# The following are only required in development, not production
nose
coverage
sphinx
pep8
autopep8
mock
pyinotify
# Required for optional extensions (only the ones supported on py3)
argcomplete
pystache
pyYaml
colorlog
configobj
tabulate
pylibmc
redis
jinja2
watchdog
pybars3

View File

@@ -1,9 +1,12 @@
[nosetests]
verbosity=3
verbosity=2
debug=0
detailed-errors=1
with-coverage=1
cover-package=wo
cover-inclusive=1
cover-erase=1
cover-html=1
cover-html-dir=coverage_report/
where=tests/

View File

@@ -25,7 +25,7 @@ if not os.path.exists('/var/lib/wo/'):
os.makedirs('/var/lib/wo/')
setup(name='wo',
version='3.9.8.12',
version='3.9.9',
description=long_description,
long_description=long_description,
classifiers=[],

View File

@@ -27,12 +27,6 @@ class CliTestCaseStack(test.WOTestCase):
self.app.run()
self.app.close()
def test_wo_cli_stack_services_status_memcached(self):
self.app = get_test_app(argv=['stack', 'status', '--memcache'])
self.app.setup()
self.app.run()
self.app.close()
def test_wo_cli_stack_services_status_all(self):
self.app = get_test_app(argv=['stack', 'status'])
self.app.setup()

View File

@@ -2,6 +2,7 @@
from wo.utils import test
class ExamplePluginTestCase(test.WOTestCase):
def test_load_example_plugin(self):
self.app.setup()

View File

@@ -9,6 +9,10 @@ CRED="${CSI}1;31m"
CGREEN="${CSI}1;32m"
CEND="${CSI}0m"
apt-get -qq purge mysql* graphviz* redis*
apt-get install -qq git python3-setuptools python3-dev python3-apt ccze tree
sudo apt-get -qq autoremove --purge
exit_script() {
curl --progress-bar --upload-file /var/log/wo/wordops.log https://transfer.vtbox.net/"$(basename wordops.log)" && echo ""
exit 1
@@ -17,7 +21,7 @@ exit_script() {
echo -e "${CGREEN}#############################################${CEND}"
echo -e ' stack install '
echo -e "${CGREEN}#############################################${CEND}"
stack_list='nginx php php73 mysql redis fail2ban clamav proftpd netdata phpmyadmin composer dashboard extplorer adminer redis phpredisadmin mysqltuner utils'
stack_list='nginx php php73 mysql redis fail2ban clamav proftpd netdata phpmyadmin composer dashboard extplorer adminer redis phpredisadmin mysqltuner utils ufw'
for stack in $stack_list; do
echo -ne " Installing $stack [..]\r"
if {
@@ -150,9 +154,46 @@ for stack in $stack_upgrade; do
fi
done
echo -e "${CGREEN}#############################################${CEND}"
echo -e ' wo clean '
echo -e "${CGREEN}#############################################${CEND}"
stack_clean='fastcgi redis opcache all'
for stack in $stack_clean; do
echo -ne " cleaning $stack cache [..]\r"
if {
wo clean --${stack}
} >> /var/log/wo/test.log; then
echo -ne " cleaning $stack cache [${CGREEN}OK${CEND}]\\r"
echo -ne '\n'
else
echo -e " cleaning $stack cache [${CRED}FAIL${CEND}]"
echo -ne '\n'
exit_script
fi
done
echo -e "${CGREEN}#############################################${CEND}"
echo -e ' various informations '
echo -e "${CGREEN}#############################################${CEND}"
wp --allow-root --info
wo site info wp1.com
wo stack purge --all --force
wo site info wp.net
echo -e "${CGREEN}#############################################${CEND}"
echo -e ' wo stack purge '
echo -e "${CGREEN}#############################################${CEND}"
stack_purge='nginx php php73 mysql redis fail2ban clamav proftpd netdata phpmyadmin composer dashboard extplorer adminer redis ufw'
for stack in $stack_purge; do
echo -ne " purging $stack [..]\r"
if {
wo stack purge --${stack} --force
} >> /var/log/wo/test.log; then
echo -ne " purging $stack [${CGREEN}OK${CEND}]\\r"
echo -ne '\n'
else
echo -e " purging $stack [${CRED}FAIL${CEND}]"
echo -ne '\n'
exit_script
fi
done

View File

@@ -4,8 +4,9 @@
# in this file in the same way as WOBaseController.
from cement.core import handler
from wo.cli.controllers.base import WOBaseController
def load(app):
handler.register(WOBaseController)
app.handler.register(WOBaseController)

View File

@@ -1,7 +1,9 @@
"""WordOps base controller."""
from cement.core.controller import CementBaseController, expose
from wo.core.variables import WOVariables
VERSION = WOVariables.wo_version
BANNER = """

View File

@@ -2,8 +2,9 @@
# To avoid encoding releated error,we defined our custom output handler
# I hope we will remove this when we upgarde to Cement 2.6 (Not released yet)
import os
from cement.utils import fs
from cement.ext.ext_mustache import MustacheOutputHandler
from cement.utils import fs
class WOOutputHandler(MustacheOutputHandler):

View File

@@ -2,8 +2,8 @@
import os
import sys
from cement.core.foundation import CementApp
from cement.core.exc import CaughtSignal, FrameworkError
from cement.core.foundation import CementApp
from cement.ext.ext_argparse import ArgParseArgumentHandler
from cement.utils.misc import init_defaults

View File

@@ -90,6 +90,6 @@ class WOCleanController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOCleanController)
app.handler.register(WOCleanController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_clean_hook)
app.hook.register('post_argument_parsing', wo_clean_hook)

View File

@@ -588,7 +588,7 @@ class WODebugController(CementBaseController):
" disabled".format(self.app.pargs.site_name))
@expose(hide=True)
def signal_handler(self, signal, frame):
def signal_handler(self, app, signal, frame):
"""Handle Ctrl+c hevent for -i option of debug"""
self.start = False
if self.app.pargs.nginx:
@@ -847,6 +847,6 @@ class WODebugController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WODebugController)
app.handler.register(WODebugController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_debug_hook)
app.hook.register('post_argument_parsing', wo_debug_hook)

View File

@@ -26,7 +26,7 @@ class WOImportslowlogController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOImportslowlogController)
app.handler.register(WOImportslowlogController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_import_slow_log_hook)
app.hook.register('post_argument_parsing', wo_import_slow_log_hook)

View File

@@ -292,7 +292,7 @@ class WOInfoController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOInfoController)
app.handler.register(WOInfoController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_info_hook)
app.hook.register('post_argument_parsing', wo_info_hook)

View File

@@ -571,10 +571,10 @@ class WOLogMailController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOLogController)
handler.register(WOLogShowController)
handler.register(WOLogResetController)
handler.register(WOLogGzipController)
handler.register(WOLogMailController)
app.handler.register(WOLogController)
app.handler.register(WOLogShowController)
app.handler.register(WOLogResetController)
app.handler.register(WOLogGzipController)
app.handler.register(WOLogMailController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_log_hook)
app.hook.register('post_argument_parsing', wo_log_hook)

View File

@@ -40,6 +40,6 @@ class WOMaintenanceController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOMaintenanceController)
app.handler.register(WOMaintenanceController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_maintenance_hook)
app.hook.register('post_argument_parsing', wo_maintenance_hook)

View File

@@ -1,16 +1,16 @@
import getpass
import random
import string
import os
from cement.core import handler, hook
from cement.core.controller import CementBaseController, expose
from wo.core.git import WOGit
from wo.core.logging import Log
from wo.core.random import RANDOM
from wo.core.services import WOService
from wo.core.shellexec import WOShellExec
from wo.core.template import WOTemplate
from wo.core.variables import WOVariables
from wo.core.random import RANDOM
def wo_secure_hook(app):
@@ -33,6 +33,13 @@ class WOSecureController(CementBaseController):
dict(help='set backend port', action='store_true')),
(['--ip'],
dict(help='set backend whitelisted ip', action='store_true')),
(['--sshport'], dict(
help='set custom ssh port', action='store_true')),
(['--ssh'], dict(
help='harden ssh security', action='store_true')),
(['--force'],
dict(help='force execution without being prompt',
action='store_true')),
(['user_input'],
dict(help='user input', nargs='?', default=None)),
(['user_pass'],
@@ -48,10 +55,16 @@ class WOSecureController(CementBaseController):
self.secure_port()
if pargs.ip:
self.secure_ip()
if pargs.sshport:
self.secure_ssh_port()
if pargs.ssh:
self.secure_ssh()
@expose(hide=True)
def secure_auth(self):
"""This function secures authentication"""
WOGit.add(self, ["/etc/nginx"],
msg="Add Nginx to into Git")
pargs = self.app.pargs
passwd = RANDOM.long(self)
if not pargs.user_input:
@@ -83,17 +96,20 @@ class WOSecureController(CementBaseController):
@expose(hide=True)
def secure_port(self):
"""This function Secures port"""
WOGit.add(self, ["/etc/nginx"],
msg="Add Nginx to into Git")
pargs = self.app.pargs
if pargs.user_input:
while not pargs.user_input.isdigit():
while ((not pargs.user_input.isdigit()) and
(not pargs.user_input < 65536)):
Log.info(self, "Please enter a valid port number ")
pargs.user_input = input("WordOps "
"admin port [22222]:")
if not pargs.user_input:
port = input("WordOps admin port [22222]:")
if port == "":
pargs.user_input = 22222
while (not port.isdigit()) and (port != "") and (not port < 65556):
port = 22222
while (not port.isdigit()) and (port != "") and (not port < 65536):
Log.info(self, "Please Enter valid port number :")
port = input("WordOps admin port [22222]:")
pargs.user_input = port
@@ -112,6 +128,8 @@ class WOSecureController(CementBaseController):
@expose(hide=True)
def secure_ip(self):
"""IP whitelisting"""
WOGit.add(self, ["/etc/nginx"],
msg="Add Nginx to into Git")
pargs = self.app.pargs
if not pargs.user_input:
ip = input("Enter the comma separated IP addresses "
@@ -134,7 +152,75 @@ class WOSecureController(CementBaseController):
Log.info(self, "Successfully added IP address in acl.conf file")
@expose(hide=True)
def secure_ssh(self):
"""Harden ssh security"""
pargs = self.app.pargs
if not pargs.force:
start_secure = input('Are you sure you to want to'
' harden SSH security ?'
'\nSSH login with password will not '
'be possible anymore. Please make sure '
'you are already using SSH Keys.\n'
'Harden SSH security [y/N]')
if start_secure != "Y" and start_secure != "y":
Log.error(self, "Not hardening SSH security")
Log.debug(self, "check if /etc/ssh/sshd_config exist")
if os.path.isfile('/etc/ssh/sshd_config'):
Log.debug(self, "looking for the current ssh port")
for line in open('/etc/ssh/sshd_config', encoding='utf-8'):
if 'Port' in line:
ssh_line = line.strip()
break
port = (ssh_line).split(' ')
current_ssh_port = (port[1]).strip()
if os.getenv('SUDO_USER'):
sudo_user = os.getenv('SUDO_USER')
else:
sudo_user = ''
data = dict(sshport=current_ssh_port, allowpass='no',
user=sudo_user)
WOTemplate.deploy(self, '/etc/ssh/sshd_config',
'sshd.mustache', data)
WOGit.add(self, ["/etc/ssh"],
msg="Adding changed SSH port into Git")
if not WOService.restart_service(self, 'ssh'):
Log.error(self, "service SSH restart failed.")
Log.info(self, "Successfully harden SSH security")
else:
Log.error(self, "SSH config file not found")
@expose(hide=True)
def secure_ssh_port(self):
"""Change SSH port"""
WOGit.add(self, ["/etc/ssh"],
msg="Adding changed SSH port into Git")
pargs = self.app.pargs
if pargs.user_input:
while ((not pargs.user_input.isdigit()) and
(not pargs.user_input < 65536)):
Log.info(self, "Please enter a valid port number ")
pargs.user_input = input("Server "
"SSH port [22]:")
if not pargs.user_input:
port = input("Server SSH port [22]:")
if port == "":
port = 22
while (not port.isdigit()) and (port != "") and (not port < 65536):
Log.info(self, "Please Enter valid port number :")
port = input("Server SSH port [22]:")
pargs.user_input = port
WOShellExec.cmd_exec(self, "sed -i \"s/Port.*/Port "
"{port}/\" /etc/ssh/sshd_config"
.format(port=pargs.user_input))
WOGit.add(self, ["/etc/ssh"],
msg="Adding changed SSH port into Git")
if not WOService.restart_service(self, 'ssh'):
Log.error(self, "service SSH restart failed.")
Log.info(self, "Successfully changed SSH port to {port}"
.format(port=pargs.user_input))
def load(app):
handler.register(WOSecureController)
hook.register('post_argument_parsing', wo_secure_hook)
app.handler.register(WOSecureController)
app.hook.register('post_argument_parsing', wo_secure_hook)

View File

@@ -1,9 +1,7 @@
# """WordOps site controller."""
import glob
import json
import os
import subprocess
from subprocess import Popen
from cement.core import handler, hook
from cement.core.controller import CementBaseController, expose
@@ -11,6 +9,7 @@ from cement.core.controller import CementBaseController, expose
from wo.cli.plugins.site_functions import *
from wo.cli.plugins.sitedb import (addNewSite, deleteSiteInfo, getAllsites,
getSiteInfo, updateSiteInfo)
from wo.core.acme import WOAcme
from wo.core.domainvalidate import WODomain
from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit
@@ -58,7 +57,8 @@ class WOSiteController(CementBaseController):
pargs.site_name = pargs.site_name.strip()
# validate domain name
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
# check if site exists
if not check_domain_exists(self, wo_domain):
@@ -136,8 +136,10 @@ class WOSiteController(CementBaseController):
Log.debug(self, str(e))
Log.error(self, 'could not input site name')
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self, wo_domain)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain_type,
wo_root_domain) = WODomain.getdomainlevel(self, wo_domain)
wo_db_name = ''
wo_db_user = ''
wo_db_pass = ''
@@ -188,7 +190,8 @@ class WOSiteController(CementBaseController):
def log(self):
pargs = self.app.pargs
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
wo_site_webroot = getSiteInfo(self, wo_domain).site_path
if not check_domain_exists(self, wo_domain):
@@ -210,7 +213,8 @@ class WOSiteController(CementBaseController):
Log.error(self, 'could not input site name')
# TODO Write code for wo site edit command here
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
if not check_domain_exists(self, wo_domain):
Log.error(self, "site {0} does not exist".format(wo_domain))
@@ -241,7 +245,8 @@ class WOSiteController(CementBaseController):
Log.error(self, 'Unable to read input, please try again')
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
if not check_domain_exists(self, wo_domain):
Log.error(self, "site {0} does not exist".format(wo_domain))
@@ -261,7 +266,6 @@ class WOSiteEditController(CementBaseController):
label = 'edit'
stacked_on = 'site'
stacked_type = 'nested'
exit_on_close = True
description = ('Edit Nginx configuration of site')
arguments = [
(['site_name'],
@@ -282,7 +286,8 @@ class WOSiteEditController(CementBaseController):
Log.error(self, 'Unable to read input, Please try again')
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
if not check_domain_exists(self, wo_domain):
Log.error(self, "site {0} does not exist".format(wo_domain))
@@ -316,7 +321,6 @@ class WOSiteCreateController(CementBaseController):
label = 'create'
stacked_on = 'site'
stacked_type = 'nested'
exit_on_close = True
description = ('this commands set up configuration and installs '
'required files as options are provided')
arguments = [
@@ -368,6 +372,9 @@ class WOSiteCreateController(CementBaseController):
dict(help="choose dns provider api for letsencrypt",
action='store' or 'store_const',
const='dns_cf', nargs='?')),
(['--dnsalias'],
dict(help="set domain used for acme dns alias validation",
action='store', nargs='?')),
(['--hsts'],
dict(help="enable HSTS for site secured with letsencrypt",
action='store_true')),
@@ -424,7 +431,8 @@ class WOSiteCreateController(CementBaseController):
Log.error(self, "Unable to input site name, Please try again!")
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
if not wo_domain.strip():
Log.error(self, "Invalid domain name, "
"Provide valid domain name")
@@ -717,31 +725,60 @@ class WOSiteCreateController(CementBaseController):
"`tail /var/log/wo/wordops.log` and please try again")
if pargs.letsencrypt:
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self,
wo_domain)
acme_domains = []
(wo_domain_type,
wo_root_domain) = WODomain.getdomainlevel(self,
wo_domain)
data['letsencrypt'] = True
letsencrypt = True
if data['letsencrypt'] is True:
Log.debug(self, "Going to issue Let's Encrypt certificate")
acmedata = dict(acme_domains, dns=False, acme_dns='dns_cf',
dnsalias=False, acme_alias='')
if pargs.dns:
wo_acme_dns = pargs.dns
wo_dns = True
else:
wo_acme_dns = ''
wo_dns = False
Log.debug(self, "DNS validation enabled")
acmedata['dns'] = True
if not pargs.dns == 'dns_cf':
Log.debug(self, "DNS API : {0}".format(pargs.dns))
acmedata['acme_dns'] = pargs.dns
if pargs.dnsalias:
Log.debug(self, "DNS Alias enabled")
acmedata['dnsalias'] = True
acmedata['acme_alias'] = pargs.dnsalias
# detect subdomain and set subdomain variable
if pargs.letsencrypt == "subdomain":
wo_subdomain = True
wo_wildcard = False
Log.warn(
self, 'Flag --letsencrypt=subdomain is '
'deprecated and not required anymore.')
acme_subdomain = True
acme_wildcard = False
elif pargs.letsencrypt == "wildcard":
wo_wildcard = True
wo_subdomain = False
acme_wildcard = True
acme_subdomain = False
acmedata['dns'] = True
else:
wo_wildcard = False
wo_subdomain = False
Log.debug(self, "Domain type = {0}"
.format(wo_domain_type))
if ((wo_domain_type == 'subdomain') and
(not pargs.letsencrypt == 'wildcard')):
wo_subdomain = True
if ((wo_domain_type == 'subdomain')):
Log.debug(self, "Domain type = {0}"
.format(wo_domain_type))
acme_subdomain = True
else:
acme_subdomain = False
acme_wildcard = False
if acme_subdomain is True:
Log.info(self, "Certificate type : subdomain")
acme_domains = acme_domains + ['{0}'.format(wo_domain)]
elif acme_wildcard is True:
Log.info(self, "Certificate type : wildcard")
acme_domains = acme_domains + ['{0}'.format(wo_domain),
'*.{0}'.format(wo_domain)]
else:
Log.info(self, "Certificate type : domain")
acme_domains = acme_domains + ['{0}'.format(wo_domain),
'www.{0}'.format(wo_domain)]
if acme_subdomain is True:
# check if a wildcard cert for the root domain exist
Log.debug(self, "checkWildcardExist on *.{0}"
.format(wo_root_domain))
@@ -757,14 +794,25 @@ class WOSiteCreateController(CementBaseController):
# copy the cert from the root domain
copyWildcardCert(self, wo_domain, wo_root_domain)
else:
# check DNS records before issuing cert
if not acmedata['dns'] is True:
if not WOAcme.check_dns(self, acme_domains):
Log.error(self,
"Aborting SSL certificate issuance")
Log.debug(self, "Setup Cert with acme.sh for {0}"
.format(wo_domain))
setupLetsEncrypt(self, wo_domain, wo_subdomain,
wo_wildcard, wo_dns, wo_acme_dns)
if WOAcme.setupletsencrypt(
self, acme_domains, acmedata):
WOAcme.deploycert(self, wo_domain)
else:
setupLetsEncrypt(self, wo_domain, wo_subdomain,
wo_wildcard, wo_dns, wo_acme_dns)
httpsRedirect(self, wo_domain, True, wo_wildcard)
if not acmedata['dns'] is True:
if not WOAcme.check_dns(self, acme_domains):
Log.error(self,
"Aborting SSL certificate issuance")
if WOAcme.setupletsencrypt(
self, acme_domains, acmedata):
WOAcme.deploycert(self, wo_domain)
httpsRedirect(self, wo_domain, True, acme_wildcard)
if pargs.hsts:
SSL.setuphsts(self, wo_domain)
@@ -792,7 +840,6 @@ class WOSiteUpdateController(CementBaseController):
label = 'update'
stacked_on = 'site'
stacked_type = 'nested'
exit_on_close = True
description = ('This command updates websites configuration to '
'another as per the options are provided')
arguments = [
@@ -842,6 +889,9 @@ class WOSiteUpdateController(CementBaseController):
dict(help="choose dns provider api for letsencrypt",
action='store' or 'store_const',
const='dns_cf', nargs='?')),
(['--dnsalias'],
dict(help="set domain used for acme dns alias validation",
action='store', nargs='?')),
(['--hsts'],
dict(help="configure hsts for the site",
action='store' or 'store_const',
@@ -931,7 +981,8 @@ class WOSiteUpdateController(CementBaseController):
Log.error(self, 'Unable to input site name, Please try again!')
pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
(wo_domain,
wo_www_domain) = WODomain.validatedomain(self, pargs.site_name)
wo_site_webroot = WOVariables.wo_webroot + wo_domain
check_site = getSiteInfo(self, wo_domain)
@@ -1129,44 +1180,48 @@ class WOSiteUpdateController(CementBaseController):
pargs.php73 = False
if pargs.letsencrypt:
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self,
wo_domain)
acme_domains = []
acmedata = dict(acme_domains, dns=False, acme_dns='dns_cf',
dnsalias=False, acme_alias='')
(wo_domain_type,
wo_root_domain) = WODomain.getdomainlevel(self, wo_domain)
if pargs.letsencrypt == 'on':
data['letsencrypt'] = True
letsencrypt = True
if ((wo_domain_type == 'subdomain') and
(not pargs.letsencrypt == 'wildcard')):
wo_subdomain = True
if (wo_domain_type == 'subdomain'):
acme_subdomain = True
else:
wo_subdomain = False
wo_wildcard = False
acme_subdomain = False
acme_wildcard = False
elif pargs.letsencrypt == 'subdomain':
data['letsencrypt'] = True
letsencrypt = True
wo_subdomain = True
wo_wildcard = False
acme_subdomain = True
acme_wildcard = False
elif pargs.letsencrypt == 'wildcard':
data['letsencrypt'] = True
letsencrypt = True
wo_wildcard = True
wo_subdomain = False
acme_wildcard = True
acme_subdomain = False
acmedata['dns'] = True
elif pargs.letsencrypt == 'off':
data['letsencrypt'] = False
letsencrypt = False
wo_subdomain = False
wo_wildcard = False
acme_subdomain = False
acme_wildcard = False
elif pargs.letsencrypt == 'clean':
data['letsencrypt'] = False
letsencrypt = False
wo_subdomain = False
wo_wildcard = False
acme_subdomain = False
acme_wildcard = False
elif pargs.letsencrypt == 'purge':
data['letsencrypt'] = False
letsencrypt = False
wo_subdomain = False
wo_wildcard = False
acme_subdomain = False
acme_wildcard = False
if not wo_subdomain:
if not (acme_subdomain is True):
if letsencrypt is check_ssl:
if letsencrypt is False:
Log.error(self, "SSl is not configured for given "
@@ -1271,13 +1326,12 @@ class WOSiteUpdateController(CementBaseController):
data['php73'] = False
php73 = False
if pargs.letsencrypt == "on" or pargs.php73 == "on":
if pargs.php73 == "on":
data['php73'] = True
php73 = True
else:
data['php73'] = False
php73 = False
if pargs.php73 == "on":
data['php73'] = True
php73 = True
else:
data['php73'] = False
php73 = False
if pargs.wpredis and data['currcachetype'] != 'wpredis':
data['wpredis'] = True
@@ -1348,20 +1402,38 @@ class WOSiteUpdateController(CementBaseController):
if pargs.letsencrypt:
if data['letsencrypt'] is True:
# DNS API configuration
if pargs.dns:
wo_acme_dns = pargs.dns
wo_dns = True
Log.debug(self, "DNS validation enabled")
acmedata['dns'] = True
if not pargs.dns == 'dns_cf':
Log.debug(self, "DNS API : {0}".format(pargs.dns))
acmedata['acme_dns'] = pargs.dns
if pargs.dnsalias:
Log.debug(self, "DNS Alias enabled")
acmedata['dnsalias'] = True
acmedata['acme_alias'] = pargs.dnsalias
# Set list of domains to secure
if acme_subdomain is True:
Log.info(self, "Certificate type : subdomain")
acme_domains = acme_domains + ['{0}'.format(wo_domain)]
elif acme_wildcard is True:
Log.info(self, "Certificate type : wildcard")
acme_domains = acme_domains + ['{0}'.format(wo_domain),
'*.{0}'.format(wo_domain)]
else:
wo_acme_dns = ''
wo_dns = False
if wo_subdomain:
Log.info(self, "Certificate type : domain")
acme_domains = acme_domains + ['{0}'.format(wo_domain),
'www.{0}'.format(wo_domain)]
if acme_subdomain:
# check if a wildcard cert for the root domain exist
Log.debug(self, "checkWildcardExist on *.{0}"
.format(wo_root_domain))
iswildcard = SSL.checkwildcardexist(self, wo_root_domain)
Log.debug(self, "iswildcard = {0}".format(iswildcard))
if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"):
if wo_subdomain:
if acme_subdomain:
if iswildcard:
Log.info(self, "Using existing Wildcard SSL "
"certificate from {0} to secure {1}"
@@ -1372,13 +1444,31 @@ class WOSiteUpdateController(CementBaseController):
# copy the cert from the root domain
copyWildcardCert(self, wo_domain, wo_root_domain)
else:
# check DNS records before issuing cert
if not acmedata['dns'] is True:
if not WOAcme.check_dns(self, acme_domains):
Log.error(
self,
"Aborting SSL certificate issuance")
Log.debug(self, "Setup Cert with acme.sh for {0}"
.format(wo_domain))
setupLetsEncrypt(self, wo_domain, wo_subdomain,
wo_wildcard, wo_dns, wo_acme_dns)
if WOAcme.setupletsencrypt(
self, acme_domains, acmedata):
WOAcme.deploycert(self, wo_domain)
else:
Log.error(self, "Unable to issue certificate")
else:
setupLetsEncrypt(self, wo_domain, wo_subdomain,
wo_wildcard, wo_dns, wo_acme_dns)
# check DNS records before issuing cert
if not acmedata['dns'] is True:
if not WOAcme.check_dns(self, acme_domains):
Log.error(
self,
"Aborting SSL certificate issuance")
if WOAcme.setupletsencrypt(
self, acme_domains, acmedata):
WOAcme.deploycert(self, wo_domain)
else:
Log.error(self, "Unable to issue certificate")
else:
WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled"
.format(wo_site_webroot),
@@ -1390,7 +1480,7 @@ class WOSiteUpdateController(CementBaseController):
'/etc/nginx/conf.d/force-ssl-{0}.conf'
.format(wo_domain))
httpsRedirect(self, wo_domain, True, wo_wildcard)
httpsRedirect(self, wo_domain, True, acme_wildcard)
SSL.siteurlhttps(self, wo_domain)
if not WOService.reload_service(self, 'nginx'):
@@ -1399,7 +1489,7 @@ class WOSiteUpdateController(CementBaseController):
Log.info(self, "Congratulations! Successfully "
"Configured SSL for Site "
" https://{0}".format(wo_domain))
if wo_subdomain and iswildcard:
if acme_subdomain and iswildcard:
if (SSL.getexpirationdays(self, wo_root_domain) > 0):
Log.info(
self, "Your cert will expire within " +
@@ -1826,7 +1916,6 @@ class WOSiteDeleteController(CementBaseController):
label = 'delete'
stacked_on = 'site'
stacked_type = 'nested'
exit_on_close = True
description = 'delete an existing website'
arguments = [
(['site_name'],
@@ -1966,7 +2055,6 @@ class WOSiteListController(CementBaseController):
label = 'list'
stacked_on = 'site'
stacked_type = 'nested'
exit_on_close = True
description = 'List websites'
arguments = [
(['--enabled'],
@@ -1997,11 +2085,11 @@ class WOSiteListController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOSiteController)
handler.register(WOSiteCreateController)
handler.register(WOSiteUpdateController)
handler.register(WOSiteDeleteController)
handler.register(WOSiteListController)
handler.register(WOSiteEditController)
app.handler.register(WOSiteController)
app.handler.register(WOSiteCreateController)
app.handler.register(WOSiteUpdateController)
app.handler.register(WOSiteDeleteController)
app.handler.register(WOSiteListController)
app.handler.register(WOSiteEditController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_site_hook)
app.hook.register('post_argument_parsing', wo_site_hook)

View File

@@ -11,6 +11,7 @@ from subprocess import CalledProcessError
from wo.cli.plugins.sitedb import getSiteInfo
from wo.cli.plugins.stack import WOStackController
from wo.cli.plugins.stack_pref import post_pref
from wo.core.acme import WOAcme
from wo.core.aptget import WOAptGet
from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit
@@ -38,8 +39,8 @@ def pre_run_checks(self):
Log.wait(self, "Running pre-update checks")
try:
Log.debug(self, "checking NGINX configuration ...")
FNULL = open('/dev/null', 'w')
subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=FNULL,
fnull = open('/dev/null', 'w')
subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=fnull,
stderr=subprocess.STDOUT)
except CalledProcessError as e:
Log.failed(self, "Running pre-update checks")
@@ -1348,129 +1349,6 @@ def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='',
# setup letsencrypt for domain + www.domain
def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False,
wo_dns=False, wo_acme_dns='dns_cf'):
if os.path.isfile("/etc/letsencrypt/"
"renewal/{0}_ecc/"
"fullchain.cer".format(wo_domain_name)):
Log.debug(self, "Let's Encrypt certificate "
"found for the domain: {0}"
.format(wo_domain_name))
ssl = archivedCertificateHandle(self, wo_domain_name)
else:
keylenght = "{0}".format(self.app.config.get('letsencrypt',
'keylength'))
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
"'/etc/letsencrypt/config'")
if wo_dns:
acme_mode = "--dns {0}".format(wo_acme_dns)
validation_mode = "DNS with {0}".format(wo_acme_dns)
Log.debug(
self, "Validation : DNS mode with {0}".format(wo_acme_dns))
else:
acme_mode = "-w /var/www/html"
validation_mode = "Webroot challenge"
Log.debug(self, "Validation : Webroot mode")
if subdomain:
Log.info(self, "Certificate type: Subdomain")
Log.info(self, "Validation mode : {0}".format(validation_mode))
Log.wait(self, "Issuing SSL cert with acme.sh")
ssl = WOShellExec.cmd_exec(self, "{0} ".format(wo_acme_exec) +
"--issue "
"-d {0} {1} "
"-k {2} -f"
.format(wo_domain_name,
acme_mode,
keylenght))
elif wildcard:
Log.info(self, "Certificate type: Wildcard")
Log.info(self, "Validation mode : {0}".format(validation_mode))
Log.wait(self, "Issuing SSL cert with acme.sh")
ssl = WOShellExec.cmd_exec(self, "{0} ".format(wo_acme_exec) +
"--issue "
"-d {0} -d '*.{0}' --dns {1} "
"-k {2} -f"
.format(wo_domain_name,
wo_acme_dns,
keylenght))
else:
Log.info(self, "Certificate type: Domain + www")
Log.info(self, "Validation mode : {0}".format(validation_mode))
Log.wait(self, "Issuing SSL cert with acme.sh")
ssl = WOShellExec.cmd_exec(self, "{0} ".format(wo_acme_exec) +
"--issue "
"-d {0} -d www.{0} {1} "
"-k {2} -f"
.format(wo_domain_name,
acme_mode, keylenght))
if ssl:
Log.valide(self, "Issuing SSL cert with acme.sh")
Log.wait(self, "Deploying SSL cert")
Log.debug(self, "Cert deployment for domain: {0}"
.format(wo_domain_name))
try:
WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && "
"/etc/letsencrypt/acme.sh "
"--config-home "
"'/etc/letsencrypt/config' "
"--install-cert -d {1} --ecc "
"--cert-file {0}/{1}/cert.pem "
"--key-file {0}/{1}/key.pem "
"--fullchain-file "
"{0}/{1}/fullchain.pem "
"--ca-file {0}/{1}/ca.pem "
"--reloadcmd "
"\"nginx -t && "
"service nginx restart\" "
.format(WOVariables.wo_ssl_live,
wo_domain_name))
Log.valide(self, "Deploying SSL cert")
if os.path.isdir('/var/www/{0}/conf/nginx'
.format(wo_domain_name)):
sslconf = open("/var/www/{0}/conf/nginx/ssl.conf"
.format(wo_domain_name),
encoding='utf-8', mode='w')
sslconf.write(
"listen 443 ssl http2;\n"
"listen [::]:443 ssl http2;\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)
if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf',
'/etc/letsencrypt'):
Log.info(self, "Securing WordOps backend with {0} certificate"
.format(wo_domain_name))
sslconf = open("/var/www/22222/conf/nginx/ssl.conf",
encoding='utf-8', mode='w')
sslconf.write("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()
WOGit.add(self, ["/etc/letsencrypt"],
msg="Adding letsencrypt folder")
except IOError as e:
Log.debug(self, str(e))
Log.debug(self, "Error occured while generating "
"ssl.conf")
else:
Log.error(self, "Unable to install certificate", False)
Log.error(self, "Please make sure that your site is pointed to \n"
"same server on which "
"you are running Let\'s Encrypt Client "
"\n to allow it to verify the site automatically.")
# copy wildcard certificate to a subdomain
@@ -1616,14 +1494,16 @@ def httpsRedirect(self, wo_domain_name, redirect=True, wildcard=False):
def archivedCertificateHandle(self, domain):
Log.warn(self, "You already have an existing certificate "
"for the domain requested.\n"
"(ref: {0}/"
"{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) +
"\nPlease select an option from below?"
"\n\t1: Reinstall existing certificate"
"\n\t2: Renew & replace the certificate (limit ~5 per 7 days)"
"")
Log.warn(
self, "You already have an existing certificate "
"for the domain requested.\n"
"(ref: {0}/"
"{1}_ecc/{1}.conf)".format(WOVariables.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"
@@ -1634,20 +1514,7 @@ def archivedCertificateHandle(self, domain):
if check_prompt == "1":
Log.info(self, "Reinstalling SSL cert with acme.sh")
ssl = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && "
"/etc/letsencrypt/acme.sh "
"--config-home "
"'/etc/letsencrypt/config' "
"--install-cert -d {1} --ecc "
"--cert-file {0}/{1}/cert.pem "
"--key-file {0}/{1}/key.pem "
"--fullchain-file "
"{0}/{1}/fullchain.pem "
"--ca-file {0}/{1}/ca.pem "
"--reloadcmd "
"\"nginx -t && service nginx restart\" "
.format(WOVariables.wo_ssl_live,
domain))
ssl = WOAcme.deploycert(self, domain)
if ssl:
try:
@@ -1727,7 +1594,7 @@ def setuprocketchat(self):
if ((not WOVariables.wo_platform_codename == 'bionic') and
(not WOVariables.wo_platform_codename == 'xenial')):
Log.info(self, "Rocket.chat is only available on Ubuntu 16.04 "
"& 18.04 LTS")
"& 18.04 LTS")
return False
else:
if not WOAptGet.is_installed(self, 'snapd'):

View File

@@ -1,16 +1,6 @@
"""Stack Plugin for WordOps"""
import codecs
import configparser
import os
import pwd
import random
import re
import shutil
import string
import psutil
import requests
from cement.core import handler, hook
from cement.core.controller import CementBaseController, expose
@@ -21,18 +11,13 @@ from wo.cli.plugins.stack_migrate import WOStackMigrateController
from wo.cli.plugins.stack_pref import post_pref, pre_pref
from wo.cli.plugins.stack_services import WOStackStatusController
from wo.cli.plugins.stack_upgrade import WOStackUpgradeController
from wo.core.apt_repo import WORepo
from wo.core.aptget import WOAptGet
from wo.core.cron import WOCron
from wo.core.download import WODownload
from wo.core.extract import WOExtract
from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit
from wo.core.logging import Log
from wo.core.mysql import WOMysql
from wo.core.services import WOService
from wo.core.shellexec import CommandExecutionError, WOShellExec
from wo.core.template import WOTemplate
from wo.core.shellexec import WOShellExec
from wo.core.variables import WOVariables
@@ -88,6 +73,8 @@ class WOStackController(CementBaseController):
dict(help='Install Fail2ban stack', action='store_true')),
(['--clamav'],
dict(help='Install ClamAV stack', action='store_true')),
(['--ufw'],
dict(help='Install UFW stack', action='store_true')),
(['--sendmail'],
dict(help='Install Sendmail stack', action='store_true')),
(['--utils'],
@@ -129,6 +116,7 @@ class WOStackController(CementBaseController):
(not pargs.adminer) and (not pargs.utils) and
(not pargs.redis) and (not pargs.proftpd) and
(not pargs.extplorer) and (not pargs.clamav) and
(not pargs.ufw) and
(not pargs.phpredisadmin) and (not pargs.sendmail) and
(not pargs.php73)):
pargs.web = True
@@ -164,6 +152,7 @@ class WOStackController(CementBaseController):
if pargs.security:
pargs.fail2ban = True
pargs.clamav = True
pargs.ufw = True
# Nginx
if pargs.nginx:
@@ -270,6 +259,13 @@ class WOStackController(CementBaseController):
Log.debug(self, "ClamAV already installed")
Log.info(self, "ClamAV already installed")
# UFW
if pargs.ufw:
if not WOFileUtils.grep(
self, '/etc/ufw/ufw.conf', 'ENABLED=yes'):
Log.debug(self, "Setting apt_packages variable for UFW")
apt_packages = apt_packages + ["ufw"]
# sendmail
if pargs.sendmail:
Log.debug(self, "Setting apt_packages variable for Sendmail")
@@ -492,7 +488,9 @@ class WOStackController(CementBaseController):
Log.debug(self, "Downloading following: {0}".format(packages))
WODownload.download(self, packages)
Log.debug(self, "Calling post_pref")
Log.wait(self, "Configuring packages")
post_pref(self, [], packages)
Log.valide(self, "Configuring packages")
if disp_msg:
if (self.msg):
@@ -518,6 +516,7 @@ class WOStackController(CementBaseController):
(not pargs.adminer) and (not pargs.utils) and
(not pargs.redis) and (not pargs.proftpd) and
(not pargs.extplorer) and (not pargs.clamav) and
(not pargs.ufw) and
(not pargs.phpredisadmin) and (not pargs.sendmail) and
(not pargs.php73)):
pargs.web = True
@@ -551,6 +550,7 @@ class WOStackController(CementBaseController):
if pargs.security:
pargs.fail2ban = True
pargs.clamav = True
pargs.ufw = True
# NGINX
if pargs.nginx:
@@ -580,14 +580,17 @@ class WOStackController(CementBaseController):
# REDIS
if pargs.redis:
Log.debug(self, "Remove apt_packages variable of Redis")
apt_packages = apt_packages + ["redis-server"]
if WOAptGet.is_installed(self, 'redis-server'):
Log.debug(self, "Remove apt_packages variable of Redis")
apt_packages = apt_packages + ["redis-server"]
# MariaDB
if pargs.mysql:
Log.debug(self, "Removing apt_packages variable of MySQL")
apt_packages = apt_packages + ['mariadb-server', 'mysql-common',
'mariadb-client']
if WOAptGet.is_installed(self, 'mariadb-server'):
Log.debug(self, "Removing apt_packages variable of MySQL")
apt_packages = apt_packages + ['mariadb-server',
'mysql-common',
'mariadb-client']
# mysqlclient
if pargs.mysqlclient:
@@ -620,6 +623,12 @@ class WOStackController(CementBaseController):
Log.debug(self, "Remove apt_packages variable for ProFTPd")
apt_packages = apt_packages + ["proftpd-basic"]
# UFW
if pargs.ufw:
if WOAptGet.is_installed(self, 'ufw'):
Log.debug(self, "Remove apt_packages variable for UFW")
apt_packages = apt_packages + ["ufw"]
# WPCLI
if pargs.wpcli:
Log.debug(self, "Removing package variable of WPCLI ")
@@ -628,18 +637,22 @@ class WOStackController(CementBaseController):
# PHPMYADMIN
if pargs.phpmyadmin:
Log.debug(self, "Removing package of phpMyAdmin ")
packages = packages + ['{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)]
if os.path.isdir('{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)):
Log.debug(self, "Removing package of phpMyAdmin ")
packages = packages + ['{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)]
# Composer
if pargs.composer:
Log.debug(self, "Removing package of Composer ")
if os.path.isfile('/usr/local/bin/composer'):
packages = packages + ['/usr/local/bin/composer']
# MySQLTuner
if pargs.mysqltuner:
Log.debug(self, "Removing packages for MySQLTuner ")
packages = packages + ['/usr/bin/mysqltuner']
if os.path.isfile('/usr/bin/mysqltuner'):
Log.debug(self, "Removing packages for MySQLTuner ")
packages = packages + ['/usr/bin/mysqltuner']
# PHPREDISADMIN
if pargs.phpredisadmin:
@@ -651,9 +664,11 @@ class WOStackController(CementBaseController):
.format(WOVariables.wo_webroot)]
# ADMINER
if pargs.adminer:
Log.debug(self, "Removing package variable of Adminer ")
packages = packages + ['{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)]
if os.path.isdir('{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)):
Log.debug(self, "Removing package variable of Adminer ")
packages = packages + ['{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)]
if pargs.utils:
Log.debug(self, "Removing package variable of utils ")
packages = packages + ['{0}22222/htdocs/php/webgrind/'
@@ -673,11 +688,17 @@ class WOStackController(CementBaseController):
packages = packages + ['/var/lib/wo/tmp/kickstart.sh']
if pargs.dashboard:
Log.debug(self, "Removing Wo-Dashboard")
packages = packages + ['{0}22222/htdocs/assets'
.format(WOVariables.wo_webroot),
'{0}22222/htdocs/index.php'
.format(WOVariables.wo_webroot)]
if (os.path.isfile('{0}22222/htdocs/index.php'
.format(WOVariables.wo_webroot)) or
os.path.isfile('{0}22222/htdocs/index.html'
.format(WOVariables.wo_webroot))):
Log.debug(self, "Removing Wo-Dashboard")
packages = packages + ['{0}22222/htdocs/assets'
.format(WOVariables.wo_webroot),
'{0}22222/htdocs/index.php'
.format(WOVariables.wo_webroot),
'{0}22222/htdocs/index.html'
.format(WOVariables.wo_webroot)]
if (packages) or (apt_packages):
if (not pargs.force):
@@ -689,10 +710,10 @@ class WOStackController(CementBaseController):
if start_remove != "Y" and start_remove != "y":
Log.error(self, "Not starting stack removal")
if (set(["nginx-custom"]).issubset(set(apt_packages))):
if 'nginx-custom' in apt_packages:
WOService.stop_service(self, 'nginx')
if (set(["mariadb-server"]).issubset(set(apt_packages))):
if 'mariadb-server' in apt_packages:
WOMysql.backupAll(self)
WOService.stop_service(self, 'mysql')
@@ -739,6 +760,7 @@ class WOStackController(CementBaseController):
(not pargs.adminer) and (not pargs.utils) and
(not pargs.redis) and (not pargs.proftpd) and
(not pargs.extplorer) and (not pargs.clamav) and
(not pargs.ufw) and
(not pargs.phpredisadmin) and (not pargs.sendmail) and
(not pargs.php73)):
pargs.web = True
@@ -771,16 +793,19 @@ class WOStackController(CementBaseController):
if pargs.security:
pargs.fail2ban = True
pargs.clamav = True
pargs.ufw = True
# NGINX
if pargs.nginx:
if WOAptGet.is_installed(self, 'nginx-custom'):
Log.debug(self, "Purge apt_packages variable of Nginx")
Log.debug(self, "Add Nginx to apt_packages list")
apt_packages = apt_packages + WOVariables.wo_nginx
else:
Log.info(self, "Nginx is not installed")
# PHP
if pargs.php:
Log.debug(self, "Purge apt_packages variable PHP")
Log.debug(self, "Add PHP to apt_packages list")
if WOAptGet.is_installed(self, 'php7.2-fpm'):
if not (WOAptGet.is_installed(self, 'php7.3-fpm')):
apt_packages = apt_packages + WOVariables.wo_php + \
@@ -800,68 +825,84 @@ class WOStackController(CementBaseController):
# REDIS
if pargs.redis:
Log.debug(self, "Remove apt_packages variable of Redis")
apt_packages = apt_packages + ["redis-server"]
if WOAptGet.is_installed(self, 'redis-server'):
Log.debug(self, "Remove apt_packages variable of Redis")
apt_packages = apt_packages + ["redis-server"]
else:
Log.info(self, "Redis is not installed")
# MariaDB
if pargs.mysql:
Log.debug(self, "Removing apt_packages variable of MySQL")
apt_packages = apt_packages + ['mariadb-server', 'mysql-common',
'mariadb-client']
packages = packages + ['/etc/mysql', '/var/lib/mysql']
if WOAptGet.is_installed(self, 'mariadb-server'):
Log.debug(self, "Add MySQL to apt_packages list")
apt_packages = apt_packages + ['mariadb-server',
'mysql-common',
'mariadb-client']
packages = packages + ['/etc/mysql', '/var/lib/mysql']
else:
Log.info(self, "MariaDB is not installed")
# mysqlclient
if pargs.mysqlclient:
Log.debug(self, "Removing apt_packages variable "
"for MySQL Client")
if WOShellExec.cmd_exec(self, "mysqladmin ping"):
Log.debug(self, "Add MySQL client to apt_packages list")
apt_packages = apt_packages + WOVariables.wo_mysql_client
# fail2ban
if pargs.fail2ban:
if WOAptGet.is_installed(self, 'fail2ban'):
Log.debug(self, "Remove apt_packages variable of Fail2ban")
Log.debug(self, "Add Fail2ban to apt_packages list")
apt_packages = apt_packages + WOVariables.wo_fail2ban
# ClamAV
if pargs.clamav:
Log.debug(self, "Setting apt_packages variable for ClamAV")
if WOAptGet.is_installed(self, 'clamav'):
Log.debug(self, "Add ClamAV to apt_packages list")
apt_packages = apt_packages + WOVariables.wo_clamav
# UFW
if pargs.ufw:
if WOAptGet.is_installed(self, 'ufw'):
Log.debug(self, "Add UFW to apt_packages list")
apt_packages = apt_packages + ["ufw"]
# sendmail
if pargs.sendmail:
Log.debug(self, "Setting apt_packages variable for Sendmail")
if WOAptGet.is_installed(self, 'sendmail'):
Log.debug(self, "Add sendmail to apt_packages list")
apt_packages = apt_packages + ["sendmail"]
# proftpd
if pargs.proftpd:
if WOAptGet.is_installed(self, 'proftpd-basic'):
Log.debug(self, "Purge apt_packages variable for ProFTPd")
Log.debug(self, "Add Proftpd to apt_packages list")
apt_packages = apt_packages + ["proftpd-basic"]
# WP-CLI
if pargs.wpcli:
Log.debug(self, "Purge package variable WPCLI")
if os.path.isfile('/usr/local/bin/wp'):
Log.debug(self, "Purge package variable WPCLI")
packages = packages + ['/usr/local/bin/wp']
# PHPMYADMIN
if pargs.phpmyadmin:
packages = packages + ['{0}22222/htdocs/db/pma'.
format(WOVariables.wo_webroot)]
Log.debug(self, "Purge package variable phpMyAdmin")
if os.path.isdir('{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)):
Log.debug(self, "Removing package of phpMyAdmin ")
packages = packages + ['{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)]
# Composer
if pargs.composer:
Log.debug(self, "Removing package variable of Composer ")
if os.path.isfile('/usr/local/bin/composer'):
Log.debug(self, "Removing package variable of Composer ")
packages = packages + ['/usr/local/bin/composer']
# MySQLTuner
if pargs.mysqltuner:
Log.debug(self, "Removing packages for MySQLTuner ")
packages = packages + ['/usr/bin/mysqltuner']
if os.path.isfile('/usr/bin/mysqltuner'):
Log.debug(self, "Removing packages for MySQLTuner ")
packages = packages + ['/usr/bin/mysqltuner']
# PHPREDISADMIN
if pargs.phpredisadmin:
@@ -871,11 +912,13 @@ class WOStackController(CementBaseController):
packages = packages + ['{0}22222/htdocs/'
'cache/redis'
.format(WOVariables.wo_webroot)]
# Adminer
# ADMINER
if pargs.adminer:
Log.debug(self, "Purge package variable Adminer")
packages = packages + ['{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)]
if os.path.isdir('{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)):
Log.debug(self, "Removing package variable of Adminer ")
packages = packages + ['{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)]
# utils
if pargs.utils:
Log.debug(self, "Purge package variable utils")
@@ -921,8 +964,10 @@ class WOStackController(CementBaseController):
WOService.stop_service(self, 'fail2ban')
if (set(["mariadb-server"]).issubset(set(apt_packages))):
WOMysql.backupAll(self)
WOService.stop_service(self, 'mysql')
if (os.path.isfile('/usr/bin/mysql') and
os.path.isdir('/var/lib/mysql')):
WOMysql.backupAll(self)
WOService.stop_service(self, 'mysql')
# Netdata uninstaller
if (set(['/var/lib/wo/tmp/'
@@ -952,10 +997,10 @@ class WOStackController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOStackController)
handler.register(WOStackStatusController)
handler.register(WOStackMigrateController)
handler.register(WOStackUpgradeController)
app.handler.register(WOStackController)
app.handler.register(WOStackStatusController)
app.handler.register(WOStackMigrateController)
app.handler.register(WOStackUpgradeController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_stack_hook)
app.hook.register('post_argument_parsing', wo_stack_hook)

View File

@@ -1,52 +0,0 @@
import os
import shutil
from cement.core import handler, hook
from cement.core.controller import CementBaseController, expose
from wo.cli.plugins.stack_pref import post_pref, pre_pref
from wo.core.aptget import WOAptGet
from wo.core.download import WODownload
from wo.core.extract import WOExtract
from wo.core.fileutils import WOFileUtils
from wo.core.logging import Log
from wo.core.services import WOService
from wo.core.shellexec import WOShellExec
from wo.core.variables import WOVariables
class WOStackUpgradeController(CementBaseController):
class Meta:
label = 'config'
stacked_on = 'stack'
stacked_type = 'nested'
exit_on_close = True
description = ('Upgrade stack safely')
arguments = [
(['--nginx'],
dict(help='Upgrade all stack', action='store_true')),
(['--php'],
dict(help='Upgrade PHP 7.2 stack', action='store_true')),
(['--php73'],
dict(help='Upgrade PHP 7.3 stack', action='store_true')),
(['--mysql'],
dict(help='Upgrade MySQL stack', action='store_true')),
(['--wpcli'],
dict(help='Upgrade WPCLI', action='store_true')),
(['--redis'],
dict(help='Upgrade Redis', action='store_true')),
(['--netdata'],
dict(help='Upgrade Netdata', action='store_true')),
(['--dashboard'],
dict(help='Upgrade WordOps Dashboard', action='store_true')),
(['--composer'],
dict(help='Upgrade Composer', action='store_true')),
(['--phpmyadmin'],
dict(help='Upgrade phpMyAdmin', action='store_true')),
(['--no-prompt'],
dict(help="Upgrade Packages without any prompt",
action='store_true')),
(['--force'],
dict(help="Force Packages upgrade without any prompt",
action='store_true')),
]

View File

@@ -21,9 +21,9 @@ from wo.core.logging import Log
from wo.core.mysql import WOMysql
from wo.core.services import WOService
from wo.core.shellexec import CommandExecutionError, WOShellExec
from wo.core.sslutils import SSL
from wo.core.template import WOTemplate
from wo.core.variables import WOVariables
from wo.core.sslutils import SSL
def pre_pref(self, apt_packages):
@@ -159,22 +159,22 @@ def post_pref(self, apt_packages, packages, upgrade=False):
["/etc/nginx"],
msg="Adding Nginx into Git")
data = dict(tls13=True)
WOTemplate.render(self,
WOTemplate.deploy(self,
'/etc/nginx/nginx.conf',
'nginx-core.mustache', data)
if not os.path.isfile('{0}/gzip.conf.disabled'.format(ngxcnf)):
data = dict()
WOTemplate.render(self, '{0}/gzip.conf'.format(ngxcnf),
WOTemplate.deploy(self, '{0}/gzip.conf'.format(ngxcnf),
'gzip.mustache', data)
if not os.path.isfile('{0}/brotli.conf'.format(ngxcnf)):
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/brotli.conf.disabled'
.format(ngxcnf),
'brotli.mustache', data)
WOTemplate.render(self, '{0}/tweaks.conf'.format(ngxcnf),
WOTemplate.deploy(self, '{0}/tweaks.conf'.format(ngxcnf),
'tweaks.mustache', data)
# Fix for white screen death with NGINX PLUS
@@ -187,26 +187,26 @@ def post_pref(self, apt_packages, packages, upgrade=False):
try:
data = dict(php="9000", debug="9001",
php7="9070", debug7="9170")
WOTemplate.render(
WOTemplate.deploy(
self, '{0}/upstream.conf'.format(ngxcnf),
'upstream.mustache', data, overwrite=True)
data = dict(phpconf=True if
WOAptGet.is_installed(self, 'php7.2-fpm')
else False)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/stub_status.conf'.format(ngxcnf),
'stub_status.mustache', data)
data = dict()
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/webp.conf'.format(ngxcnf),
'webp.mustache', data, overwrite=False)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/cloudflare.conf'.format(ngxcnf),
'cloudflare.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/map-wp-fastcgi-cache.conf'.format(
ngxcnf),
'map-wp.mustache', data)
@@ -223,83 +223,83 @@ def post_pref(self, apt_packages, packages, upgrade=False):
data = dict()
# Common Configuration
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/locations-wo.conf'
.format(ngxcom),
'locations.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpsubdir.conf'
.format(ngxcom),
'wpsubdir.mustache', data)
data = dict(upstream="php72")
# PHP 7.2 conf
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/php72.conf'
.format(ngxcom),
'php.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/redis-php72.conf'
.format(ngxcom),
'redis.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpcommon-php72.conf'
.format(ngxcom),
'wpcommon.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpfc-php72.conf'
.format(ngxcom),
'wpfc.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpsc-php72.conf'
.format(ngxcom),
'wpsc.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wprocket-php72.conf'
.format(ngxcom),
'wprocket.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpce-php72.conf'
.format(ngxcom),
'wpce.mustache', data)
# PHP 7.3 conf
data = dict(upstream="php73")
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/php73.conf'
.format(ngxcom),
'php.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/redis-php73.conf'
.format(ngxcom),
'redis.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpcommon-php73.conf'
.format(ngxcom),
'wpcommon.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpfc-php73.conf'
.format(ngxcom),
'wpfc.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpsc-php73.conf'
.format(ngxcom),
'wpsc.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wprocket-php73.conf'
.format(ngxcom),
'wprocket.mustache', data)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/wpce-php73.conf'
.format(ngxcom),
'wpce.mustache', data)
@@ -315,15 +315,15 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# Following files should not be overwrited
data = dict(webroot=ngxroot)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/acl.conf'
.format(ngxcom),
'acl.mustache', data, overwrite=False)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/blockips.conf'
.format(ngxcnf),
'blockips.mustache', data, overwrite=False)
WOTemplate.render(self,
WOTemplate.deploy(self,
'{0}/fastcgi.conf'
.format(ngxcnf),
'fastcgi.mustache', data, overwrite=True)
@@ -361,7 +361,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# 22222 port settings
data = dict(webroot=ngxroot)
WOTemplate.render(
WOTemplate.deploy(
self,
'/etc/nginx/sites-available/22222',
'22222.mustache', data, overwrite=True)
@@ -466,7 +466,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
if not os.path.isfile("/opt/cf-update.sh"):
data = dict()
WOTemplate.render(self, '/opt/cf-update.sh',
WOTemplate.deploy(self, '/opt/cf-update.sh',
'cf-update.mustache',
data, overwrite=False)
WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775)
@@ -868,7 +868,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
inno_buffer=wo_ram_innodb,
inno_log_buffer=wo_ram_log_buffer,
innodb_instances=wo_innodb_instance)
WOTemplate.render(
WOTemplate.deploy(
self, '/etc/mysql/my.cnf', 'my.mustache', data)
# replacing default values
Log.debug(self, "Tuning MySQL configuration")
@@ -892,17 +892,17 @@ def post_pref(self, apt_packages, packages, upgrade=False):
if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"):
Log.info(self, "Configuring Fail2Ban")
data = dict()
WOTemplate.render(
WOTemplate.deploy(
self,
'/etc/fail2ban/jail.d/custom.conf',
'fail2ban.mustache',
data, overwrite=False)
WOTemplate.render(
WOTemplate.deploy(
self,
'/etc/fail2ban/filter.d/wo-wordpress.conf',
'fail2ban-wp.mustache',
data, overwrite=False)
WOTemplate.render(
WOTemplate.deploy(
self,
'/etc/fail2ban/filter.d/nginx-forbidden.conf',
'fail2ban-forbidden.mustache',
@@ -950,10 +950,11 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOService.restart_service(self, 'proftpd')
# add rule for proftpd with UFW
if os.path.isdir('/etc/ufw'):
if WOFileUtils.grepcheck(
self, '/etc/ufw/ufw.conf', 'ENABLED=yes'):
try:
WOShellExec.cmd_exec(
self, "ufw allow 21")
self, "ufw limit 21")
WOShellExec.cmd_exec(
self, "ufw allow 49000:50000/tcp")
WOShellExec.cmd_exec(
@@ -975,6 +976,24 @@ def post_pref(self, apt_packages, packages, upgrade=False):
msg="Adding ProFTPd into Git")
WOService.reload_service(self, 'proftpd')
if "ufw" in apt_packages:
# check if ufw is already enabled
if not WOFileUtils.grep(self,
'/etc/ufw/ufw.conf', 'ENABLED=yes'):
Log.wait(self, "Configuring UFW")
# check if ufw script is already created
if not os.path.isfile("/opt/ufw.sh"):
data = dict()
WOTemplate.deploy(self, '/opt/ufw.sh',
'ufw.mustache',
data, overwrite=False)
WOFileUtils.chmod(self, "/opt/ufw.sh", 0o700)
# setup ufw rules
WOShellExec.cmd_exec(self, "bash /opt/ufw.sh")
Log.valide(self, "Configuring UFW")
else:
Log.info(self, "UFW is already installed and enabled")
# Redis configuration
if "redis-server" in apt_packages:
if os.path.isfile("/etc/nginx/conf.d/upstream.conf"):
@@ -1058,7 +1077,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
Log.debug(self, "Setting up freshclam cronjob")
if not os.path.isfile("/opt/freshclam.sh"):
data = dict()
WOTemplate.render(self, '/opt/freshclam.sh',
WOTemplate.deploy(self, '/opt/freshclam.sh',
'freshclam.mustache',
data, overwrite=False)
WOFileUtils.chmod(self, "/opt/freshclam.sh", 0o775)
@@ -1139,28 +1158,29 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# composer install and phpmyadmin update
if any('/var/lib/wo/tmp/composer-install' == x[1]
for x in packages):
Log.info(self, "Installing composer, please wait...")
Log.wait(self, "Installing composer")
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.valide(self, "Installing composer")
if ((os.path.isdir("/var/www/22222/htdocs/db/pma")) and
(not os.path.isfile('/var/www/22222/htdocs/db/'
'pma/composer.lock'))):
Log.info(self, "Updating phpMyAdmin, please wait...")
Log.wait(self, "Updating phpMyAdmin")
WOShellExec.cmd_exec(
self, "/usr/local/bin/composer update "
"--no-plugins --no-scripts "
"-n --no-dev -d "
"/var/www/22222/htdocs/db/pma/ &")
"--no-plugins --no-scripts -n --no-dev -d "
"/var/www/22222/htdocs/db/pma/")
WOFileUtils.chown(
self, '{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot),
'www-data',
'www-data',
recursive=True)
Log.valide(self, "Updating phpMyAdmin")
if not os.path.exists('{0}22222/htdocs/cache/'
'redis/phpRedisAdmin'
.format(WOVariables.wo_webroot)):
@@ -1171,12 +1191,11 @@ def post_pref(self, apt_packages, packages, upgrade=False):
.format(WOVariables.wo_webroot))
if not os.path.isfile('/var/www/22222/htdocs/cache/redis/'
'phpRedisAdmin/composer.lock'):
WOShellExec.cmd_exec(self, "/usr/local/bin/composer "
"create-project --no-plugins "
"--no-scripts -n -s dev "
"erik-dubbelboer/php-redis-admin "
"/var/www/22222/htdocs/cache"
"/redis/phpRedisAdmin &")
WOShellExec.cmd_exec(
self, "/usr/local/bin/composer "
"create-project --no-plugins --no-scripts -n -s dev "
"erik-dubbelboer/php-redis-admin "
"/var/www/22222/htdocs/cache/redis/phpRedisAdmin")
WOFileUtils.chown(self, '{0}22222/htdocs'
.format(WOVariables.wo_webroot),
'www-data',
@@ -1192,11 +1211,11 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# netdata install
if any('/var/lib/wo/tmp/kickstart.sh' == x[1]
for x in packages):
Log.info(self, "Installing Netdata, please wait...")
WOShellExec.cmd_exec(self, "bash /var/lib/wo/tmp/"
"kickstart.sh "
"--dont-wait",
errormsg='', log=False)
Log.wait(self, "Installing Netdata")
WOShellExec.cmd_exec(
self, "bash /var/lib/wo/tmp/kickstart.sh "
"--dont-wait", errormsg='', log=False)
Log.valide(self, "Installing Netdata")
if os.path.isdir('/etc/netdata'):
wo_netdata = "/"
elif os.path.isdir('/opt/netdata'):
@@ -1228,7 +1247,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOMysql.execute(
self, "flush privileges;",
log=False)
except CommandExecutionError as e:
except Exception as e:
Log.debug(self, "{0}".format(e))
Log.info(
self, "fail to setup mysql user for netdata")
@@ -1254,7 +1273,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
"| cut -d ' ' -f 2").read()
if (wo_wan != 'eth0' and wo_wan != ''):
WOFileUtils.searchreplace(self,
"{0}22222/htdocs/index.php"
"{0}22222/htdocs/index.html"
.format(WOVariables.wo_webroot),
"eth0",
"{0}".format(wo_wan))

View File

@@ -14,7 +14,6 @@ class WOStackStatusController(CementBaseController):
label = 'stack_services'
stacked_on = 'stack'
stacked_type = 'embedded'
exit_on_close = True
description = 'Check the stack status'
@expose(help="Start stack services")

View File

@@ -20,7 +20,6 @@ class WOStackUpgradeController(CementBaseController):
label = 'upgrade'
stacked_on = 'stack'
stacked_type = 'nested'
exit_on_close = True
description = ('Upgrade stack safely')
arguments = [
(['--all'],
@@ -149,7 +148,8 @@ class WOStackUpgradeController(CementBaseController):
'Netdata']]
if pargs.dashboard:
if os.path.isfile('/var/www/22222/htdocs/index.php'):
if (os.path.isfile('/var/www/22222/htdocs/index.php') or
os.path.isfile('/var/www/22222/htdocs/index.html')):
packages = packages + \
[["https://github.com/WordOps/wordops-dashboard/"
"releases/download/v{0}/wordops-dashboard.tar.gz"
@@ -234,7 +234,11 @@ class WOStackUpgradeController(CementBaseController):
WOFileUtils.rm(self, '/var/lib/wo/tmp/kickstart.sh')
if pargs.dashboard:
WOFileUtils.rm(self, '/var/www/22222/htdocs/index.php')
if os.path.isfile('/var/www/22222/htdocs/index.php'):
WOFileUtils.rm(self, '/var/www/22222/htdocs/index.php')
if os.path.isfile('/var/www/22222/htdocs/index.html'):
WOFileUtils.rm(
self, '/var/www/22222/htdocs/index.html')
Log.debug(self, "Downloading following: {0}".format(packages))
WODownload.download(self, packages)
@@ -257,20 +261,17 @@ class WOStackUpgradeController(CementBaseController):
Log.valide(self, "Upgrading Netdata")
if pargs.dashboard:
Log.debug(self, "Extracting wo-dashboard.tar.gz "
"to location {0}22222/htdocs/"
.format(WOVariables.wo_webroot))
WOExtract.extract(self, '/var/lib/wo/tmp/'
'wo-dashboard.tar.gz',
'{0}22222/htdocs'
.format(WOVariables.wo_webroot))
WOFileUtils.chown(self, "{0}22222/htdocs"
.format(WOVariables.wo_webroot),
'www-data',
'www-data', recursive=True)
post_pref(
self, [], [["https://github.com/WordOps"
"/wordops-dashboard/"
"releases/download/v{0}/"
"wordops-dashboard.tar.gz"
.format(WOVariables.wo_dashboard),
"/var/lib/wo/tmp/wo-dashboard.tar.gz",
"WordOps Dashboard"]])
if pargs.composer:
Log.wait(self, "Upgrading Composer ")
Log.wait(self, "Upgrading Composer")
WOShellExec.cmd_exec(
self, "php -q /var/lib/wo"
"/tmp/composer-install "
@@ -281,7 +282,7 @@ class WOStackUpgradeController(CementBaseController):
Log.valide(self, "Upgrading Composer ")
if pargs.phpmyadmin:
Log.wait(self, "Upgrading phpMyAdmin ")
Log.wait(self, "Upgrading phpMyAdmin")
WOExtract.extract(self, '/var/lib/wo/tmp/pma.tar.gz',
'/var/lib/wo/tmp/')
shutil.copyfile(('{0}22222/htdocs/db/pma'
@@ -302,6 +303,6 @@ class WOStackUpgradeController(CementBaseController):
.format(WOVariables.wo_webroot),
'www-data',
'www-data', recursive=True)
Log.valide(self, "Upgrading phpMyAdmin ")
Log.valide(self, "Upgrading phpMyAdmin")
Log.info(self, "Successfully updated packages")

View File

@@ -45,8 +45,9 @@ class WOSyncController(CementBaseController):
Log.debug(self, "Config files not found in {0}/ "
.format(wo_site_webroot))
if site.site_type != 'mysql':
Log.debug(self, "Searching wp-config.php in {0}/htdocs/ "
.format(wo_site_webroot))
Log.debug(self,
"Searching wp-config.php in {0}/htdocs/"
.format(wo_site_webroot))
configfiles = glob.glob(
wo_site_webroot + '/htdocs/wp-config.php')
@@ -93,6 +94,6 @@ class WOSyncController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOSyncController)
app.handler.register(WOSyncController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_sync_hook)
app.hook.register('post_argument_parsing', wo_sync_hook)

View File

@@ -78,6 +78,6 @@ class WOUpdateController(CementBaseController):
def load(app):
# register the plugin class.. this only happens if the plugin is enabled
handler.register(WOUpdateController)
app.handler.register(WOUpdateController)
# register a hook (function) to run after arguments are parsed.
hook.register('post_argument_parsing', wo_update_hook)
app.hook.register('post_argument_parsing', wo_update_hook)

View File

@@ -1,82 +1,73 @@
# WordOps nextcloud configuration
add_header X-Robots-Tag none;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location / {
rewrite ^ /index.php$request_uri;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass {{upstream}};
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
location / {
rewrite ^ /index.php$request_uri;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass {{upstream}};
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

View File

@@ -0,0 +1,45 @@
# Use a custom port in the following range : 1024-65536
Port {{sshport}}
#Prefer ed25519 & ECDSA keys rather than 2048 bit RSA
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Allow root access with ssh keys
PermitRootLogin without-password
# Allow ssh access to some users only
AllowUsers root ubuntu debian {{user}}
# allow ssh key Authentication
PubkeyAuthentication yes
# ssh keys path in ~/.ssh/authorized_keys
AuthorizedKeysFile %h/.ssh/authorized_keys
# No password or empty passwords Authentication
PasswordAuthentication {{allowpass}}
PermitEmptyPasswords no
# No challenge response Authentication
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
#PrintMotd no
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Host keys the client accepts - order here is honored by OpenSSH
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa,ecdsa-sha2-nistp521-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256
# use strong ciphers
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com

View File

@@ -0,0 +1,61 @@
#!/bin/bash
wo_ufw_setup() {
# get custom ssh port
if [ -f /etc/ssh/sshd_config ]; then
CURRENT_SSH_PORT=$(grep "Port" /etc/ssh/sshd_config | awk -F " " '{print $2}')
fi
# define firewall rules
if ! grep -q "LOGLEVEL=low" /etc/ufw/ufw.conf; then
ufw logging low
fi
if ! grep -q 'DEFAULT_OUTPUT_POLICY="ACCEPT"' /etc/default/ufw; then
ufw default allow outgoing
fi
if ! grep -q 'DEFAULT_INPUT_POLICY="DROP"' /etc/default/ufw; then
ufw default deny incoming
fi
if ! grep -q "\-\-dport 22 -j" /etc/ufw/user.rules; then
# default ssh port
ufw limit 22
fi
# custom ssh port
if [ "$CURRENT_SSH_PORT" != "22" ]; then
if ! grep -q "\-\-dport $CURRENT_SSH_PORT -j" /etc/ufw/user.rules; then
ufw limit "$CURRENT_SSH_PORT"
fi
fi
# nginx
if ! grep -q "\-\-dport 80 -j" /etc/ufw/user.rules; then
# http
ufw allow http
fi
if ! grep -q "\-\-dport 443 -j" /etc/ufw/user.rules; then
# https
ufw allow https
fi
# ntp
if ! grep -q "\-\-dport 123 -j" /etc/ufw/user.rules; then
ufw allow 123
fi
if ! grep -q "\-\-dport 22222 -j" /etc/ufw/user.rules; then
# wordops backend
ufw limit 22222
fi
# enable ufw
if [ -n "$CURRENT_SSH_PORT" ]; then
ufw --force enable
fi
# remove ufw from syslog
if [ -f /etc/rsyslog.d/20-ufw.conf ]; then
sed -i 's/\#\& stop/\& stop/' /etc/rsyslog.d/20-ufw.conf
service rsyslog restart
fi
}
wo_ufw_setup

135
wo/core/acme.py Normal file
View File

@@ -0,0 +1,135 @@
import os
import requests
from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit
from wo.core.logging import Log
from wo.core.shellexec import WOShellExec
from wo.core.variables import WOVariables
class WOAcme:
"""Acme.sh utilities for WordOps"""
def setupletsencrypt(self, acme_domains, acmedata):
"""issue SSL certificates with acme.sh"""
all_domains = '\' -d \''.join(acme_domains)
wo_acme_dns = acmedata['acme_dns']
keylenght = "{0}".format(self.app.config.get('letsencrypt',
'keylength'))
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
"'/etc/letsencrypt/config'")
if acmedata['dns'] is True:
acme_mode = "--dns {0}".format(wo_acme_dns)
validation_mode = "DNS mode with {0}".format(wo_acme_dns)
if acmedata['dnsalias'] is True:
acme_mode = acme_mode + \
" --challenge-alias {0}".format(acmedata['acme_alias'])
else:
acme_mode = "-w /var/www/html"
validation_mode = "Webroot challenge"
Log.debug(self, "Validation : Webroot mode")
Log.info(self, "Validation mode : {0}".format(validation_mode))
Log.wait(self, "Issuing SSL cert with acme.sh")
if not WOShellExec.cmd_exec(
self, "{0} ".format(wo_acme_exec) +
"--issue -d '{0}' {1} -k {2} -f"
.format(all_domains, acme_mode, keylenght)):
Log.failed(self, "Issuing SSL cert with acme.sh")
if acmedata['dns'] is True:
Log.warn(
self, "Please make sure your properly "
"set your DNS API credentials for acme.sh")
else:
Log.error(
self, "Your domain is properly configured "
"but acme.sh was unable to issue certificate.\n"
"You can find more informations in "
"/var/log/wo/wordops.log", False)
return False
else:
Log.valide(self, "Issuing SSL cert with acme.sh")
return True
def deploycert(self, wo_domain_name):
wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home "
"'/etc/letsencrypt/config'")
if not os.path.isfile('/etc/letsencrypt/renewal/{0}_ecc/fullchain.cer'
.format(wo_domain_name)):
Log.error(self, 'Certificate not found. Deployment canceled')
Log.debug(self, "Cert deployment for domain: {0}"
.format(wo_domain_name))
try:
Log.wait(self, "Deploying SSL cert")
if WOShellExec.cmd_exec(
self, "mkdir -p {0}/{1} && {2} --install-cert -d {1} --ecc "
"--cert-file {0}/{1}/cert.pem --key-file {0}/{1}/key.pem "
"--fullchain-file {0}/{1}/fullchain.pem "
"--ca-file {0}/{1}/ca.pem --reloadcmd \"nginx -t && "
"service nginx restart\" "
.format(WOVariables.wo_ssl_live,
wo_domain_name, wo_acme_exec)):
Log.valide(self, "Deploying SSL cert")
else:
Log.failed(self, "Deploying SSL cert")
Log.error(self, "Unable to deploy certificate")
if os.path.isdir('/var/www/{0}/conf/nginx'
.format(wo_domain_name)):
sslconf = open("/var/www/{0}/conf/nginx/ssl.conf"
.format(wo_domain_name),
encoding='utf-8', mode='w')
sslconf.write(
"listen 443 ssl http2;\n"
"listen [::]:443 ssl http2;\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()
if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf',
'/etc/letsencrypt'):
Log.info(self, "Securing WordOps backend with current cert"
.format(wo_domain_name))
sslconf = open("/var/www/22222/conf/nginx/ssl.conf",
encoding='utf-8', mode='w')
sslconf.write("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()
WOGit.add(self, ["/etc/letsencrypt"],
msg="Adding letsencrypt folder")
except IOError as e:
Log.debug(self, str(e))
Log.debug(self, "Error occured while generating "
"ssl.conf")
def check_dns(self, acme_domains):
"""Check if a list of domains point to the server IP"""
server_ip = requests.get('http://v4.wordops.eu/').text
for domain in acme_domains:
domain_ip = requests.get('http://v4.wordops.eu/dns/{0}/'
.format(domain)).text
if(not domain_ip == server_ip):
Log.warn(
self, "{0} is not pointing to your server IP"
.format(domain))
Log.error(
self, "You have to add the "
"proper DNS record", False)
return False
break
else:
Log.debug(self, "DNS record are properly set")
return True

View File

@@ -1,7 +1,8 @@
"""WordOps generic database creation module"""
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
from wo.core.variables import WOVariables
# db_path = self.app.config.get('site', 'db_path')

View File

@@ -9,7 +9,8 @@ Render Templates
class WOTemplate():
def render(self, fileconf, template, data, overwrite=True):
def deploy(self, fileconf, template, data, overwrite=True):
"""Deploy template with render()"""
data = dict(data)
if (not os.path.isfile('{0}.custom'
.format(fileconf))):

View File

@@ -11,13 +11,13 @@ class WOVariables():
"""Intialization of core variables"""
# WordOps version
wo_version = "3.9.8.12"
wo_version = "3.9.9"
# WordOps packages versions
wo_wp_cli = "2.3.0"
wo_adminer = "4.7.2"
wo_phpmyadmin = "4.9.0.1"
wo_phpmyadmin = "4.9.1"
wo_extplorer = "2.1.13"
wo_dashboard = "1.1"
wo_dashboard = "1.2"
# Get WPCLI path
wo_wpcli_path = '/usr/local/bin/wp'
@@ -111,15 +111,6 @@ class WOVariables():
wo_nginx = ["nginx-custom", "nginx-wo"]
wo_nginx_key = '188C9FB063F0247A'
# PHP repo and packages
if wo_distro == 'ubuntu':
wo_php_repo = "ppa:ondrej/php"
else:
wo_php_repo = (
"deb https://packages.sury.org/php/ {codename} main"
.format(codename=wo_platform_codename))
wo_php_key = 'AC0E47584A7A714D'
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",
@@ -133,18 +124,6 @@ class WOVariables():
wo_php_extra = ["php-memcached", "php-imagick",
"graphviz", "php-xdebug", "php-msgpack", "php-redis"]
# MySQL repo and packages
if wo_distro == 'ubuntu':
wo_mysql_repo = ("deb [arch=amd64,ppc64el] "
"http://sfo1.mirrors.digitalocean.com/mariadb/repo/"
"10.3/ubuntu {codename} main"
.format(codename=wo_platform_codename))
else:
wo_mysql_repo = ("deb [arch=amd64,ppc64el] "
"http://sfo1.mirrors.digitalocean.com/mariadb/repo/"
"10.3/debian {codename} main"
.format(codename=wo_platform_codename))
if not wo_distro == 'raspbian':
if (not wo_platform_codename == 'jessie'):
wo_mysql = ["mariadb-server", "percona-toolkit",
@@ -166,11 +145,25 @@ class WOVariables():
# Redis repo details
if wo_distro == 'ubuntu':
wo_php_repo = "ppa:ondrej/php"
wo_redis_repo = ("ppa:chris-lea/redis-server")
wo_goaccess_repo = ("ppa:alex-p/goaccess")
wo_mysql_repo = ("deb [arch=amd64,ppc64el] "
"http://sfo1.mirrors.digitalocean.com/mariadb/repo/"
"10.3/ubuntu {codename} main"
.format(codename=wo_platform_codename))
else:
wo_php_repo = (
"deb https://packages.sury.org/php/ {codename} main"
.format(codename=wo_platform_codename))
wo_php_key = 'AC0E47584A7A714D'
wo_redis_repo = ("deb https://packages.sury.org/php/ {codename} all"
.format(codename=wo_platform_codename))
wo_mysql_repo = ("deb [arch=amd64,ppc64el] "
"http://sfo1.mirrors.digitalocean.com/mariadb/repo/"
"10.3/debian {codename} main"
.format(codename=wo_platform_codename))
wo_redis = ['redis-server']