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 sudo: required
dist: bionic dist: xenial
language: bash language: bash
@@ -21,10 +21,11 @@ before_install:
before_script: before_script:
- sudo rm -rf /etc/mysql - sudo rm -rf /etc/mysql
- sudo bash -c 'echo example.com > /etc/hostname' - sudo bash -c 'echo example.com > /etc/hostname'
- sudo apt-get -qq purge mysql* graphviz* redis*
- sudo apt-get -qq autoremove --purge
- unset LANG - 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: after_script:
- sudo cat /etc/nginx/nginx.conf | ccze -A - sudo cat /etc/nginx/nginx.conf | ccze -A
@@ -37,11 +38,7 @@ script:
- lsb_release -a - lsb_release -a
- sudo bash -c 'echo -e "[user]\n\tname = abc\n\temail = root@localhost.com" > /home/travis/.gitconfig' - sudo bash -c 'echo -e "[user]\n\tname = abc\n\temail = root@localhost.com" > /home/travis/.gitconfig'
- sudo echo "Travis Banch = $TRAVIS_BRANCH" - 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 install --travis -b "$TRAVIS_BRANCH"
- sudo time bash tests/travis.sh - sudo time bash tests/travis.sh
- sudo wo update --travis - sudo wo update --travis
- sudo wo stack status - 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.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 ### v3.9.8.12 - 2019-09-20
#### Changed #### Changed

View File

@@ -47,7 +47,7 @@ _wo_complete()
"secure") "secure")
COMPREPLY=( $(compgen \ COMPREPLY=( $(compgen \
-W "--auth --port --ip" \ -W "--auth --port --ip --ssh --sshport" \
-- $cur) ) -- $cur) )
;; ;;
@@ -74,17 +74,17 @@ _wo_complete()
# HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE # HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE
"install" | "purge" | "remove" ) "install" | "purge" | "remove" )
COMPREPLY=( $(compgen \ 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) ) -- $cur) )
;; ;;
"upgrade" ) "upgrade" )
COMPREPLY=( $(compgen \ 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) ) -- $cur) )
;; ;;
"start" | "stop" | "reload" | "restart" | "status") "start" | "stop" | "reload" | "restart" | "status")
COMPREPLY=( $(compgen \ COMPREPLY=( $(compgen \
-W "--nginx --php --php73 --mysql --redis --fail2ban --netdata -proftpd" \ -W "--nginx --php --php73 --mysql --redis --fail2ban --ufw --netdata -proftpd" \
-- $cur) ) -- $cur) )
;; ;;
"list") "list")
@@ -267,11 +267,11 @@ _wo_complete()
-- $cur) ) -- $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 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 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 elif [[ "${COMP_WORDS[1]}" == "debug" ]]; then
retlist="--start --nginx --php --php73 --fpm --fpm7 --mysql -i --interactive -stop --import-slow-log --import-slow-log-interval= -" retlist="--start --nginx --php --php73 --fpm --fpm7 --mysql -i --interactive -stop --import-slow-log --import-slow-log-interval= -"
if [[ $prev == '--mysql' ]]; then if [[ $prev == '--mysql' ]]; then

View File

@@ -11,9 +11,9 @@ wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php |
.TP .TP
wo site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ] wo site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ]
.TP .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 .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 .TP
wo site delete example.com [--db | --files | --all | --no-prompt | --force/-f ] wo site delete example.com [--db | --files | --all | --no-prompt | --force/-f ]
.TP .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() { wo_backup_ee() {
if [ -d /etc/nginx ]; then local BACKUP_EE=""
local EE_NGINX="/etc/nginx" [ -d /etc/nginx ] && { BACKUP_EE="$BACKUP_EE /etc/nginx"; }
else [ -d /etc/letsencrypt ] && { BACKUP_EE="$BACKUP_EE /etc/letsencrypt"; }
local EE_NGINX="" /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"
fi return 0
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"
} }
wo_backup_wo() { 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 return 0
} }
wo_clean_ee() { 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 return 0
} }
@@ -856,13 +819,13 @@ else
fi fi
_run wo_install_dep "Installing wo dependencies" _run wo_install_dep "Installing wo dependencies"
_run wo_timesync _run wo_timesync
if [ "$ufw" = "y" ]; then #if [ "$ufw" = "y" ]; then
_run wo_ufw_setup "Configuring UFW" # _run wo_ufw_setup "Configuring UFW"
fi #fi
# skip steps if travis # skip steps if travis
if [ -z "$wo_travis" ]; then if [ -z "$wo_travis" ]; then
_run wo_dist_upgrade
_run wo_download "Downloading WordOps" _run wo_download "Downloading WordOps"
_run wo_dist_upgrade
wo_git_config wo_git_config
_run wo_install "Installing WordOps" _run wo_install "Installing WordOps"
else else
@@ -908,7 +871,7 @@ else
wo_lib_echo "WordOps (wo) installed successfully" wo_lib_echo "WordOps (wo) installed successfully"
echo echo
wo_lib_echo "To enable bash-completion, just use the command:" wo_lib_echo "To enable bash-completion, just use the command:"
wo_lib_echo_info "bash" wo_lib_echo_info "bash -l"
echo echo
wo_lib_echo "To install WordOps recommended stacks, you can use the command:" wo_lib_echo "To install WordOps recommended stacks, you can use the command:"
wo_lib_echo_info "wo stack install" 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] [nosetests]
verbosity=3 verbosity=2
debug=0 debug=0
detailed-errors=1 detailed-errors=1
with-coverage=1 with-coverage=1
cover-package=wo cover-package=wo
cover-inclusive=1
cover-erase=1 cover-erase=1
cover-html=1 cover-html=1
cover-html-dir=coverage_report/ 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/') os.makedirs('/var/lib/wo/')
setup(name='wo', setup(name='wo',
version='3.9.8.12', version='3.9.9',
description=long_description, description=long_description,
long_description=long_description, long_description=long_description,
classifiers=[], classifiers=[],

View File

@@ -27,12 +27,6 @@ class CliTestCaseStack(test.WOTestCase):
self.app.run() self.app.run()
self.app.close() 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): def test_wo_cli_stack_services_status_all(self):
self.app = get_test_app(argv=['stack', 'status']) self.app = get_test_app(argv=['stack', 'status'])
self.app.setup() self.app.setup()

View File

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

View File

@@ -9,6 +9,10 @@ CRED="${CSI}1;31m"
CGREEN="${CSI}1;32m" CGREEN="${CSI}1;32m"
CEND="${CSI}0m" 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() { exit_script() {
curl --progress-bar --upload-file /var/log/wo/wordops.log https://transfer.vtbox.net/"$(basename wordops.log)" && echo "" curl --progress-bar --upload-file /var/log/wo/wordops.log https://transfer.vtbox.net/"$(basename wordops.log)" && echo ""
exit 1 exit 1
@@ -17,7 +21,7 @@ exit_script() {
echo -e "${CGREEN}#############################################${CEND}" echo -e "${CGREEN}#############################################${CEND}"
echo -e ' stack install ' echo -e ' stack install '
echo -e "${CGREEN}#############################################${CEND}" 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 for stack in $stack_list; do
echo -ne " Installing $stack [..]\r" echo -ne " Installing $stack [..]\r"
if { if {
@@ -150,9 +154,46 @@ for stack in $stack_upgrade; do
fi fi
done 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 "${CGREEN}#############################################${CEND}"
echo -e ' various informations ' echo -e ' various informations '
echo -e "${CGREEN}#############################################${CEND}" echo -e "${CGREEN}#############################################${CEND}"
wp --allow-root --info wp --allow-root --info
wo site info wp1.com wo site info wp.net
wo stack purge --all --force
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. # in this file in the same way as WOBaseController.
from cement.core import handler from cement.core import handler
from wo.cli.controllers.base import WOBaseController from wo.cli.controllers.base import WOBaseController
def load(app): def load(app):
handler.register(WOBaseController) app.handler.register(WOBaseController)

View File

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

View File

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

View File

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

View File

@@ -90,6 +90,6 @@ class WOCleanController(CementBaseController):
def load(app): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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)) " disabled".format(self.app.pargs.site_name))
@expose(hide=True) @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""" """Handle Ctrl+c hevent for -i option of debug"""
self.start = False self.start = False
if self.app.pargs.nginx: if self.app.pargs.nginx:
@@ -847,6 +847,6 @@ class WODebugController(CementBaseController):
def load(app): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # register the plugin class.. this only happens if the plugin is enabled
handler.register(WOLogController) app.handler.register(WOLogController)
handler.register(WOLogShowController) app.handler.register(WOLogShowController)
handler.register(WOLogResetController) app.handler.register(WOLogResetController)
handler.register(WOLogGzipController) app.handler.register(WOLogGzipController)
handler.register(WOLogMailController) app.handler.register(WOLogMailController)
# register a hook (function) to run after arguments are parsed. # 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): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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 getpass
import random import os
import string
from cement.core import handler, hook from cement.core import handler, hook
from cement.core.controller import CementBaseController, expose from cement.core.controller import CementBaseController, expose
from wo.core.git import WOGit from wo.core.git import WOGit
from wo.core.logging import Log from wo.core.logging import Log
from wo.core.random import RANDOM
from wo.core.services import WOService from wo.core.services import WOService
from wo.core.shellexec import WOShellExec from wo.core.shellexec import WOShellExec
from wo.core.template import WOTemplate
from wo.core.variables import WOVariables from wo.core.variables import WOVariables
from wo.core.random import RANDOM
def wo_secure_hook(app): def wo_secure_hook(app):
@@ -33,6 +33,13 @@ class WOSecureController(CementBaseController):
dict(help='set backend port', action='store_true')), dict(help='set backend port', action='store_true')),
(['--ip'], (['--ip'],
dict(help='set backend whitelisted ip', action='store_true')), 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'], (['user_input'],
dict(help='user input', nargs='?', default=None)), dict(help='user input', nargs='?', default=None)),
(['user_pass'], (['user_pass'],
@@ -48,10 +55,16 @@ class WOSecureController(CementBaseController):
self.secure_port() self.secure_port()
if pargs.ip: if pargs.ip:
self.secure_ip() self.secure_ip()
if pargs.sshport:
self.secure_ssh_port()
if pargs.ssh:
self.secure_ssh()
@expose(hide=True) @expose(hide=True)
def secure_auth(self): def secure_auth(self):
"""This function secures authentication""" """This function secures authentication"""
WOGit.add(self, ["/etc/nginx"],
msg="Add Nginx to into Git")
pargs = self.app.pargs pargs = self.app.pargs
passwd = RANDOM.long(self) passwd = RANDOM.long(self)
if not pargs.user_input: if not pargs.user_input:
@@ -83,17 +96,20 @@ class WOSecureController(CementBaseController):
@expose(hide=True) @expose(hide=True)
def secure_port(self): def secure_port(self):
"""This function Secures port""" """This function Secures port"""
WOGit.add(self, ["/etc/nginx"],
msg="Add Nginx to into Git")
pargs = self.app.pargs pargs = self.app.pargs
if pargs.user_input: 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 ") Log.info(self, "Please enter a valid port number ")
pargs.user_input = input("WordOps " pargs.user_input = input("WordOps "
"admin port [22222]:") "admin port [22222]:")
if not pargs.user_input: if not pargs.user_input:
port = input("WordOps admin port [22222]:") port = input("WordOps admin port [22222]:")
if port == "": if port == "":
pargs.user_input = 22222 port = 22222
while (not port.isdigit()) and (port != "") and (not port < 65556): while (not port.isdigit()) and (port != "") and (not port < 65536):
Log.info(self, "Please Enter valid port number :") Log.info(self, "Please Enter valid port number :")
port = input("WordOps admin port [22222]:") port = input("WordOps admin port [22222]:")
pargs.user_input = port pargs.user_input = port
@@ -112,6 +128,8 @@ class WOSecureController(CementBaseController):
@expose(hide=True) @expose(hide=True)
def secure_ip(self): def secure_ip(self):
"""IP whitelisting""" """IP whitelisting"""
WOGit.add(self, ["/etc/nginx"],
msg="Add Nginx to into Git")
pargs = self.app.pargs pargs = self.app.pargs
if not pargs.user_input: if not pargs.user_input:
ip = input("Enter the comma separated IP addresses " 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") 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): def load(app):
handler.register(WOSecureController) app.handler.register(WOSecureController)
hook.register('post_argument_parsing', wo_secure_hook) app.hook.register('post_argument_parsing', wo_secure_hook)

View File

@@ -1,9 +1,7 @@
# """WordOps site controller."""
import glob import glob
import json import json
import os import os
import subprocess import subprocess
from subprocess import Popen
from cement.core import handler, hook from cement.core import handler, hook
from cement.core.controller import CementBaseController, expose 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.site_functions import *
from wo.cli.plugins.sitedb import (addNewSite, deleteSiteInfo, getAllsites, from wo.cli.plugins.sitedb import (addNewSite, deleteSiteInfo, getAllsites,
getSiteInfo, updateSiteInfo) getSiteInfo, updateSiteInfo)
from wo.core.acme import WOAcme
from wo.core.domainvalidate import WODomain from wo.core.domainvalidate import WODomain
from wo.core.fileutils import WOFileUtils from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit from wo.core.git import WOGit
@@ -58,7 +57,8 @@ class WOSiteController(CementBaseController):
pargs.site_name = pargs.site_name.strip() pargs.site_name = pargs.site_name.strip()
# validate domain name # 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 # check if site exists
if not check_domain_exists(self, wo_domain): if not check_domain_exists(self, wo_domain):
@@ -136,8 +136,10 @@ class WOSiteController(CementBaseController):
Log.debug(self, str(e)) Log.debug(self, str(e))
Log.error(self, 'could not input site name') Log.error(self, 'could not input site name')
pargs.site_name = pargs.site_name.strip() pargs.site_name = pargs.site_name.strip()
(wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) (wo_domain,
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self, 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_name = ''
wo_db_user = '' wo_db_user = ''
wo_db_pass = '' wo_db_pass = ''
@@ -188,7 +190,8 @@ class WOSiteController(CementBaseController):
def log(self): def log(self):
pargs = self.app.pargs pargs = self.app.pargs
pargs.site_name = pargs.site_name.strip() 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 wo_site_webroot = getSiteInfo(self, wo_domain).site_path
if not check_domain_exists(self, wo_domain): if not check_domain_exists(self, wo_domain):
@@ -210,7 +213,8 @@ class WOSiteController(CementBaseController):
Log.error(self, 'could not input site name') Log.error(self, 'could not input site name')
# TODO Write code for wo site edit command here # TODO Write code for wo site edit command here
pargs.site_name = pargs.site_name.strip() 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): if not check_domain_exists(self, wo_domain):
Log.error(self, "site {0} does not exist".format(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') Log.error(self, 'Unable to read input, please try again')
pargs.site_name = pargs.site_name.strip() 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): if not check_domain_exists(self, wo_domain):
Log.error(self, "site {0} does not exist".format(wo_domain)) Log.error(self, "site {0} does not exist".format(wo_domain))
@@ -261,7 +266,6 @@ class WOSiteEditController(CementBaseController):
label = 'edit' label = 'edit'
stacked_on = 'site' stacked_on = 'site'
stacked_type = 'nested' stacked_type = 'nested'
exit_on_close = True
description = ('Edit Nginx configuration of site') description = ('Edit Nginx configuration of site')
arguments = [ arguments = [
(['site_name'], (['site_name'],
@@ -282,7 +286,8 @@ class WOSiteEditController(CementBaseController):
Log.error(self, 'Unable to read input, Please try again') Log.error(self, 'Unable to read input, Please try again')
pargs.site_name = pargs.site_name.strip() 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): if not check_domain_exists(self, wo_domain):
Log.error(self, "site {0} does not exist".format(wo_domain)) Log.error(self, "site {0} does not exist".format(wo_domain))
@@ -316,7 +321,6 @@ class WOSiteCreateController(CementBaseController):
label = 'create' label = 'create'
stacked_on = 'site' stacked_on = 'site'
stacked_type = 'nested' stacked_type = 'nested'
exit_on_close = True
description = ('this commands set up configuration and installs ' description = ('this commands set up configuration and installs '
'required files as options are provided') 'required files as options are provided')
arguments = [ arguments = [
@@ -368,6 +372,9 @@ class WOSiteCreateController(CementBaseController):
dict(help="choose dns provider api for letsencrypt", dict(help="choose dns provider api for letsencrypt",
action='store' or 'store_const', action='store' or 'store_const',
const='dns_cf', nargs='?')), const='dns_cf', nargs='?')),
(['--dnsalias'],
dict(help="set domain used for acme dns alias validation",
action='store', nargs='?')),
(['--hsts'], (['--hsts'],
dict(help="enable HSTS for site secured with letsencrypt", dict(help="enable HSTS for site secured with letsencrypt",
action='store_true')), action='store_true')),
@@ -424,7 +431,8 @@ class WOSiteCreateController(CementBaseController):
Log.error(self, "Unable to input site name, Please try again!") Log.error(self, "Unable to input site name, Please try again!")
pargs.site_name = pargs.site_name.strip() 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(): if not wo_domain.strip():
Log.error(self, "Invalid domain name, " Log.error(self, "Invalid domain name, "
"Provide valid domain name") "Provide valid domain name")
@@ -717,31 +725,60 @@ class WOSiteCreateController(CementBaseController):
"`tail /var/log/wo/wordops.log` and please try again") "`tail /var/log/wo/wordops.log` and please try again")
if pargs.letsencrypt: if pargs.letsencrypt:
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self, acme_domains = []
wo_domain) (wo_domain_type,
wo_root_domain) = WODomain.getdomainlevel(self,
wo_domain)
data['letsencrypt'] = True data['letsencrypt'] = True
letsencrypt = True letsencrypt = True
if data['letsencrypt'] is 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: if pargs.dns:
wo_acme_dns = pargs.dns Log.debug(self, "DNS validation enabled")
wo_dns = True acmedata['dns'] = True
else: if not pargs.dns == 'dns_cf':
wo_acme_dns = '' Log.debug(self, "DNS API : {0}".format(pargs.dns))
wo_dns = False 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": if pargs.letsencrypt == "subdomain":
wo_subdomain = True Log.warn(
wo_wildcard = False self, 'Flag --letsencrypt=subdomain is '
'deprecated and not required anymore.')
acme_subdomain = True
acme_wildcard = False
elif pargs.letsencrypt == "wildcard": elif pargs.letsencrypt == "wildcard":
wo_wildcard = True acme_wildcard = True
wo_subdomain = False acme_subdomain = False
acmedata['dns'] = True
else: else:
wo_wildcard = False if ((wo_domain_type == 'subdomain')):
wo_subdomain = False Log.debug(self, "Domain type = {0}"
Log.debug(self, "Domain type = {0}" .format(wo_domain_type))
.format(wo_domain_type)) acme_subdomain = True
if ((wo_domain_type == 'subdomain') and else:
(not pargs.letsencrypt == 'wildcard')): acme_subdomain = False
wo_subdomain = True 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 # check if a wildcard cert for the root domain exist
Log.debug(self, "checkWildcardExist on *.{0}" Log.debug(self, "checkWildcardExist on *.{0}"
.format(wo_root_domain)) .format(wo_root_domain))
@@ -757,14 +794,25 @@ class WOSiteCreateController(CementBaseController):
# copy the cert from the root domain # copy the cert from the root domain
copyWildcardCert(self, wo_domain, wo_root_domain) copyWildcardCert(self, wo_domain, wo_root_domain)
else: 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}" Log.debug(self, "Setup Cert with acme.sh for {0}"
.format(wo_domain)) .format(wo_domain))
setupLetsEncrypt(self, wo_domain, wo_subdomain, if WOAcme.setupletsencrypt(
wo_wildcard, wo_dns, wo_acme_dns) self, acme_domains, acmedata):
WOAcme.deploycert(self, wo_domain)
else: else:
setupLetsEncrypt(self, wo_domain, wo_subdomain, if not acmedata['dns'] is True:
wo_wildcard, wo_dns, wo_acme_dns) if not WOAcme.check_dns(self, acme_domains):
httpsRedirect(self, wo_domain, True, wo_wildcard) 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: if pargs.hsts:
SSL.setuphsts(self, wo_domain) SSL.setuphsts(self, wo_domain)
@@ -792,7 +840,6 @@ class WOSiteUpdateController(CementBaseController):
label = 'update' label = 'update'
stacked_on = 'site' stacked_on = 'site'
stacked_type = 'nested' stacked_type = 'nested'
exit_on_close = True
description = ('This command updates websites configuration to ' description = ('This command updates websites configuration to '
'another as per the options are provided') 'another as per the options are provided')
arguments = [ arguments = [
@@ -842,6 +889,9 @@ class WOSiteUpdateController(CementBaseController):
dict(help="choose dns provider api for letsencrypt", dict(help="choose dns provider api for letsencrypt",
action='store' or 'store_const', action='store' or 'store_const',
const='dns_cf', nargs='?')), const='dns_cf', nargs='?')),
(['--dnsalias'],
dict(help="set domain used for acme dns alias validation",
action='store', nargs='?')),
(['--hsts'], (['--hsts'],
dict(help="configure hsts for the site", dict(help="configure hsts for the site",
action='store' or 'store_const', action='store' or 'store_const',
@@ -931,7 +981,8 @@ class WOSiteUpdateController(CementBaseController):
Log.error(self, 'Unable to input site name, Please try again!') Log.error(self, 'Unable to input site name, Please try again!')
pargs.site_name = pargs.site_name.strip() 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 wo_site_webroot = WOVariables.wo_webroot + wo_domain
check_site = getSiteInfo(self, wo_domain) check_site = getSiteInfo(self, wo_domain)
@@ -1129,44 +1180,48 @@ class WOSiteUpdateController(CementBaseController):
pargs.php73 = False pargs.php73 = False
if pargs.letsencrypt: if pargs.letsencrypt:
(wo_domain_type, wo_root_domain) = WODomain.getdomainlevel(self, acme_domains = []
wo_domain) 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': if pargs.letsencrypt == 'on':
data['letsencrypt'] = True data['letsencrypt'] = True
letsencrypt = True letsencrypt = True
if ((wo_domain_type == 'subdomain') and if (wo_domain_type == 'subdomain'):
(not pargs.letsencrypt == 'wildcard')): acme_subdomain = True
wo_subdomain = True
else: else:
wo_subdomain = False acme_subdomain = False
wo_wildcard = False acme_wildcard = False
elif pargs.letsencrypt == 'subdomain': elif pargs.letsencrypt == 'subdomain':
data['letsencrypt'] = True data['letsencrypt'] = True
letsencrypt = True letsencrypt = True
wo_subdomain = True acme_subdomain = True
wo_wildcard = False acme_wildcard = False
elif pargs.letsencrypt == 'wildcard': elif pargs.letsencrypt == 'wildcard':
data['letsencrypt'] = True data['letsencrypt'] = True
letsencrypt = True letsencrypt = True
wo_wildcard = True acme_wildcard = True
wo_subdomain = False acme_subdomain = False
acmedata['dns'] = True
elif pargs.letsencrypt == 'off': elif pargs.letsencrypt == 'off':
data['letsencrypt'] = False data['letsencrypt'] = False
letsencrypt = False letsencrypt = False
wo_subdomain = False acme_subdomain = False
wo_wildcard = False acme_wildcard = False
elif pargs.letsencrypt == 'clean': elif pargs.letsencrypt == 'clean':
data['letsencrypt'] = False data['letsencrypt'] = False
letsencrypt = False letsencrypt = False
wo_subdomain = False acme_subdomain = False
wo_wildcard = False acme_wildcard = False
elif pargs.letsencrypt == 'purge': elif pargs.letsencrypt == 'purge':
data['letsencrypt'] = False data['letsencrypt'] = False
letsencrypt = False letsencrypt = False
wo_subdomain = False acme_subdomain = False
wo_wildcard = False acme_wildcard = False
if not wo_subdomain: if not (acme_subdomain is True):
if letsencrypt is check_ssl: if letsencrypt is check_ssl:
if letsencrypt is False: if letsencrypt is False:
Log.error(self, "SSl is not configured for given " Log.error(self, "SSl is not configured for given "
@@ -1271,13 +1326,12 @@ class WOSiteUpdateController(CementBaseController):
data['php73'] = False data['php73'] = False
php73 = False php73 = False
if pargs.letsencrypt == "on" or pargs.php73 == "on": if pargs.php73 == "on":
if pargs.php73 == "on": data['php73'] = True
data['php73'] = True php73 = True
php73 = True else:
else: data['php73'] = False
data['php73'] = False php73 = False
php73 = False
if pargs.wpredis and data['currcachetype'] != 'wpredis': if pargs.wpredis and data['currcachetype'] != 'wpredis':
data['wpredis'] = True data['wpredis'] = True
@@ -1348,20 +1402,38 @@ class WOSiteUpdateController(CementBaseController):
if pargs.letsencrypt: if pargs.letsencrypt:
if data['letsencrypt'] is True: if data['letsencrypt'] is True:
# DNS API configuration
if pargs.dns: if pargs.dns:
wo_acme_dns = pargs.dns Log.debug(self, "DNS validation enabled")
wo_dns = True 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: else:
wo_acme_dns = '' Log.info(self, "Certificate type : domain")
wo_dns = False acme_domains = acme_domains + ['{0}'.format(wo_domain),
if wo_subdomain: 'www.{0}'.format(wo_domain)]
if acme_subdomain:
# check if a wildcard cert for the root domain exist # check if a wildcard cert for the root domain exist
Log.debug(self, "checkWildcardExist on *.{0}" Log.debug(self, "checkWildcardExist on *.{0}"
.format(wo_root_domain)) .format(wo_root_domain))
iswildcard = SSL.checkwildcardexist(self, wo_root_domain) iswildcard = SSL.checkwildcardexist(self, wo_root_domain)
Log.debug(self, "iswildcard = {0}".format(iswildcard)) Log.debug(self, "iswildcard = {0}".format(iswildcard))
if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"): if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"):
if wo_subdomain: if acme_subdomain:
if iswildcard: if iswildcard:
Log.info(self, "Using existing Wildcard SSL " Log.info(self, "Using existing Wildcard SSL "
"certificate from {0} to secure {1}" "certificate from {0} to secure {1}"
@@ -1372,13 +1444,31 @@ class WOSiteUpdateController(CementBaseController):
# copy the cert from the root domain # copy the cert from the root domain
copyWildcardCert(self, wo_domain, wo_root_domain) copyWildcardCert(self, wo_domain, wo_root_domain)
else: 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}" Log.debug(self, "Setup Cert with acme.sh for {0}"
.format(wo_domain)) .format(wo_domain))
setupLetsEncrypt(self, wo_domain, wo_subdomain, if WOAcme.setupletsencrypt(
wo_wildcard, wo_dns, wo_acme_dns) self, acme_domains, acmedata):
WOAcme.deploycert(self, wo_domain)
else:
Log.error(self, "Unable to issue certificate")
else: else:
setupLetsEncrypt(self, wo_domain, wo_subdomain, # check DNS records before issuing cert
wo_wildcard, wo_dns, wo_acme_dns) 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: else:
WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled" WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled"
.format(wo_site_webroot), .format(wo_site_webroot),
@@ -1390,7 +1480,7 @@ class WOSiteUpdateController(CementBaseController):
'/etc/nginx/conf.d/force-ssl-{0}.conf' '/etc/nginx/conf.d/force-ssl-{0}.conf'
.format(wo_domain)) .format(wo_domain))
httpsRedirect(self, wo_domain, True, wo_wildcard) httpsRedirect(self, wo_domain, True, acme_wildcard)
SSL.siteurlhttps(self, wo_domain) SSL.siteurlhttps(self, wo_domain)
if not WOService.reload_service(self, 'nginx'): if not WOService.reload_service(self, 'nginx'):
@@ -1399,7 +1489,7 @@ class WOSiteUpdateController(CementBaseController):
Log.info(self, "Congratulations! Successfully " Log.info(self, "Congratulations! Successfully "
"Configured SSL for Site " "Configured SSL for Site "
" https://{0}".format(wo_domain)) " https://{0}".format(wo_domain))
if wo_subdomain and iswildcard: if acme_subdomain and iswildcard:
if (SSL.getexpirationdays(self, wo_root_domain) > 0): if (SSL.getexpirationdays(self, wo_root_domain) > 0):
Log.info( Log.info(
self, "Your cert will expire within " + self, "Your cert will expire within " +
@@ -1826,7 +1916,6 @@ class WOSiteDeleteController(CementBaseController):
label = 'delete' label = 'delete'
stacked_on = 'site' stacked_on = 'site'
stacked_type = 'nested' stacked_type = 'nested'
exit_on_close = True
description = 'delete an existing website' description = 'delete an existing website'
arguments = [ arguments = [
(['site_name'], (['site_name'],
@@ -1966,7 +2055,6 @@ class WOSiteListController(CementBaseController):
label = 'list' label = 'list'
stacked_on = 'site' stacked_on = 'site'
stacked_type = 'nested' stacked_type = 'nested'
exit_on_close = True
description = 'List websites' description = 'List websites'
arguments = [ arguments = [
(['--enabled'], (['--enabled'],
@@ -1997,11 +2085,11 @@ class WOSiteListController(CementBaseController):
def load(app): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # register the plugin class.. this only happens if the plugin is enabled
handler.register(WOSiteController) app.handler.register(WOSiteController)
handler.register(WOSiteCreateController) app.handler.register(WOSiteCreateController)
handler.register(WOSiteUpdateController) app.handler.register(WOSiteUpdateController)
handler.register(WOSiteDeleteController) app.handler.register(WOSiteDeleteController)
handler.register(WOSiteListController) app.handler.register(WOSiteListController)
handler.register(WOSiteEditController) app.handler.register(WOSiteEditController)
# register a hook (function) to run after arguments are parsed. # 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.sitedb import getSiteInfo
from wo.cli.plugins.stack import WOStackController from wo.cli.plugins.stack import WOStackController
from wo.cli.plugins.stack_pref import post_pref from wo.cli.plugins.stack_pref import post_pref
from wo.core.acme import WOAcme
from wo.core.aptget import WOAptGet from wo.core.aptget import WOAptGet
from wo.core.fileutils import WOFileUtils from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit from wo.core.git import WOGit
@@ -38,8 +39,8 @@ def pre_run_checks(self):
Log.wait(self, "Running pre-update checks") Log.wait(self, "Running pre-update checks")
try: try:
Log.debug(self, "checking NGINX configuration ...") Log.debug(self, "checking NGINX configuration ...")
FNULL = open('/dev/null', 'w') fnull = open('/dev/null', 'w')
subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=FNULL, subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=fnull,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
except CalledProcessError as e: except CalledProcessError as e:
Log.failed(self, "Running pre-update checks") Log.failed(self, "Running pre-update checks")
@@ -1348,129 +1349,6 @@ def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='',
# setup letsencrypt for domain + www.domain # 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 # copy wildcard certificate to a subdomain
@@ -1616,14 +1494,16 @@ def httpsRedirect(self, wo_domain_name, redirect=True, wildcard=False):
def archivedCertificateHandle(self, domain): def archivedCertificateHandle(self, domain):
Log.warn(self, "You already have an existing certificate " Log.warn(
"for the domain requested.\n" self, "You already have an existing certificate "
"(ref: {0}/" "for the domain requested.\n"
"{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) + "(ref: {0}/"
"\nPlease select an option from below?" "{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) +
"\n\t1: Reinstall existing certificate" "\nPlease select an option from below?"
"\n\t2: Renew & replace the certificate (limit ~5 per 7 days)" "\n\t1: Reinstall existing certificate"
"") "\n\t2: Issue a new certificate to replace "
"the current one (limit ~5 per 7 days)"
"")
check_prompt = input( check_prompt = input(
"\nType the appropriate number [1-2] or any other key to cancel: ") "\nType the appropriate number [1-2] or any other key to cancel: ")
if not os.path.isfile("{0}/{1}/fullchain.pem" if not os.path.isfile("{0}/{1}/fullchain.pem"
@@ -1634,20 +1514,7 @@ def archivedCertificateHandle(self, domain):
if check_prompt == "1": if check_prompt == "1":
Log.info(self, "Reinstalling SSL cert with acme.sh") Log.info(self, "Reinstalling SSL cert with acme.sh")
ssl = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " ssl = WOAcme.deploycert(self, domain)
"/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))
if ssl: if ssl:
try: try:
@@ -1727,7 +1594,7 @@ def setuprocketchat(self):
if ((not WOVariables.wo_platform_codename == 'bionic') and if ((not WOVariables.wo_platform_codename == 'bionic') and
(not WOVariables.wo_platform_codename == 'xenial')): (not WOVariables.wo_platform_codename == 'xenial')):
Log.info(self, "Rocket.chat is only available on Ubuntu 16.04 " Log.info(self, "Rocket.chat is only available on Ubuntu 16.04 "
"& 18.04 LTS") "& 18.04 LTS")
return False return False
else: else:
if not WOAptGet.is_installed(self, 'snapd'): if not WOAptGet.is_installed(self, 'snapd'):

View File

@@ -1,16 +1,6 @@
"""Stack Plugin for WordOps""" """Stack Plugin for WordOps"""
import codecs
import configparser
import os 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 import handler, hook
from cement.core.controller import CementBaseController, expose 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_pref import post_pref, pre_pref
from wo.cli.plugins.stack_services import WOStackStatusController from wo.cli.plugins.stack_services import WOStackStatusController
from wo.cli.plugins.stack_upgrade import WOStackUpgradeController from wo.cli.plugins.stack_upgrade import WOStackUpgradeController
from wo.core.apt_repo import WORepo
from wo.core.aptget import WOAptGet from wo.core.aptget import WOAptGet
from wo.core.cron import WOCron
from wo.core.download import WODownload from wo.core.download import WODownload
from wo.core.extract import WOExtract
from wo.core.fileutils import WOFileUtils from wo.core.fileutils import WOFileUtils
from wo.core.git import WOGit
from wo.core.logging import Log from wo.core.logging import Log
from wo.core.mysql import WOMysql from wo.core.mysql import WOMysql
from wo.core.services import WOService from wo.core.services import WOService
from wo.core.shellexec import CommandExecutionError, WOShellExec from wo.core.shellexec import WOShellExec
from wo.core.template import WOTemplate
from wo.core.variables import WOVariables from wo.core.variables import WOVariables
@@ -88,6 +73,8 @@ class WOStackController(CementBaseController):
dict(help='Install Fail2ban stack', action='store_true')), dict(help='Install Fail2ban stack', action='store_true')),
(['--clamav'], (['--clamav'],
dict(help='Install ClamAV stack', action='store_true')), dict(help='Install ClamAV stack', action='store_true')),
(['--ufw'],
dict(help='Install UFW stack', action='store_true')),
(['--sendmail'], (['--sendmail'],
dict(help='Install Sendmail stack', action='store_true')), dict(help='Install Sendmail stack', action='store_true')),
(['--utils'], (['--utils'],
@@ -129,6 +116,7 @@ class WOStackController(CementBaseController):
(not pargs.adminer) and (not pargs.utils) and (not pargs.adminer) and (not pargs.utils) and
(not pargs.redis) and (not pargs.proftpd) and (not pargs.redis) and (not pargs.proftpd) and
(not pargs.extplorer) and (not pargs.clamav) and (not pargs.extplorer) and (not pargs.clamav) and
(not pargs.ufw) and
(not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.phpredisadmin) and (not pargs.sendmail) and
(not pargs.php73)): (not pargs.php73)):
pargs.web = True pargs.web = True
@@ -164,6 +152,7 @@ class WOStackController(CementBaseController):
if pargs.security: if pargs.security:
pargs.fail2ban = True pargs.fail2ban = True
pargs.clamav = True pargs.clamav = True
pargs.ufw = True
# Nginx # Nginx
if pargs.nginx: if pargs.nginx:
@@ -270,6 +259,13 @@ class WOStackController(CementBaseController):
Log.debug(self, "ClamAV already installed") Log.debug(self, "ClamAV already installed")
Log.info(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 # sendmail
if pargs.sendmail: if pargs.sendmail:
Log.debug(self, "Setting apt_packages variable for 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)) Log.debug(self, "Downloading following: {0}".format(packages))
WODownload.download(self, packages) WODownload.download(self, packages)
Log.debug(self, "Calling post_pref") Log.debug(self, "Calling post_pref")
Log.wait(self, "Configuring packages")
post_pref(self, [], packages) post_pref(self, [], packages)
Log.valide(self, "Configuring packages")
if disp_msg: if disp_msg:
if (self.msg): if (self.msg):
@@ -518,6 +516,7 @@ class WOStackController(CementBaseController):
(not pargs.adminer) and (not pargs.utils) and (not pargs.adminer) and (not pargs.utils) and
(not pargs.redis) and (not pargs.proftpd) and (not pargs.redis) and (not pargs.proftpd) and
(not pargs.extplorer) and (not pargs.clamav) and (not pargs.extplorer) and (not pargs.clamav) and
(not pargs.ufw) and
(not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.phpredisadmin) and (not pargs.sendmail) and
(not pargs.php73)): (not pargs.php73)):
pargs.web = True pargs.web = True
@@ -551,6 +550,7 @@ class WOStackController(CementBaseController):
if pargs.security: if pargs.security:
pargs.fail2ban = True pargs.fail2ban = True
pargs.clamav = True pargs.clamav = True
pargs.ufw = True
# NGINX # NGINX
if pargs.nginx: if pargs.nginx:
@@ -580,14 +580,17 @@ class WOStackController(CementBaseController):
# REDIS # REDIS
if pargs.redis: if pargs.redis:
Log.debug(self, "Remove apt_packages variable of Redis") if WOAptGet.is_installed(self, 'redis-server'):
apt_packages = apt_packages + ["redis-server"] Log.debug(self, "Remove apt_packages variable of Redis")
apt_packages = apt_packages + ["redis-server"]
# MariaDB # MariaDB
if pargs.mysql: if pargs.mysql:
Log.debug(self, "Removing apt_packages variable of MySQL") if WOAptGet.is_installed(self, 'mariadb-server'):
apt_packages = apt_packages + ['mariadb-server', 'mysql-common', Log.debug(self, "Removing apt_packages variable of MySQL")
'mariadb-client'] apt_packages = apt_packages + ['mariadb-server',
'mysql-common',
'mariadb-client']
# mysqlclient # mysqlclient
if pargs.mysqlclient: if pargs.mysqlclient:
@@ -620,6 +623,12 @@ class WOStackController(CementBaseController):
Log.debug(self, "Remove apt_packages variable for ProFTPd") Log.debug(self, "Remove apt_packages variable for ProFTPd")
apt_packages = apt_packages + ["proftpd-basic"] 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 # WPCLI
if pargs.wpcli: if pargs.wpcli:
Log.debug(self, "Removing package variable of WPCLI ") Log.debug(self, "Removing package variable of WPCLI ")
@@ -628,18 +637,22 @@ class WOStackController(CementBaseController):
# PHPMYADMIN # PHPMYADMIN
if pargs.phpmyadmin: if pargs.phpmyadmin:
Log.debug(self, "Removing package of phpMyAdmin ") if os.path.isdir('{0}22222/htdocs/db/pma'
packages = packages + ['{0}22222/htdocs/db/pma' .format(WOVariables.wo_webroot)):
.format(WOVariables.wo_webroot)] Log.debug(self, "Removing package of phpMyAdmin ")
packages = packages + ['{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)]
# Composer # Composer
if pargs.composer: if pargs.composer:
Log.debug(self, "Removing package of Composer ") Log.debug(self, "Removing package of Composer ")
if os.path.isfile('/usr/local/bin/composer'): if os.path.isfile('/usr/local/bin/composer'):
packages = packages + ['/usr/local/bin/composer'] packages = packages + ['/usr/local/bin/composer']
# MySQLTuner
if pargs.mysqltuner: if pargs.mysqltuner:
Log.debug(self, "Removing packages for MySQLTuner ") if os.path.isfile('/usr/bin/mysqltuner'):
packages = packages + ['/usr/bin/mysqltuner'] Log.debug(self, "Removing packages for MySQLTuner ")
packages = packages + ['/usr/bin/mysqltuner']
# PHPREDISADMIN # PHPREDISADMIN
if pargs.phpredisadmin: if pargs.phpredisadmin:
@@ -651,9 +664,11 @@ class WOStackController(CementBaseController):
.format(WOVariables.wo_webroot)] .format(WOVariables.wo_webroot)]
# ADMINER # ADMINER
if pargs.adminer: if pargs.adminer:
Log.debug(self, "Removing package variable of Adminer ") if os.path.isdir('{0}22222/htdocs/db/adminer'
packages = packages + ['{0}22222/htdocs/db/adminer' .format(WOVariables.wo_webroot)):
.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: if pargs.utils:
Log.debug(self, "Removing package variable of utils ") Log.debug(self, "Removing package variable of utils ")
packages = packages + ['{0}22222/htdocs/php/webgrind/' packages = packages + ['{0}22222/htdocs/php/webgrind/'
@@ -673,11 +688,17 @@ class WOStackController(CementBaseController):
packages = packages + ['/var/lib/wo/tmp/kickstart.sh'] packages = packages + ['/var/lib/wo/tmp/kickstart.sh']
if pargs.dashboard: if pargs.dashboard:
Log.debug(self, "Removing Wo-Dashboard") if (os.path.isfile('{0}22222/htdocs/index.php'
packages = packages + ['{0}22222/htdocs/assets' .format(WOVariables.wo_webroot)) or
.format(WOVariables.wo_webroot), os.path.isfile('{0}22222/htdocs/index.html'
'{0}22222/htdocs/index.php' .format(WOVariables.wo_webroot))):
.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 (packages) or (apt_packages):
if (not pargs.force): if (not pargs.force):
@@ -689,10 +710,10 @@ class WOStackController(CementBaseController):
if start_remove != "Y" and start_remove != "y": if start_remove != "Y" and start_remove != "y":
Log.error(self, "Not starting stack removal") 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') WOService.stop_service(self, 'nginx')
if (set(["mariadb-server"]).issubset(set(apt_packages))): if 'mariadb-server' in apt_packages:
WOMysql.backupAll(self) WOMysql.backupAll(self)
WOService.stop_service(self, 'mysql') WOService.stop_service(self, 'mysql')
@@ -739,6 +760,7 @@ class WOStackController(CementBaseController):
(not pargs.adminer) and (not pargs.utils) and (not pargs.adminer) and (not pargs.utils) and
(not pargs.redis) and (not pargs.proftpd) and (not pargs.redis) and (not pargs.proftpd) and
(not pargs.extplorer) and (not pargs.clamav) and (not pargs.extplorer) and (not pargs.clamav) and
(not pargs.ufw) and
(not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.phpredisadmin) and (not pargs.sendmail) and
(not pargs.php73)): (not pargs.php73)):
pargs.web = True pargs.web = True
@@ -771,16 +793,19 @@ class WOStackController(CementBaseController):
if pargs.security: if pargs.security:
pargs.fail2ban = True pargs.fail2ban = True
pargs.clamav = True pargs.clamav = True
pargs.ufw = True
# NGINX # NGINX
if pargs.nginx: if pargs.nginx:
if WOAptGet.is_installed(self, 'nginx-custom'): 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 apt_packages = apt_packages + WOVariables.wo_nginx
else:
Log.info(self, "Nginx is not installed")
# PHP # PHP
if pargs.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 WOAptGet.is_installed(self, 'php7.2-fpm'):
if not (WOAptGet.is_installed(self, 'php7.3-fpm')): if not (WOAptGet.is_installed(self, 'php7.3-fpm')):
apt_packages = apt_packages + WOVariables.wo_php + \ apt_packages = apt_packages + WOVariables.wo_php + \
@@ -800,68 +825,84 @@ class WOStackController(CementBaseController):
# REDIS # REDIS
if pargs.redis: if pargs.redis:
Log.debug(self, "Remove apt_packages variable of Redis") if WOAptGet.is_installed(self, 'redis-server'):
apt_packages = apt_packages + ["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 # MariaDB
if pargs.mysql: if pargs.mysql:
Log.debug(self, "Removing apt_packages variable of MySQL") if WOAptGet.is_installed(self, 'mariadb-server'):
apt_packages = apt_packages + ['mariadb-server', 'mysql-common', Log.debug(self, "Add MySQL to apt_packages list")
'mariadb-client'] apt_packages = apt_packages + ['mariadb-server',
packages = packages + ['/etc/mysql', '/var/lib/mysql'] 'mysql-common',
'mariadb-client']
packages = packages + ['/etc/mysql', '/var/lib/mysql']
else:
Log.info(self, "MariaDB is not installed")
# mysqlclient # mysqlclient
if pargs.mysqlclient: if pargs.mysqlclient:
Log.debug(self, "Removing apt_packages variable "
"for MySQL Client")
if WOShellExec.cmd_exec(self, "mysqladmin ping"): 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 apt_packages = apt_packages + WOVariables.wo_mysql_client
# fail2ban # fail2ban
if pargs.fail2ban: if pargs.fail2ban:
if WOAptGet.is_installed(self, '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 apt_packages = apt_packages + WOVariables.wo_fail2ban
# ClamAV # ClamAV
if pargs.clamav: if pargs.clamav:
Log.debug(self, "Setting apt_packages variable for ClamAV")
if WOAptGet.is_installed(self, 'clamav'): if WOAptGet.is_installed(self, 'clamav'):
Log.debug(self, "Add ClamAV to apt_packages list")
apt_packages = apt_packages + WOVariables.wo_clamav 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 # sendmail
if pargs.sendmail: if pargs.sendmail:
Log.debug(self, "Setting apt_packages variable for Sendmail")
if WOAptGet.is_installed(self, 'sendmail'): if WOAptGet.is_installed(self, 'sendmail'):
Log.debug(self, "Add sendmail to apt_packages list")
apt_packages = apt_packages + ["sendmail"] apt_packages = apt_packages + ["sendmail"]
# proftpd # proftpd
if pargs.proftpd: if pargs.proftpd:
if WOAptGet.is_installed(self, 'proftpd-basic'): 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"] apt_packages = apt_packages + ["proftpd-basic"]
# WP-CLI # WP-CLI
if pargs.wpcli: if pargs.wpcli:
Log.debug(self, "Purge package variable WPCLI")
if os.path.isfile('/usr/local/bin/wp'): if os.path.isfile('/usr/local/bin/wp'):
Log.debug(self, "Purge package variable WPCLI")
packages = packages + ['/usr/local/bin/wp'] packages = packages + ['/usr/local/bin/wp']
# PHPMYADMIN # PHPMYADMIN
if pargs.phpmyadmin: if pargs.phpmyadmin:
packages = packages + ['{0}22222/htdocs/db/pma'. if os.path.isdir('{0}22222/htdocs/db/pma'
format(WOVariables.wo_webroot)] .format(WOVariables.wo_webroot)):
Log.debug(self, "Purge package variable phpMyAdmin") Log.debug(self, "Removing package of phpMyAdmin ")
packages = packages + ['{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot)]
# Composer # Composer
if pargs.composer: if pargs.composer:
Log.debug(self, "Removing package variable of Composer ")
if os.path.isfile('/usr/local/bin/composer'): if os.path.isfile('/usr/local/bin/composer'):
Log.debug(self, "Removing package variable of Composer ")
packages = packages + ['/usr/local/bin/composer'] packages = packages + ['/usr/local/bin/composer']
# MySQLTuner
if pargs.mysqltuner: if pargs.mysqltuner:
Log.debug(self, "Removing packages for MySQLTuner ") if os.path.isfile('/usr/bin/mysqltuner'):
packages = packages + ['/usr/bin/mysqltuner'] Log.debug(self, "Removing packages for MySQLTuner ")
packages = packages + ['/usr/bin/mysqltuner']
# PHPREDISADMIN # PHPREDISADMIN
if pargs.phpredisadmin: if pargs.phpredisadmin:
@@ -871,11 +912,13 @@ class WOStackController(CementBaseController):
packages = packages + ['{0}22222/htdocs/' packages = packages + ['{0}22222/htdocs/'
'cache/redis' 'cache/redis'
.format(WOVariables.wo_webroot)] .format(WOVariables.wo_webroot)]
# Adminer # ADMINER
if pargs.adminer: if pargs.adminer:
Log.debug(self, "Purge package variable Adminer") if os.path.isdir('{0}22222/htdocs/db/adminer'
packages = packages + ['{0}22222/htdocs/db/adminer' .format(WOVariables.wo_webroot)):
.format(WOVariables.wo_webroot)] Log.debug(self, "Removing package variable of Adminer ")
packages = packages + ['{0}22222/htdocs/db/adminer'
.format(WOVariables.wo_webroot)]
# utils # utils
if pargs.utils: if pargs.utils:
Log.debug(self, "Purge package variable utils") Log.debug(self, "Purge package variable utils")
@@ -921,8 +964,10 @@ class WOStackController(CementBaseController):
WOService.stop_service(self, 'fail2ban') WOService.stop_service(self, 'fail2ban')
if (set(["mariadb-server"]).issubset(set(apt_packages))): if (set(["mariadb-server"]).issubset(set(apt_packages))):
WOMysql.backupAll(self) if (os.path.isfile('/usr/bin/mysql') and
WOService.stop_service(self, 'mysql') os.path.isdir('/var/lib/mysql')):
WOMysql.backupAll(self)
WOService.stop_service(self, 'mysql')
# Netdata uninstaller # Netdata uninstaller
if (set(['/var/lib/wo/tmp/' if (set(['/var/lib/wo/tmp/'
@@ -952,10 +997,10 @@ class WOStackController(CementBaseController):
def load(app): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # register the plugin class.. this only happens if the plugin is enabled
handler.register(WOStackController) app.handler.register(WOStackController)
handler.register(WOStackStatusController) app.handler.register(WOStackStatusController)
handler.register(WOStackMigrateController) app.handler.register(WOStackMigrateController)
handler.register(WOStackUpgradeController) app.handler.register(WOStackUpgradeController)
# register a hook (function) to run after arguments are parsed. # 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.mysql import WOMysql
from wo.core.services import WOService from wo.core.services import WOService
from wo.core.shellexec import CommandExecutionError, WOShellExec from wo.core.shellexec import CommandExecutionError, WOShellExec
from wo.core.sslutils import SSL
from wo.core.template import WOTemplate from wo.core.template import WOTemplate
from wo.core.variables import WOVariables from wo.core.variables import WOVariables
from wo.core.sslutils import SSL
def pre_pref(self, apt_packages): def pre_pref(self, apt_packages):
@@ -159,22 +159,22 @@ def post_pref(self, apt_packages, packages, upgrade=False):
["/etc/nginx"], ["/etc/nginx"],
msg="Adding Nginx into Git") msg="Adding Nginx into Git")
data = dict(tls13=True) data = dict(tls13=True)
WOTemplate.render(self, WOTemplate.deploy(self,
'/etc/nginx/nginx.conf', '/etc/nginx/nginx.conf',
'nginx-core.mustache', data) 'nginx-core.mustache', data)
if not os.path.isfile('{0}/gzip.conf.disabled'.format(ngxcnf)): if not os.path.isfile('{0}/gzip.conf.disabled'.format(ngxcnf)):
data = dict() data = dict()
WOTemplate.render(self, '{0}/gzip.conf'.format(ngxcnf), WOTemplate.deploy(self, '{0}/gzip.conf'.format(ngxcnf),
'gzip.mustache', data) 'gzip.mustache', data)
if not os.path.isfile('{0}/brotli.conf'.format(ngxcnf)): if not os.path.isfile('{0}/brotli.conf'.format(ngxcnf)):
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/brotli.conf.disabled' '{0}/brotli.conf.disabled'
.format(ngxcnf), .format(ngxcnf),
'brotli.mustache', data) 'brotli.mustache', data)
WOTemplate.render(self, '{0}/tweaks.conf'.format(ngxcnf), WOTemplate.deploy(self, '{0}/tweaks.conf'.format(ngxcnf),
'tweaks.mustache', data) 'tweaks.mustache', data)
# Fix for white screen death with NGINX PLUS # Fix for white screen death with NGINX PLUS
@@ -187,26 +187,26 @@ def post_pref(self, apt_packages, packages, upgrade=False):
try: try:
data = dict(php="9000", debug="9001", data = dict(php="9000", debug="9001",
php7="9070", debug7="9170") php7="9070", debug7="9170")
WOTemplate.render( WOTemplate.deploy(
self, '{0}/upstream.conf'.format(ngxcnf), self, '{0}/upstream.conf'.format(ngxcnf),
'upstream.mustache', data, overwrite=True) 'upstream.mustache', data, overwrite=True)
data = dict(phpconf=True if data = dict(phpconf=True if
WOAptGet.is_installed(self, 'php7.2-fpm') WOAptGet.is_installed(self, 'php7.2-fpm')
else False) else False)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/stub_status.conf'.format(ngxcnf), '{0}/stub_status.conf'.format(ngxcnf),
'stub_status.mustache', data) 'stub_status.mustache', data)
data = dict() data = dict()
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/webp.conf'.format(ngxcnf), '{0}/webp.conf'.format(ngxcnf),
'webp.mustache', data, overwrite=False) 'webp.mustache', data, overwrite=False)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/cloudflare.conf'.format(ngxcnf), '{0}/cloudflare.conf'.format(ngxcnf),
'cloudflare.mustache', data) 'cloudflare.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/map-wp-fastcgi-cache.conf'.format( '{0}/map-wp-fastcgi-cache.conf'.format(
ngxcnf), ngxcnf),
'map-wp.mustache', data) 'map-wp.mustache', data)
@@ -223,83 +223,83 @@ def post_pref(self, apt_packages, packages, upgrade=False):
data = dict() data = dict()
# Common Configuration # Common Configuration
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/locations-wo.conf' '{0}/locations-wo.conf'
.format(ngxcom), .format(ngxcom),
'locations.mustache', data) 'locations.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpsubdir.conf' '{0}/wpsubdir.conf'
.format(ngxcom), .format(ngxcom),
'wpsubdir.mustache', data) 'wpsubdir.mustache', data)
data = dict(upstream="php72") data = dict(upstream="php72")
# PHP 7.2 conf # PHP 7.2 conf
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/php72.conf' '{0}/php72.conf'
.format(ngxcom), .format(ngxcom),
'php.mustache', data) 'php.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/redis-php72.conf' '{0}/redis-php72.conf'
.format(ngxcom), .format(ngxcom),
'redis.mustache', data) 'redis.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpcommon-php72.conf' '{0}/wpcommon-php72.conf'
.format(ngxcom), .format(ngxcom),
'wpcommon.mustache', data) 'wpcommon.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpfc-php72.conf' '{0}/wpfc-php72.conf'
.format(ngxcom), .format(ngxcom),
'wpfc.mustache', data) 'wpfc.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpsc-php72.conf' '{0}/wpsc-php72.conf'
.format(ngxcom), .format(ngxcom),
'wpsc.mustache', data) 'wpsc.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wprocket-php72.conf' '{0}/wprocket-php72.conf'
.format(ngxcom), .format(ngxcom),
'wprocket.mustache', data) 'wprocket.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpce-php72.conf' '{0}/wpce-php72.conf'
.format(ngxcom), .format(ngxcom),
'wpce.mustache', data) 'wpce.mustache', data)
# PHP 7.3 conf # PHP 7.3 conf
data = dict(upstream="php73") data = dict(upstream="php73")
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/php73.conf' '{0}/php73.conf'
.format(ngxcom), .format(ngxcom),
'php.mustache', data) 'php.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/redis-php73.conf' '{0}/redis-php73.conf'
.format(ngxcom), .format(ngxcom),
'redis.mustache', data) 'redis.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpcommon-php73.conf' '{0}/wpcommon-php73.conf'
.format(ngxcom), .format(ngxcom),
'wpcommon.mustache', data) 'wpcommon.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpfc-php73.conf' '{0}/wpfc-php73.conf'
.format(ngxcom), .format(ngxcom),
'wpfc.mustache', data) 'wpfc.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpsc-php73.conf' '{0}/wpsc-php73.conf'
.format(ngxcom), .format(ngxcom),
'wpsc.mustache', data) 'wpsc.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wprocket-php73.conf' '{0}/wprocket-php73.conf'
.format(ngxcom), .format(ngxcom),
'wprocket.mustache', data) 'wprocket.mustache', data)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/wpce-php73.conf' '{0}/wpce-php73.conf'
.format(ngxcom), .format(ngxcom),
'wpce.mustache', data) 'wpce.mustache', data)
@@ -315,15 +315,15 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# Following files should not be overwrited # Following files should not be overwrited
data = dict(webroot=ngxroot) data = dict(webroot=ngxroot)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/acl.conf' '{0}/acl.conf'
.format(ngxcom), .format(ngxcom),
'acl.mustache', data, overwrite=False) 'acl.mustache', data, overwrite=False)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/blockips.conf' '{0}/blockips.conf'
.format(ngxcnf), .format(ngxcnf),
'blockips.mustache', data, overwrite=False) 'blockips.mustache', data, overwrite=False)
WOTemplate.render(self, WOTemplate.deploy(self,
'{0}/fastcgi.conf' '{0}/fastcgi.conf'
.format(ngxcnf), .format(ngxcnf),
'fastcgi.mustache', data, overwrite=True) 'fastcgi.mustache', data, overwrite=True)
@@ -361,7 +361,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# 22222 port settings # 22222 port settings
data = dict(webroot=ngxroot) data = dict(webroot=ngxroot)
WOTemplate.render( WOTemplate.deploy(
self, self,
'/etc/nginx/sites-available/22222', '/etc/nginx/sites-available/22222',
'22222.mustache', data, overwrite=True) '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"): if not os.path.isfile("/opt/cf-update.sh"):
data = dict() data = dict()
WOTemplate.render(self, '/opt/cf-update.sh', WOTemplate.deploy(self, '/opt/cf-update.sh',
'cf-update.mustache', 'cf-update.mustache',
data, overwrite=False) data, overwrite=False)
WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775) 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_buffer=wo_ram_innodb,
inno_log_buffer=wo_ram_log_buffer, inno_log_buffer=wo_ram_log_buffer,
innodb_instances=wo_innodb_instance) innodb_instances=wo_innodb_instance)
WOTemplate.render( WOTemplate.deploy(
self, '/etc/mysql/my.cnf', 'my.mustache', data) self, '/etc/mysql/my.cnf', 'my.mustache', data)
# replacing default values # replacing default values
Log.debug(self, "Tuning MySQL configuration") 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"): if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"):
Log.info(self, "Configuring Fail2Ban") Log.info(self, "Configuring Fail2Ban")
data = dict() data = dict()
WOTemplate.render( WOTemplate.deploy(
self, self,
'/etc/fail2ban/jail.d/custom.conf', '/etc/fail2ban/jail.d/custom.conf',
'fail2ban.mustache', 'fail2ban.mustache',
data, overwrite=False) data, overwrite=False)
WOTemplate.render( WOTemplate.deploy(
self, self,
'/etc/fail2ban/filter.d/wo-wordpress.conf', '/etc/fail2ban/filter.d/wo-wordpress.conf',
'fail2ban-wp.mustache', 'fail2ban-wp.mustache',
data, overwrite=False) data, overwrite=False)
WOTemplate.render( WOTemplate.deploy(
self, self,
'/etc/fail2ban/filter.d/nginx-forbidden.conf', '/etc/fail2ban/filter.d/nginx-forbidden.conf',
'fail2ban-forbidden.mustache', 'fail2ban-forbidden.mustache',
@@ -950,10 +950,11 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOService.restart_service(self, 'proftpd') WOService.restart_service(self, 'proftpd')
# add rule for proftpd with UFW # add rule for proftpd with UFW
if os.path.isdir('/etc/ufw'): if WOFileUtils.grepcheck(
self, '/etc/ufw/ufw.conf', 'ENABLED=yes'):
try: try:
WOShellExec.cmd_exec( WOShellExec.cmd_exec(
self, "ufw allow 21") self, "ufw limit 21")
WOShellExec.cmd_exec( WOShellExec.cmd_exec(
self, "ufw allow 49000:50000/tcp") self, "ufw allow 49000:50000/tcp")
WOShellExec.cmd_exec( WOShellExec.cmd_exec(
@@ -975,6 +976,24 @@ def post_pref(self, apt_packages, packages, upgrade=False):
msg="Adding ProFTPd into Git") msg="Adding ProFTPd into Git")
WOService.reload_service(self, 'proftpd') 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 # Redis configuration
if "redis-server" in apt_packages: if "redis-server" in apt_packages:
if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): 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") Log.debug(self, "Setting up freshclam cronjob")
if not os.path.isfile("/opt/freshclam.sh"): if not os.path.isfile("/opt/freshclam.sh"):
data = dict() data = dict()
WOTemplate.render(self, '/opt/freshclam.sh', WOTemplate.deploy(self, '/opt/freshclam.sh',
'freshclam.mustache', 'freshclam.mustache',
data, overwrite=False) data, overwrite=False)
WOFileUtils.chmod(self, "/opt/freshclam.sh", 0o775) 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 # composer install and phpmyadmin update
if any('/var/lib/wo/tmp/composer-install' == x[1] if any('/var/lib/wo/tmp/composer-install' == x[1]
for x in packages): 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" WOShellExec.cmd_exec(self, "php -q /var/lib/wo"
"/tmp/composer-install " "/tmp/composer-install "
"--install-dir=/var/lib/wo/tmp/") "--install-dir=/var/lib/wo/tmp/")
shutil.copyfile('/var/lib/wo/tmp/composer.phar', shutil.copyfile('/var/lib/wo/tmp/composer.phar',
'/usr/local/bin/composer') '/usr/local/bin/composer')
WOFileUtils.chmod(self, "/usr/local/bin/composer", 0o775) WOFileUtils.chmod(self, "/usr/local/bin/composer", 0o775)
Log.valide(self, "Installing composer")
if ((os.path.isdir("/var/www/22222/htdocs/db/pma")) and if ((os.path.isdir("/var/www/22222/htdocs/db/pma")) and
(not os.path.isfile('/var/www/22222/htdocs/db/' (not os.path.isfile('/var/www/22222/htdocs/db/'
'pma/composer.lock'))): 'pma/composer.lock'))):
Log.info(self, "Updating phpMyAdmin, please wait...") Log.wait(self, "Updating phpMyAdmin")
WOShellExec.cmd_exec( WOShellExec.cmd_exec(
self, "/usr/local/bin/composer update " self, "/usr/local/bin/composer update "
"--no-plugins --no-scripts " "--no-plugins --no-scripts -n --no-dev -d "
"-n --no-dev -d " "/var/www/22222/htdocs/db/pma/")
"/var/www/22222/htdocs/db/pma/ &")
WOFileUtils.chown( WOFileUtils.chown(
self, '{0}22222/htdocs/db/pma' self, '{0}22222/htdocs/db/pma'
.format(WOVariables.wo_webroot), .format(WOVariables.wo_webroot),
'www-data', 'www-data',
'www-data', 'www-data',
recursive=True) recursive=True)
Log.valide(self, "Updating phpMyAdmin")
if not os.path.exists('{0}22222/htdocs/cache/' if not os.path.exists('{0}22222/htdocs/cache/'
'redis/phpRedisAdmin' 'redis/phpRedisAdmin'
.format(WOVariables.wo_webroot)): .format(WOVariables.wo_webroot)):
@@ -1171,12 +1191,11 @@ def post_pref(self, apt_packages, packages, upgrade=False):
.format(WOVariables.wo_webroot)) .format(WOVariables.wo_webroot))
if not os.path.isfile('/var/www/22222/htdocs/cache/redis/' if not os.path.isfile('/var/www/22222/htdocs/cache/redis/'
'phpRedisAdmin/composer.lock'): 'phpRedisAdmin/composer.lock'):
WOShellExec.cmd_exec(self, "/usr/local/bin/composer " WOShellExec.cmd_exec(
"create-project --no-plugins " self, "/usr/local/bin/composer "
"--no-scripts -n -s dev " "create-project --no-plugins --no-scripts -n -s dev "
"erik-dubbelboer/php-redis-admin " "erik-dubbelboer/php-redis-admin "
"/var/www/22222/htdocs/cache" "/var/www/22222/htdocs/cache/redis/phpRedisAdmin")
"/redis/phpRedisAdmin &")
WOFileUtils.chown(self, '{0}22222/htdocs' WOFileUtils.chown(self, '{0}22222/htdocs'
.format(WOVariables.wo_webroot), .format(WOVariables.wo_webroot),
'www-data', 'www-data',
@@ -1192,11 +1211,11 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# netdata install # netdata install
if any('/var/lib/wo/tmp/kickstart.sh' == x[1] if any('/var/lib/wo/tmp/kickstart.sh' == x[1]
for x in packages): for x in packages):
Log.info(self, "Installing Netdata, please wait...") Log.wait(self, "Installing Netdata")
WOShellExec.cmd_exec(self, "bash /var/lib/wo/tmp/" WOShellExec.cmd_exec(
"kickstart.sh " self, "bash /var/lib/wo/tmp/kickstart.sh "
"--dont-wait", "--dont-wait", errormsg='', log=False)
errormsg='', log=False) Log.valide(self, "Installing Netdata")
if os.path.isdir('/etc/netdata'): if os.path.isdir('/etc/netdata'):
wo_netdata = "/" wo_netdata = "/"
elif os.path.isdir('/opt/netdata'): elif os.path.isdir('/opt/netdata'):
@@ -1228,7 +1247,7 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOMysql.execute( WOMysql.execute(
self, "flush privileges;", self, "flush privileges;",
log=False) log=False)
except CommandExecutionError as e: except Exception as e:
Log.debug(self, "{0}".format(e)) Log.debug(self, "{0}".format(e))
Log.info( Log.info(
self, "fail to setup mysql user for netdata") 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() "| cut -d ' ' -f 2").read()
if (wo_wan != 'eth0' and wo_wan != ''): if (wo_wan != 'eth0' and wo_wan != ''):
WOFileUtils.searchreplace(self, WOFileUtils.searchreplace(self,
"{0}22222/htdocs/index.php" "{0}22222/htdocs/index.html"
.format(WOVariables.wo_webroot), .format(WOVariables.wo_webroot),
"eth0", "eth0",
"{0}".format(wo_wan)) "{0}".format(wo_wan))

View File

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

View File

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

View File

@@ -45,8 +45,9 @@ class WOSyncController(CementBaseController):
Log.debug(self, "Config files not found in {0}/ " Log.debug(self, "Config files not found in {0}/ "
.format(wo_site_webroot)) .format(wo_site_webroot))
if site.site_type != 'mysql': if site.site_type != 'mysql':
Log.debug(self, "Searching wp-config.php in {0}/htdocs/ " Log.debug(self,
.format(wo_site_webroot)) "Searching wp-config.php in {0}/htdocs/"
.format(wo_site_webroot))
configfiles = glob.glob( configfiles = glob.glob(
wo_site_webroot + '/htdocs/wp-config.php') wo_site_webroot + '/htdocs/wp-config.php')
@@ -93,6 +94,6 @@ class WOSyncController(CementBaseController):
def load(app): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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): def load(app):
# register the plugin class.. this only happens if the plugin is enabled # 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. # 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 # 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-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none; add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer; add_header Referrer-Policy no-referrer;
# Optional: Don't log access to assets
location = /robots.txt { access_log off;
allow all; }
log_not_found off; location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
access_log off; 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; # Enable gzip but do not remove ETag headers
gzip_vary on; gzip on;
gzip_comp_level 4; gzip_vary on;
gzip_min_length 256; gzip_comp_level 4;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; gzip_min_length 256;
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; 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;
}

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""" """WordOps generic database creation module"""
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
from wo.core.variables import WOVariables from wo.core.variables import WOVariables
# db_path = self.app.config.get('site', 'db_path') # db_path = self.app.config.get('site', 'db_path')

View File

@@ -9,7 +9,8 @@ Render Templates
class WOTemplate(): 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) data = dict(data)
if (not os.path.isfile('{0}.custom' if (not os.path.isfile('{0}.custom'
.format(fileconf))): .format(fileconf))):

View File

@@ -11,13 +11,13 @@ class WOVariables():
"""Intialization of core variables""" """Intialization of core variables"""
# WordOps version # WordOps version
wo_version = "3.9.8.12" wo_version = "3.9.9"
# WordOps packages versions # WordOps packages versions
wo_wp_cli = "2.3.0" wo_wp_cli = "2.3.0"
wo_adminer = "4.7.2" wo_adminer = "4.7.2"
wo_phpmyadmin = "4.9.0.1" wo_phpmyadmin = "4.9.1"
wo_extplorer = "2.1.13" wo_extplorer = "2.1.13"
wo_dashboard = "1.1" wo_dashboard = "1.2"
# Get WPCLI path # Get WPCLI path
wo_wpcli_path = '/usr/local/bin/wp' wo_wpcli_path = '/usr/local/bin/wp'
@@ -111,15 +111,6 @@ class WOVariables():
wo_nginx = ["nginx-custom", "nginx-wo"] wo_nginx = ["nginx-custom", "nginx-wo"]
wo_nginx_key = '188C9FB063F0247A' 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", 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-readline", "php7.2-common", "php7.2-recode",
"php7.2-cli", "php7.2-mbstring", "php7.2-intl", "php7.2-cli", "php7.2-mbstring", "php7.2-intl",
@@ -133,18 +124,6 @@ class WOVariables():
wo_php_extra = ["php-memcached", "php-imagick", wo_php_extra = ["php-memcached", "php-imagick",
"graphviz", "php-xdebug", "php-msgpack", "php-redis"] "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_distro == 'raspbian':
if (not wo_platform_codename == 'jessie'): if (not wo_platform_codename == 'jessie'):
wo_mysql = ["mariadb-server", "percona-toolkit", wo_mysql = ["mariadb-server", "percona-toolkit",
@@ -166,11 +145,25 @@ class WOVariables():
# Redis repo details # Redis repo details
if wo_distro == 'ubuntu': if wo_distro == 'ubuntu':
wo_php_repo = "ppa:ondrej/php"
wo_redis_repo = ("ppa:chris-lea/redis-server") 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: 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" wo_redis_repo = ("deb https://packages.sury.org/php/ {codename} all"
.format(codename=wo_platform_codename)) .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'] wo_redis = ['redis-server']