diff --git a/.travis.yml b/.travis.yml index 341ef4d..01e50c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: required -dist: xenial +dist: bionic language: bash @@ -31,7 +31,7 @@ script: - sudo bash -c 'echo -e "[user]\n\tname = abc\n\temail = root@localhost.com" > /home/travis/.gitconfig' - sudo echo "Travis Banch = $TRAVIS_BRANCH" - sudo apt-get install -qq --force-yes git python3-setuptools python3-dev python3-apt ccze tree - - sudo bash install -b $TRAVIS_BRANCH --travis + - sudo bash install --travis - sudo wo --help && sudo wo stack install && sudo wo stack install --proftpd - sudo wo site create html.net --html && sudo wo site create php.com --php && sudo wo site create mysql.com --mysql && sudo wo site create proxy.com --proxy=127.0.0.1:3000 - sudo wo site create wp1.com --wp && sudo wo site create wpsc1.net --wpsc && sudo wo site create wpfc1.com --wpfc @@ -46,10 +46,12 @@ script: - sudo wo site update 1.com --wp && sudo wo site update 2.com --php73 && sudo wo site update 3.com --php73 && sudo wo site update 1.com --wpfc && sudo wo site update 1.com --wpsc && sudo wo site update 1.com --wpredis - sudo wp --allow-root --info - sudo wo info - - sudo tree -L 2 /etc/nginx - - sudo cat /var/www/wp1.com/wp-config.php + - sudo cat /etc/nginx/nginx.conf + - sudo cat /etc/mysql/my.cnf - sudo wo stack upgrade --netdata --no-prompt - sudo wo stack upgrade --phpmyadmin --no-prompt - sudo wo stack upgrade --composer --no-prompt - sudo wo update --travis - - sudo wo stack status \ No newline at end of file + - sudo wo stack status + - echo "yes" | sudo wo stack purge --all + - sudo bash install --purge diff --git a/CHANGELOG.md b/CHANGELOG.md index 087e42c..ba005be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,45 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### v3.9.x - [Unreleased] +### v3.9.7 - 2019-08-02 + +#### Added + +- MySQL configuration tuning +- Cronjob to optimize MySQL databases weekly +- WO-kernel systemd service to automatically apply kernel tweaks on server startup +- Proftpd stack now secured with TLS +- New Nginx package built with Brotli from operating system libraries +- Brotli configuration with only well compressible MIME types +- WordPress site url automatically updated to `https://domain.tld` when using `-le/--letsencrypt` flag +- More informations during certificate issuance about validation mode selected +- `--php72` as alternative for `--php` +- Automated removal of the deprecated variable `ssl on;` in previous Nginx ssl.conf +- Project Contributing guidelines +- Project Code of conduct + +#### Changed + +- `wo maintenance` refactored +- Improved debug log +- Updated Nginx configuration process to not overwrite files with custom data (htpasswd-wo, acl.conf etc..) +- Adminer updated to v4.7.2 +- eXtplorer updated to v2.1.13 +- Removed WordOps version from the Nginx header X-Powered-By to avoid possible security issues +- Several code quality improvements to speed up WordOps execution +- Few adjustements on PHP-FPM configuration (max_input_time,opcache.consistency_checks) +- Added /dev/urandom & /dev/shm to open_basedir in PHP-FPM configuration + +#### Fixed + +- Kernel tweaks were not applied without server reboot +- Fail2ban standalone install +- `wo stack purge --all` error due to PHP7.3 check +- Nginx helper configuration during plugin install for Nginx fastcgi_cache and redis-cache +- phpRedisAdmin stack installation +- Fixed Travis CI build on pull requests +- Nginx `server_names_hash_bucket_size` variable error after WordOps upgrade + ### v3.9.6.2 - 2019-07-24 #### Changed diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..5f8b59a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team lead at contact@wordops.io. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a7bb730 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributing + +Thank you for considering contributing to WordOps. + +We love to receive contributions. Maintaining a CLI tool for deploying WordPress with Nginx with a few key strokes require to have enough knowledge for each stack configuration and to work with non-interactive operations. We rely on community contributions and user feedback to continue providing the best CLI tool to deploy WordPress with Nginx, PHP-FPM, MariaDB and Redis. + +There are many ways to contribute, with varying requirements of skills, explained in detail in the following sections. + +## All WordOps Users + +### Give WordOps a GitHub star + +This is the minimum open-source users should contribute back to the projects they use. Github stars help the project gain visibility, stand out. So, if you use WordOps, consider pressing that button. **It really matters**. + +### Spread the word + +Community growth allows the project to attract new talent willing to contribute. This talent is then developing new features and improves the project. These new features and improvements attract more users and so on. It is a loop. So, post about WordOps, present it to local meetups you attend, let your online social network or twitter, facebook, reddit, etc. know you are using it. **The more people involved, the faster the project evolves**. + +### Provide feedback + +Is there anything that bothers you about WordOps? Did you experience an issue while installing it or using it? Would you like to see it evolve to you need? Let us know. [Open a github issue](https://github.com/WordOps/WordOps/issues) to discuss it or open a thread on our [Community Forum](https://community.wordops.net/). Feedback is very important for open-source projects. We can't commit we will do everything, but your feedback influences our road-map significantly. + +## Experienced Users + +### Help other users + +As the project grows, an increasing share of our time is spent on supporting this community of users in terms of answering questions, of helping users understand how WordOps works and find their way with it. Helping other users is crucial. It allows the developers and maintainers of the project to focus on improving it. + +### Improve documentation + +All of our documentation is in markdown (.md) files inside the WordOps GitHub project. All of our [HTML documentation](https://docs.wordops.net) is generated from these files. At the top right of each documentation page you will see a pencil, that leads you directly to the markdown file that was used to generated it. Don't be afraid to click it and edit any of these documents and submit a GitHub Pull Request with your corrections/additions. + +## Developers + +(available soon) + +### Contributions Ground Rules + +#### Code of Conduct and CLA + +We expect all contributors to abide by the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/README.md b/README.md index 11433b9..9605769 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@

An essential toolset that eases WordPress site and server administration

-WordOps - +WordOps

@@ -15,7 +14,8 @@ MIT Commits GitHub release -
+
+ Badge Twitter Badge Slack @@ -32,7 +32,7 @@

WordOps.netDocumentation • -Community forum • +Community ForumDashboard demo

@@ -46,29 +46,29 @@ - **Up-to-date** : PHP 7.2 & 7.3, MariaDB 10.3 & Redis 5.0 - **Secured** : Hardened WordPress security with strict Nginx location directives - **Powerful** : Optimized Nginx configurations with multiple cache backends support -- **SSL** : Domain, Subdomain & Wildcard Let's Encrypt SSL certificates handled by acme.sh -- **Modern** : Strong ciphers_suite, modern TLS protocols and HSTS support (Grade A+ on ssllabs) +- **SSL** : Domain, Subdomain & Wildcard Let's Encrypt SSL certificates with DNS API support +- **Modern** : Strong ciphers_suite, modern TLS protocols and HSTS support (Grade A+ on [ssllabs](https://www.ssllabs.com/ssltest/analyze.html?d=demo.wordops.eu&latest)) - **Monitoring** : Live Nginx vhost traffic with ngx_vts_module and server monitoring with Netdata +- **User Friendly** : WordOps dashboard with server status/monitoring and tools ([demo](https://demo.wordops.eu)) + +--- ## Requirements ### Operating System -- Ubuntu 16.04 LTS (Xenial) +#### Recommended + - Ubuntu 18.04 LTS (Bionic) + +#### Also compatible + +- Ubuntu 16.04 LTS (Xenial) - Ubuntu 19.04 (Disco) -- Debian 8 (Jessie) - Debian 9 (Stretch) - Debian 10 (Buster) - Not ready for production - Raspbian 9 (Stretch) -### Ports requirements - -- SSH (22 or custom) -- HTTP & HTTPS (80 & 443) -- WO Admin (22222) -- GPG key Server (11371 outbound) - ## Getting Started ```bash @@ -76,9 +76,7 @@ wget -qO wo wops.cc && sudo bash wo # Install WordOps sudo wo site create example.com --wp # Install required packages & setup WordPress on example.com ``` -## Must read - -[From EasyEngine to WordOps](https://docs.wordops.net/about/from-easyengine-to-wordops/) +Detailed Getting Started guide with additional installation methods can be found in [the documentation](https://docs.wordops.net/getting-started/installation-guide/). ## Usage @@ -87,9 +85,9 @@ sudo wo site create example.com --wp # Install required packages & setup Wor ```bash wo site create example.com --wp # install wordpress without any page caching wo site create example.com --wp --php73 # install wordpress with PHP 7.3 without any page caching -wo site create example.com --wpsc # install wordpress with wp-super-cache plugin wo site create example.com --wpfc # install wordpress + nginx fastcgi_cache wo site create example.com --wpredis # install wordpress + nginx redis_cache +wo site create example.com --wpsc # install wordpress with wp-super-cache plugin ``` ### WordPress multisite with subdirectory @@ -115,17 +113,19 @@ wo site create example.com --wpsubdomain --wpredis # install wpmu-subdomain + n ```bash wo site create example.com --html # create example.com for static/html sites wo site create example.com --php # create example.com with php support +wo site create example.com --php73 # create example.com with php 7.3 support wo site create example.com --mysql # create example.com with php & mysql support +wo site create example.com --mysql --php73 # create example.com with php 7.3 & mysql support wo site create example.com --proxy=127.0.0.1:3000 # create example.com with nginx as reverse-proxy ``` ### Sites secured with Let's Encrypt ```bash -wo site create example.com --wp --letsencrypt # wordpress secured with letsencrypt -wo site create sub.example.com --wp --letsencrypt=subdomain # wordpress + letsencrypt subdomain -wo site create site.tld --wp --letsencrypt --hsts # install wordpress & secure site with letsencrypt with HSTS -wo site create site.tld --wp --letsencrypt=wildcard --dns=dns_cf # install wordpress & issue a wildcard SSL certificate with Cloudflare DNS API +wo site create example.com --wp --letsencrypt # wordpress & letsencrypt +wo site create sub.example.com --wp --letsencrypt=subdomain # wordpress & letsencrypt subdomain +wo site create site.tld --wp --letsencrypt --hsts # wordpress & letsencrypt with HSTS +wo site create site.tld --wp --letsencrypt=wildcard --dns=dns_cf # wordpress & wildcard SSL certificate with Cloudflare DNS API ``` ## Update WordOps diff --git a/docs/wo.8 b/docs/wo.8 index 6ad30fa..47b17f6 100644 --- a/docs/wo.8 +++ b/docs/wo.8 @@ -1,19 +1,19 @@ -.TH wo 8 "WordOps (wo) version: 3.3.8" "Sep 10,2015" "WordOps" +.TH wo 8 "WordOps (wo) version: 3.9.6.3" "Jul 26,2019" "WordOps" .SH NAME .B WordOps (wo) \- Manage Nginx Based Websites. .SH SYNOPSIS wo [ --version | --help | info | stack | site | debug | update | clean | import_slow_log | log | secure | sync | maintenance ] .TP -wo stack [ install | remove | purge | migrate | upgrade] [ --web | --all | --nginx | --php | --php73 | --mysql | --admin | --adminer | --redis | --phpmyadmin | --phpredisadmin | --wpcli | --utils | --dashboard | --netdata ] +wo stack [ install | remove | purge | migrate | upgrade] [ --web | --all | --nginx | --php | --php73 | --mysql | --admin | --adminer | --redis | --phpmyadmin | --phpredisadmin | --wpcli | --utils | --dashboard | --netdata | --fail2ban | --proftpd ] .TP -wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php | --php73 |--mysql | --web | --redis] +wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php | --php73 |--mysql | --web | --redis | --netdata | --fail2ban | --proftpd] .TP wo site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ] .TP -wo site create example.com [ --html | --php | --php73 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis | --letsencrypt/-le/--letsencrypt=subdomain/wildcard][--dns=dns_cf/dns_do]] +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]] .TP -wo site update example.com [ --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ] [--password] [-le/--letsencrypt=on/off/subdomain/renew/wildcard] [--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/subdomain/renew/wildcard/clean/purge] [--dns/--dns=dns_cf/dns_do]] .TP wo site delete example.com [--db | --files | --all | --no-prompt | --force/-f ] .TP @@ -46,19 +46,19 @@ Display WordOps (wo) help. .TP .B stack .TP -.B install [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard ] +.B install [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard | --fail2ban | --proftpd ] .br Install Nginx PHP5 MySQL Postfix stack Packages if not used with .br any options.Installs specific package if used with option. .TP -.B remove [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard ] +.B remove [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard | --fail2ban | --proftpd ] .br Remove Nginx PHP5 MySQL Postfix stack Packages if not used with .br any options. Remove specific package if used with option. .TP -.B purge [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard ] +.B purge [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard | --fail2ban | --proftpd ] .br Purge Nginx PHP5 MySQL Postfix stack Packages if not used with any .br @@ -165,7 +165,7 @@ Update security settings. .TP .B clean [ --fastcgi | --opcache | --redis | --all ] .br -Clean NGINX fastCGI cache, Opcache, memcached, Redis cache. +Clean NGINX fastCGI cache, Opcache, Redis cache. .br Clean NGINX fastCGI cache if no option specified. .SH ARGUMENTS @@ -312,3 +312,6 @@ Report bugs at .B Rajdeep Sharma .I \ .br +.B Thomas SUCHON +.I \ +.br diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..6057fb9 Binary files /dev/null and b/favicon.ico differ diff --git a/install b/install index 4d0a4e5..d0d2de2 100755 --- a/install +++ b/install @@ -7,10 +7,10 @@ # Copyright (c) 2019 - WordOps # This script is licensed under M.I.T # ------------------------------------------------------------------------- -# Version 3.9.6 - 2019-07-24 +# Version 3.9.7 - 2019-08-02 # ------------------------------------------------------------------------- readonly wo_version_old="2.2.3" -readonly wo_version_new="3.9.6.2" +readonly wo_version_new="3.9.7" # CONTENTS # --- # 1. VARIABLES AND DECLARATIONS @@ -73,6 +73,9 @@ while [ "$#" -gt 0 ]; do -s | --silent) wo_force_install="y" ;; + --purge | --uninstall) + wo_purge="y" + ;; *) # positional args ;; esac @@ -179,16 +182,14 @@ wo_install_dep() { } if [ "$wo_linux_distro" == "Ubuntu" ]; then # install dependencies - DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confmiss" -o Dpkg::Options::="--force-confold" --assume-yes install build-essential curl gzip python3 python3-apt python3-setuptools python3-dev sqlite3 git tar software-properties-common pigz gnupg2 cron ccze rsync tree haveged ufw > /dev/null 2>&1 + DEBIAN_FRONTEND=noninteractive apt-get -option=Dpkg::options::=--force-confmiss --option=Dpkg::options::=--force-confold --assume-yes install build-essential curl gzip python3 python3-apt python3-setuptools python3-requests python3-dev sqlite3 git tar software-properties-common pigz gnupg2 cron ccze rsync tree haveged ufw > /dev/null 2>&1 else # install dependencies - DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confmiss" -o Dpkg::Options::="--force-confold" --assume-yes install build-essential curl gzip dirmngr sudo python3 python3-apt python3-setuptools python3-dev ca-certificates sqlite3 git tar software-properties-common pigz apt-transport-https gnupg2 cron ccze rsync tree haveged ufw > /dev/null 2>&1 + DEBIAN_FRONTEND=noninteractive apt-get -option=Dpkg::options::=--force-confmiss --option=Dpkg::options::=--force-confold --assume-yes install build-essential curl gzip dirmngr sudo python3 python3-apt python3-setuptools python3-requests python3-dev ca-certificates sqlite3 git tar software-properties-common pigz apt-transport-https gnupg2 cron ccze rsync tree haveged ufw > /dev/null 2>&1 # add php repository gpg key [ -d /etc/apt/trusted.gpg.d ] && { wget -qO /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg; } # add nginx repository gpg key - wget https://download.opensuse.org/repositories/home:virtubox:WordOps/Debian_9.0/Release.key -O Release.key - apt-key add - < Release.key - rm -f Release.key + curl -sL https://download.opensuse.org/repositories/home:virtubox:WordOps/Debian_10/Release.key | apt-key add - fi locale-gen en @@ -413,7 +414,7 @@ wo_install() { >> "$wo_install_log" 2>&1 if [ "$wo_force_install" = "y" ]; then - [ ! -f "$HOME/.gitconfig" ] && { bash -c 'echo -e "[user]\n\tname = $USER\n\temail = root@$HOSTNAME.local" > $HOME/.gitconfig'; } + [ ! -f "$HOME/.gitconfig" ] && { bash -c 'echo -e "[user]\n\tname = $USER\n\temail = root@$HOSTNAME.local" > $HOME/.gitconfig'; } fi if [ -f "$HOME/.gitconfig" ]; then @@ -426,6 +427,16 @@ wo_install() { } +# Clone Github repository if it doesn't exist +wo_install_travis() { + + if [ -f "$HOME/.gitconfig" ]; then + # install and redirect log to not print python package install + python3 setup.py install >> $wo_install_log 2>&1 + fi + +} + wo_upgrade_nginx() { { @@ -449,15 +460,16 @@ wo_upgrade_nginx() { # add new Nginx repository if [ "$wo_linux_distro" = "Ubuntu" ]; then if [ ! -f /etc/apt/sources.list.d/wordops-ubuntu-nginx-wo-"$(lsb_release -sc)".list ]; then - add-apt-repository ppa:wordops/nginx-wo -y -u + add-apt-repository ppa:wordops/nginx-wo -y -u fi else if [ "$wo_distro_version" == "jessie" ]; then + # import the respository key for updates curl -sL https://download.opensuse.org/repositories/home:virtubox:WordOps/Debian_8.0/Release.key | apt-key add - else curl -sL https://download.opensuse.org/repositories/home:virtubox:WordOps/Debian_9.0/Release.key | apt-key add - fi - # import the respository key for updates + fi # stop nginx @@ -469,28 +481,32 @@ wo_upgrade_nginx() { } # install new nginx package - if [ -x /usr/local/bin/wo ]; then - - if [ -n "$CHECK_NGINX_EE" ]; then - # remove previous package - apt-mark unhold nginx-ee nginx-common nginx-custom - apt-get -y purge nginx-ee nginx-common nginx-custom --allow-change-held-packages - # remove previous php-fpm pool configuration - if [ -n "$CHECK_PHP72" ]; then - apt-get purge php7.2-fpm -y -qq - rm -f /etc/php/7.2/fpm/pool.d/{www.conf,www-two.conf,debug.conf} + if [ -n "$CHECK_NGINX_EE" ] || [ -n "$CHECK_NGINX_WO" ]; then + if [ -x /usr/local/bin/wo ]; then + if [ -n "$CHECK_NGINX_EE" ]; then + # remove previous package + apt-mark unhold nginx-ee nginx-common nginx-custom + apt-get --assume-yes purge nginx-ee nginx-common nginx-custom --allow-change-held-packages + # remove previous php-fpm pool configuration + if [ -n "$CHECK_PHP72" ]; then + apt-get purge php7.2-fpm -y -qq + rm -f /etc/php/7.2/fpm/pool.d/{www.conf,www-two.conf,debug.conf} + fi + elif [ -n "$CHECK_NGINX_WO" ]; then + apt-mark unhold nginx-wo nginx-common nginx-custom + apt-get --assume-yes purge nginx-wo nginx-common nginx-custom --allow-change-held-packages + if [ -n "$CHECK_PHP72" ]; then + apt-get purge php7.2-fpm -y -qq + rm -f /etc/php/7.2/fpm/pool.d/{www.conf,www-two.conf,debug.conf} + fi + fi + if [ -d /etc/nginx ]; then + rm -rf /etc/nginx fi - elif [ -n "$CHECK_NGINX_WO" ]; then - apt-mark unhold nginx-wo nginx-common nginx-custom - apt-get -y purge nginx-wo nginx-common nginx-custom --allow-change-held-packages + /usr/local/bin/wo stack install --nginx --php + rm -f /etc/nginx/common/acl.conf /etc/nginx/conf.d/{map-wp-cache.conf,map-wp.conf,fascgi.conf,blockips.conf} /etc/nginx/htpasswd-wo fi - if [ -d /etc/nginx ]; then - rm -rf /etc/nginx - fi - - /usr/local/bin/wo stack install --nginx --php - rm -f /etc/nginx/common/acl.conf /etc/nginx/conf.d/{map-wp-cache.conf,map-wp.conf,fascgi.conf,blockips.conf} /etc/nginx/htpasswd-wo fi # restore sites and configuration @@ -500,6 +516,7 @@ wo_upgrade_nginx() { sed -i "s/locations-php7.conf/locations-wo.conf/" /etc/nginx/sites-available/* sed -i "s/locations-php72.conf/locations-wo.conf/" /etc/nginx/sites-available/* sed -i "s/locations-php73.conf/locations-wo.conf/" /etc/nginx/sites-available/* + sed -i 's/ssl on;/#ssl on;/' /var/www/*/conf/nginx/ssl.conf # update redis.conf headers if [ -f /etc/nginx/common/redis.conf ]; then @@ -516,7 +533,7 @@ wo_upgrade_nginx() { else VERIFY_NGINX_BUCKET=$(nginx -t 2>&1 | grep "server_names_hash_bucket_size") if [ -n "$VERIFY_NGINX_BUCKET" ]; then - sed -i "s/# server_names_hash_bucket_size 64;/server_names_hash_bucket_size 64;/g" /etc/nginx/nginx.conf + sed -i "s/# server_names_hash_bucket_size 64;/server_names_hash_bucket_size 128;/g" /etc/nginx/nginx.conf fi systemctl stop nginx systemctl start nginx @@ -618,15 +635,15 @@ wo_git_init() { } wo_backup_ee() { - /bin/tar -I pigz -cf "$EE_BACKUP_FILE" /etc/nginx /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee /etc/letsencrypt >> /var/log/wo/install.log 2>&1 + /bin/tar -I pigz -cf "$EE_BACKUP_FILE" /etc/nginx /usr/local/bin/ee /usr/lib/ee/templates /usr/local/lib/python3.*/dist-packages/ee-*.egg /etc/ee /var/lib/ee /etc/letsencrypt >> /var/log/wo/install.log 2>&1 } wo_backup_wo() { - /bin/tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx /usr/local/lib/python3.6/dist-packages/wo-*.egg /etc/wo /var/lib/wo /etc/letsencrypt >> /var/log/wo/install.log 2>&1 + /bin/tar -I pigz -cf "$WO_BACKUP_FILE" /etc/nginx /usr/local/lib/python3.*/dist-packages/wo-*.egg /etc/wo /var/lib/wo /etc/letsencrypt >> /var/log/wo/install.log 2>&1 } wo_clean_ee() { - rm -f /usr/local/bin/ee /etc/bash_completion.d/ee_auto.rc /usr/lib/ee/templates /usr/local/lib/python3.6/dist-packages/ee-*.egg /etc/ee /var/lib/ee >> /var/log/wo/install.log 2>&1 + 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 >> /var/log/wo/install.log 2>&1 } wo_remove_ee_cron() { @@ -648,139 +665,175 @@ wo_tweak_kernel() { modprobe tcp_htcp && echo 'tcp_htcp' >> /etc/modules-load.d/htcp.conf echo 'net.ipv4.tcp_congestion_control = htcp' >> /etc/sysctl.d/60-wo-tweaks.conf fi - - fi - LIMIT_CHECK=$(grep "500000" /etc/security/limits.conf) - if [ -z "$LIMIT_CHECK" ]; then - echo -e "* hard nofile 500000\n* soft nofile 500000\nroot hard nofile 500000\nroot soft nofile 500000\n" >> /etc/security/limits.conf + # apply sysctl tweaks + sysctl -eq -p /etc/sysctl.d/60-wo-tweaks.conf + else + sysctl -eq -p /etc/sysctl.d/60-wo-tweaks.conf fi fi + if [ ! -x /opt/wo-kernel.sh ]; then + { + # download and setup wo-kernel systemd service to apply kernel tweaks for netdata and redis on server startup + wget -qO /opt/wo-kernel.sh https://raw.githubusercontent.com/WordOps/WordOps/updating-configuration/wo/cli/templates/wo-kernel-script.mustache + chmod +x /opt/wo-kernel.sh + wget -qO /lib/systemd/system/wo-kernel.service https://raw.githubusercontent.com/WordOps/WordOps/updating-configuration/wo/cli/templates/wo-kernel-service.mustache + systemctl enable wo-kernel.service + systemctl start wo-kernel.service + } >> /var/log/wo/install.log 2>&1 + fi + LIMIT_CHECK=$(grep "500000" /etc/security/limits.conf) + if [ -z "$LIMIT_CHECK" ]; then + echo -e "* hard nofile 500000\n* soft nofile 500000\nroot hard nofile 500000\nroot soft nofile 500000\n" >> /etc/security/limits.conf + fi + +} + +wo_clean() { + rm -rf /usr/local/lib/python3.*/dist-packages/wo-* +} + +wo_uninstall() { + rm -rf /usr/local/lib/python3.*/dist-packages/{pystache-*,cement-2.*,wo-*} /usr/local/bin/wo /etc/bash_completion.d/wo_auto.rc /var/lib/wo /etc/wo /usr/lib/wo/templates >> /var/log/wo/install.log 2>&1 } ### # 4 - WO MAIN SETUP ### -# 1 - WO already installed -if [ -x /usr/local/bin/wo ]; then - if ! { - wo -v 2>&1 | grep $wo_version_new - } || [ "$wo_force_install" = "y" ]; then - if [ -z "$wo_force_install" ]; then - echo -e "Update WordOps to $wo_version_new (y/n): " && read -r WO_ANSWER - else - WO_ANSWER="y" - fi - if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then - wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log - wo_install_dep | tee -ai $wo_install_log - wo_lib_echo "Backing-up WO install" | tee -ai $wo_install_log - wo_backup_wo | tee -ai $wo_install_log - wo_lib_echo "Syncing WO database" | tee -ai $wo_install_log - secure_wo_db | tee -ai $wo_install_log - wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log - if [ -f "$HOME/.gitconfig" ]; then - wo_install >> $wo_install_log 2>&1 +if [ "$wo_purge" = "y" ]; then + wo_lib_echo "Backing-up WO install" | tee -ai $wo_install_log + wo_backup_wo | tee -ai $wo_install_log + wo_lib_echo "Uninstalling WordOps" | tee -ai $wo_install_log + wo_uninstall | tee -ai $wo_install_log + wo_lib_echo "The WordOps backup files can be found in $WO_BACKUP_FILE" +else + # 1 - WO already installed + if [ -x /usr/local/bin/wo ]; then + if ! { + wo -v 2>&1 | grep $wo_version_new + } || [ "$wo_force_install" = "y" ]; then + if [ -z "$wo_force_install" ]; then + echo -e "Update WordOps to $wo_version_new (y/n): " && read -r WO_ANSWER else - wo_install | tee -ai $wo_install_log + WO_ANSWER="y" fi - if [ -z "$wo_preserve_config" ]; then - if [ -n "$(command -v nginx)" ]; then - if [ ! -f /etc/nginx/common/release ] || ! grep -q "v3.9.6" /etc/nginx/common/release; then - wo_lib_echo "Upgrading Nginx" | tee -ai $wo_install_log - wo_upgrade_nginx | tee -ai $wo_install_log + if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then + wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log + wo_install_dep | tee -ai $wo_install_log + wo_lib_echo "Backing-up WO install" | tee -ai $wo_install_log + wo_backup_wo | tee -ai $wo_install_log + secure_wo_db | tee -ai $wo_install_log + wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log + wo_clean | tee -ai $wo_install_log + if [ -f "$HOME/.gitconfig" ]; then + wo_install >> $wo_install_log 2>&1 + else + wo_install | tee -ai $wo_install_log + fi + if [ -z "$wo_preserve_config" ]; then + if [ -n "$(command -v nginx)" ]; then + if [ ! -f /etc/nginx/common/release ] || ! grep -q "v3.9.7" /etc/nginx/common/release; then + wo_lib_echo "Upgrading Nginx" | tee -ai $wo_install_log + wo_upgrade_nginx | tee -ai $wo_install_log + fi fi fi + wo_update_latest | tee -ai $wo_install_log + if [ ! -d /opt/acme/.sh ]; then + wo_lib_echo "Updating acme.sh" | tee -ai $wo_install_log + wo_install_acme_sh | tee -ai $wo_install_log + fi + wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log + wo_tweak_kernel | tee -ai $wo_install_log + wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log + wo_update_wp_cli | tee -ai $wo_install_log + else + wo_lib_error "Not updating WordOps to $wo_version_new, exit status = " 1 fi - wo_update_latest | tee -ai $wo_install_log - wo_lib_echo "Updating acme.sh" | tee -ai $wo_install_log - wo_install_acme_sh | tee -ai $wo_install_log - wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log - wo_tweak_kernel | tee -ai $wo_install_log - wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log - wo_git_init | tee -ai $wo_install_log - wo_update_wp_cli | tee -ai $wo_install_log else - wo_lib_error "Not updating WordOps to $wo_version_new, exit status = " 1 + wo_lib_error "You already have WordOps $wo_version_new, exit status = " 1 fi else - wo_lib_error "You already have WordOps $wo_version_new, exit status = " 1 - fi -else - # 2 - Migration from EEv3 - if [ -x /usr/local/bin/ee ]; then - if [ -z "$wo_force_install" ]; then - echo -e "Migrate from EasyEngine to WordOps (y/n): " && read -r WO_ANSWER + # 2 - Migration from EEv3 + if [ -x /usr/local/bin/ee ]; then + if [ -z "$wo_force_install" ]; then + echo -e "Migrate from EasyEngine to WordOps (y/n): " && read -r WO_ANSWER + else + WO_ANSWER="y" + fi + if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then + wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log + wo_install_dep | tee -ai $wo_install_log + wo_lib_echo "Backing-up EE install" | tee -ai $wo_install_log + wo_backup_ee | tee -ai $wo_install_log + wo_lib_echo "Removing EasyEngine cronjob" | tee -ai $wo_install_log + wo_remove_ee_cron | tee -ai $wo_install_log + wo_lib_echo "Syncing WO database" | tee -ai $wo_install_log + wo_sync_db | tee -ai $wo_install_log + secure_wo_db | tee -ai $wo_install_log + wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log + if [ -f "$HOME/.gitconfig" ]; then + wo_install >> $wo_install_log 2>&1 + else + wo_install | tee -ai $wo_install_log + fi + if [ -n "$(command -v nginx)" ]; then + wo_lib_echo "Upgrading Nginx" | tee -ai $wo_install_log + wo_upgrade_nginx | tee -ai $wo_install_log + fi + wo_update_latest | tee -ai $wo_install_log + wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log + wo_install_acme_sh | tee -ai $wo_install_log + wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log + wo_tweak_kernel | tee -ai $wo_install_log + wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log + wo_git_init | tee -ai $wo_install_log + wo_update_wp_cli | tee -ai $wo_install_log + wo_lib_echo "Cleaning-up EE previous install" | tee -ai $wo_install_log + wo_clean_ee | tee -ai $wo_install_log + else + wo_lib_error "Not installing WordOps, exit status = " 1 + fi else - WO_ANSWER="y" - fi - if [ "$WO_ANSWER" = "y" ] || [ "$WO_ANSWER" = "Y" ]; then + # 3 - Fresh WO setup wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log wo_install_dep | tee -ai $wo_install_log - wo_lib_echo "Backing-up EE install" | tee -ai $wo_install_log - wo_backup_ee | tee -ai $wo_install_log - wo_lib_echo "Removing EasyEngine cronjob" | tee -ai $wo_install_log - wo_remove_ee_cron | tee -ai $wo_install_log - wo_lib_echo "Syncing WO database" | tee -ai $wo_install_log - wo_sync_db | tee -ai $wo_install_log - secure_wo_db | tee -ai $wo_install_log wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log - if [ -f "$HOME/.gitconfig" ]; then - wo_install >> $wo_install_log 2>&1 + if [ "$wo_travis" = "y" ]; then + wo_install_travis | tee -ai $wo_install_log else wo_install | tee -ai $wo_install_log fi - if [ -n "$(command -v nginx)" ]; then - wo_lib_echo "Upgrading Nginx" | tee -ai $wo_install_log - wo_upgrade_nginx | tee -ai $wo_install_log - fi - wo_update_latest | tee -ai $wo_install_log - wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log - wo_install_acme_sh | tee -ai $wo_install_log wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log wo_tweak_kernel | tee -ai $wo_install_log + wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log + wo_install_acme_sh | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log + secure_wo_db | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log - wo_lib_echo "Cleaning-up EE previous install" | tee -ai $wo_install_log - wo_clean_ee | tee -ai $wo_install_log - else - wo_lib_error "Not installing WordOps, exit status = " 1 fi - else - # 3 - Fresh WO setup - wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log - wo_install_dep | tee -ai $wo_install_log - wo_lib_echo "Installing WordOps " | tee -ai $wo_install_log - wo_install | tee -ai $wo_install_log - wo_lib_echo "Applying Kernel tweaks" | tee -ai $wo_install_log - wo_tweak_kernel | tee -ai $wo_install_log - wo_lib_echo "Installing acme.sh" | tee -ai $wo_install_log - wo_install_acme_sh | tee -ai $wo_install_log - wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log - secure_wo_db | tee -ai $wo_install_log - wo_git_init | tee -ai $wo_install_log - wo_update_wp_cli | tee -ai $wo_install_log fi -fi -wo sync | tee -ai $wo_install_log + wo sync | tee -ai $wo_install_log -if [ "$ee_migration" = "1" ]; then + if [ "$ee_migration" = "1" ]; then + echo + wo_lib_echo "The migration from EasyEngine to WordOps was succesfull!" + wo_lib_echo "The EasyEngine backup files can be found in /var/lib/wo-backup/ee-backup.tgz" + echo + elif [ "$wo_upgrade" = "1" ]; then + wo_lib_echo "WordOps (wo) upgrade to $wo_version_new was succesfull!" + else + wo_lib_echo "WordOps (wo) installed successfully" + fi echo - wo_lib_echo "The migration from EasyEngine to WordOps was succesfull!" - wo_lib_echo "The EasyEngine backup files can be found in /var/lib/wo-backup/ee-backup.tgz" + wo_lib_echo_info "For autocompletion, run the following command:" + wo_lib_echo_info "source /etc/bash_completion.d/wo_auto.rc" echo -elif [ "$wo_upgrade" = "1" ]; then - wo_lib_echo "WordOps (wo) upgrade to $wo_version_new was succesfull!" -else - wo_lib_echo "WordOps (wo) installed successfully" + wo_lib_echo "WordOps Documentation : https://docs.wordops.net" + wo_lib_echo "WordOps Community Forum : https://community.wordops.net" + echo + fi -echo -wo_lib_echo_info "For autocompletion, run the following command:" -wo_lib_echo_info "source /etc/bash_completion.d/wo_auto.rc" -echo -wo_lib_echo "WordOps Documentation : https://docs.wordops.net" -wo_lib_echo "WordOps Community Forum : https://community.wordops.net" -echo diff --git a/setup.py b/setup.py index c1efb3d..14a12e6 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,5 @@ from setuptools import setup, find_packages -import sys import os import glob import configparser @@ -32,7 +31,7 @@ config.read(os.path.expanduser("~")+'/.gitconfig') try: wo_user = config['user']['name'] wo_email = config['user']['email'] -except Exception as e: +except Exception: print("WordOps (wo) require an username & and an email " "address to configure Git (used to save server configurations)") print("Your informations will ONLY be stored locally") @@ -57,7 +56,7 @@ if not os.path.isfile('/root/.gitconfig'): shutil.copy2(os.path.expanduser("~")+'/.gitconfig', '/root/.gitconfig') setup(name='wo', - version='3.9.6.2', + version='3.9.7', description=long_description, long_description=long_description, classifiers=[], diff --git a/wo/cli/plugins/clean.py b/wo/cli/plugins/clean.py index b434815..1a8643b 100644 --- a/wo/cli/plugins/clean.py +++ b/wo/cli/plugins/clean.py @@ -88,8 +88,8 @@ class WOCleanController(CementBaseController): def clean_opcache(self): try: Log.info(self, "Cleaning opcache") - wp = urllib.request.urlopen(" https://127.0.0.1:22222/cache" - "/opcache/opgui.php?reset=1").read() + urllib.request.urlopen(" https://127.0.0.1:22222/cache" + "/opcache/opgui.php?reset=1").read() except Exception as e: Log.debug(self, "{0}".format(e)) Log.debug(self, "Unable hit url, " diff --git a/wo/cli/plugins/debug.py b/wo/cli/plugins/debug.py index 1c29c68..649cfea 100644 --- a/wo/cli/plugins/debug.py +++ b/wo/cli/plugins/debug.py @@ -3,7 +3,7 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook from wo.core.aptget import WOAptGet -from wo.core.shellexec import * +from wo.core.shellexec import WOShellExec from wo.core.mysql import WOMysql from wo.core.services import WOService from wo.core.logging import Log @@ -92,6 +92,7 @@ class WODebugController(CementBaseController): debug_address = (self.app.config.get('stack', 'ip-address') .split()) except Exception as e: + Log.debug(self, "{0}".format(e)) debug_address = ['0.0.0.0/0'] # Check if IP address is 127.0.0.1 then enable debug globally @@ -660,6 +661,7 @@ class WODebugController(CementBaseController): try: cron_time = int(self.app.pargs.interval) except Exception as e: + Log.debug(self, "{0}".format(e)) cron_time = 5 try: @@ -753,7 +755,7 @@ class WODebugController(CementBaseController): self.debug_fpm73() if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host is "localhost": + if WOVariables.wo_mysql_host == "localhost": self.debug_mysql() else: Log.warn(self, "Remote MySQL found, WordOps does not support " diff --git a/wo/cli/plugins/import_slow_log.py b/wo/cli/plugins/import_slow_log.py index 4716cad..6e51b51 100644 --- a/wo/cli/plugins/import_slow_log.py +++ b/wo/cli/plugins/import_slow_log.py @@ -1,9 +1,6 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook -from wo.core.shellexec import WOShellExec from wo.core.logging import Log -from wo.core.variables import WOVariables -import os def wo_import_slow_log_hook(app): diff --git a/wo/cli/plugins/info.py b/wo/cli/plugins/info.py index f478ccb..efaf767 100644 --- a/wo/cli/plugins/info.py +++ b/wo/cli/plugins/info.py @@ -2,7 +2,6 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook -from wo.core.variables import WOVariables from pynginxconfig import NginxConfig from wo.core.aptget import WOAptGet from wo.core.shellexec import WOShellExec @@ -94,6 +93,7 @@ class WOInfoController(CementBaseController): www_xdebug = (config['www']['php_admin_flag[xdebug.profiler_enable' '_trigger]']) except Exception as e: + Log.debug(self, "{0}".format(e)) www_xdebug = 'off' config.read('/etc/{0}/fpm/pool.d/debug.conf'.format("php/7.2")) @@ -112,6 +112,7 @@ class WOInfoController(CementBaseController): debug_xdebug = (config['debug']['php_admin_flag[xdebug.profiler_' 'enable_trigger]']) except Exception as e: + Log.debug(self, "{0}".format(e)) debug_xdebug = 'off' data = dict(version=version, expose_php=expose_php, @@ -169,6 +170,7 @@ class WOInfoController(CementBaseController): www_xdebug = (config['www']['php_admin_flag[xdebug.profiler_enable' '_trigger]']) except Exception as e: + Log.debug(self, "{0}".format(e)) www_xdebug = 'off' config.read('/etc/php/7.3/fpm/pool.d/debug.conf') @@ -187,6 +189,7 @@ class WOInfoController(CementBaseController): debug_xdebug = (config['debug']['php_admin_flag[xdebug.profiler_' 'enable_trigger]']) except Exception as e: + Log.debug(self, "{0}".format(e)) debug_xdebug = 'off' data = dict(version=version, expose_php=expose_php, @@ -222,7 +225,7 @@ class WOInfoController(CementBaseController): "-f1 | tr -d '\n'").read() host = "localhost" port = os.popen("/usr/bin/mysql -e \"show variables\" | " - "grep ^port | awk " + "/bin/grep ^port | awk " "'{print($2)}' | tr -d '\n'").read() wait_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " "^wait_timeout | awk '{print($2)}' | " @@ -236,10 +239,10 @@ class WOInfoController(CementBaseController): "grep Max_used_connections | awk " "'{print($2)}' | tr -d '\n'").read() datadir = os.popen("/usr/bin/mysql -e \"show variables\" | " - "grep datadir | awk" + "/bin/grep datadir | awk" " '{print($2)}' | tr -d '\n'").read() socket = os.popen("/usr/bin/mysql -e \"show variables\" | " - "grep \"^socket\" | " + "/bin/grep \"^socket\" | " "awk '{print($2)}' | tr -d '\n'").read() data = dict(version=version, host=host, port=port, wait_timeout=wait_timeout, @@ -279,7 +282,7 @@ class WOInfoController(CementBaseController): Log.error(self, "PHP 7.3 is not installed") if self.app.pargs.mysql: - if WOShellExec.cmd_exec(self, "mysqladmin ping"): + if WOShellExec.cmd_exec(self, "/usr/bin/mysqladmin ping"): self.info_mysql() else: Log.error(self, "MySQL is not installed") diff --git a/wo/cli/plugins/log.py b/wo/cli/plugins/log.py index 5b08189..7baf633 100644 --- a/wo/cli/plugins/log.py +++ b/wo/cli/plugins/log.py @@ -97,7 +97,7 @@ class WOLogShowController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host is "localhost": + if WOVariables.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -236,7 +236,7 @@ class WOLogResetController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host is "localhost": + if WOVariables.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -364,7 +364,7 @@ class WOLogGzipController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host is "localhost": + if WOVariables.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -502,7 +502,7 @@ class WOLogMailController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host is "localhost": + if WOVariables.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: diff --git a/wo/cli/plugins/maintenance.py b/wo/cli/plugins/maintenance.py index c787ef2..06a9071 100644 --- a/wo/cli/plugins/maintenance.py +++ b/wo/cli/plugins/maintenance.py @@ -3,11 +3,7 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook from wo.core.logging import Log -from wo.core.variables import WOVariables from wo.core.aptget import WOAptGet -from wo.core.apt_repo import WORepo -from wo.core.services import WOService -from wo.core.shellexec import WOShellExec def wo_maintenance_hook(app): @@ -27,16 +23,12 @@ class WOMaintenanceController(CementBaseController): try: Log.info(self, "updating apt-cache, please wait...") - WOShellExec.cmd_exec(self, "apt-get update") + WOAptGet.update(self) Log.info(self, "updating packages, please wait...") - WOShellExec.cmd_exec(self, "DEBIAN_FRONTEND=noninteractive " - "apt-get -o " - "Dpkg::Options::='--force-confmiss' " - "-o Dpkg::Options::='--force-confold' " - "-y dist-upgrade") + WOAptGet.dist_upgrade(self) Log.info(self, "cleaning-up packages, please wait...") - WOShellExec.cmd_exec(self, "apt-get -y --purge autoremove") - WOShellExec.cmd_exec(self, "apt-get -y autoclean") + WOAptGet.auto_remove(self) + WOAptGet.auto_clean(self) except OSError as e: Log.debug(self, str(e)) Log.error(self, "Package updates failed !") diff --git a/wo/cli/plugins/secure.py b/wo/cli/plugins/secure.py index 4312e84..c9a7de6 100644 --- a/wo/cli/plugins/secure.py +++ b/wo/cli/plugins/secure.py @@ -1,6 +1,5 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook -from wo.core.aptget import WOAptGet from wo.core.shellexec import WOShellExec from wo.core.variables import WOVariables from wo.core.logging import Log @@ -8,8 +7,6 @@ from wo.core.git import WOGit from wo.core.services import WOService import string import random -import sys -import hashlib import getpass @@ -116,6 +113,7 @@ class WOSecureController(CementBaseController): try: user_ip = self.app.pargs.user_input.split(',') except Exception as e: + Log.debug(self, "{0}".format(e)) user_ip = ['127.0.0.1'] for ip_addr in user_ip: if not ("exist_ip_address "+ip_addr in open('/etc/nginx/common/' diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index d0fc061..d5e5e59 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -1,7 +1,6 @@ # """WordOps site controller.""" from cement.core.controller import CementBaseController, expose from cement.core import handler, hook -from wo.core.cron import WOCron from wo.core.sslutils import SSL from wo.core.variables import WOVariables from wo.core.shellexec import WOShellExec @@ -13,10 +12,10 @@ from wo.cli.plugins.sitedb import * from wo.core.git import WOGit from subprocess import Popen from wo.core.nginxhashbucket import hashbucket -import sys import os import glob import subprocess +import json def wo_site_hook(app): @@ -49,6 +48,7 @@ class WOSiteController(CementBaseController): self.app.pargs.site_name = (input('Enter site name : ') .strip()) except IOError as e: + Log.debug(self, str(e)) Log.error(self, 'could not input site name') self.app.pargs.site_name = self.app.pargs.site_name.strip() @@ -87,6 +87,7 @@ class WOSiteController(CementBaseController): .strip()) except IOError as e: + Log.debug(self, str(e)) Log.error(self, 'could not input site name') self.app.pargs.site_name = self.app.pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) @@ -126,6 +127,7 @@ class WOSiteController(CementBaseController): self.app.pargs.site_name = (input('Enter site name : ') .strip()) except IOError as e: + Log.debug(self, str(e)) Log.error(self, 'could not input site name') self.app.pargs.site_name = self.app.pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) @@ -192,6 +194,7 @@ class WOSiteController(CementBaseController): self.app.pargs.site_name = (input('Enter site name : ') .strip()) except IOError as e: + Log.debug(self, str(e)) Log.error(self, 'could not input site name') # TODO Write code for wo site edit command here self.app.pargs.site_name = self.app.pargs.site_name.strip() @@ -221,6 +224,7 @@ class WOSiteController(CementBaseController): self.app.pargs.site_name = (input('Enter site name : ') .strip()) except IOError as e: + Log.debug(self, str(e)) Log.error(self, 'Unable to read input, please try again') self.app.pargs.site_name = self.app.pargs.site_name.strip() @@ -233,7 +237,7 @@ class WOSiteController(CementBaseController): WOFileUtils.chdir(self, wo_site_webroot) try: - subprocess.call(['bash']) + subprocess.call(['/bin/bash']) except OSError as e: Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) Log.error(self, "unable to change directory") @@ -259,6 +263,7 @@ class WOSiteEditController(CementBaseController): self.app.pargs.site_name = (input('Enter site name : ') .strip()) except IOError as e: + Log.debug(self, str(e)) Log.error(self, 'Unable to read input, Please try again') self.app.pargs.site_name = self.app.pargs.site_name.strip() @@ -275,6 +280,7 @@ class WOSiteEditController(CementBaseController): WOShellExec.invoke_editor(self, '/etc/nginx/sites-availa' 'ble/{0}'.format(wo_domain)) except CommandExecutionError as e: + Log.debug(self, str(e)) Log.error(self, "Failed invoke editor") if (WOGit.checkfilestatus(self, "/etc/nginx", '/etc/nginx/sites-available/{0}' @@ -304,6 +310,8 @@ class WOSiteCreateController(CementBaseController): (['--html'], dict(help="create html site", action='store_true')), (['--php'], + dict(help="create php 7.2 site", action='store_true')), + (['--php72'], dict(help="create php 7.2 site", action='store_true')), (['--php73'], dict(help="create php 7.3 site", action='store_true')), @@ -361,6 +369,8 @@ class WOSiteCreateController(CementBaseController): @expose(hide=True) def default(self): pargs = self.app.pargs + if pargs.php72: + self.app.pargs.php = True # self.app.render((data), 'default.mustache') # Check domain name validation data = dict() @@ -619,7 +629,7 @@ class WOSiteCreateController(CementBaseController): if (data['wp'] and (self.app.pargs.vhostonly)): try: - data = setupdatabase(self, data) + wo_wp_creds = setupwordpress(self, data) # Add database information for site into database updateSiteInfo(self, wo_domain, db_name=data['wo_db_name'], db_user=data['wo_db_user'], @@ -760,10 +770,10 @@ class WOSiteCreateController(CementBaseController): if self.app.pargs.hsts: setupHsts(self, wo_domain) + site_url_https(self, wo_domain) if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " "check issues with `nginx -t` command") - Log.info(self, "Congratulations! Successfully Configured " "SSl for Site " " https://{0}".format(wo_domain)) @@ -773,7 +783,6 @@ class WOSiteCreateController(CementBaseController): msg="Adding letsencrypts config of site: {0}" .format(wo_domain)) updateSiteInfo(self, wo_domain, ssl=letsencrypt) - elif data['letsencrypt'] is False: Log.info(self, "Not using Let\'s encrypt for Site " " http://{0}".format(wo_domain)) @@ -795,8 +804,10 @@ class WOSiteUpdateController(CementBaseController): action='store_true')), (['--html'], dict(help="update to html site", action='store_true')), - (['--php'], + (['--php72'], dict(help="update to php site", action='store_true')), + (['--php'], + dict(help="update to php site", action='store_true')), (['--php73'], dict(help="update to php73 site", action='store' or 'store_const', @@ -844,6 +855,9 @@ class WOSiteUpdateController(CementBaseController): def default(self): pargs = self.app.pargs + if pargs.php72: + self.app.pargs.php = True + if pargs.all: if pargs.site_name: Log.error(self, "`--all` option cannot be used with site name" @@ -1168,7 +1182,6 @@ class WOSiteUpdateController(CementBaseController): Log.error(self, "HTTPS is not configured for given " "site", False) return 0 - pass if pargs.letsencrypt: if pargs.letsencrypt == 'on': @@ -1215,19 +1228,6 @@ class WOSiteUpdateController(CementBaseController): data['php73'] = False php73 = False - if pargs.letsencrypt == "on": - if oldsitetype in ['wpsubdomain']: - if pargs.dns: - data['letsencrypt'] = True - letsencrypt = True - pargs.letsencrypt == 'wildcard' - else: - data['letsencrypt'] = True - letsencrypt = True - else: - data['letsencrypt'] = True - letsencrypt = True - if pargs.wpredis and data['currcachetype'] != 'wpredis': data['wpredis'] = True data['basic'] = False @@ -1240,10 +1240,8 @@ class WOSiteUpdateController(CementBaseController): if pargs.hsts: if pargs.hsts == "on": data['hsts'] = True - hsts = True elif pargs.hsts == "off": data['hsts'] = False - hsts = False if not data: Log.error(self, "Cannot update {0}, Invalid Options" @@ -1311,16 +1309,17 @@ class WOSiteUpdateController(CementBaseController): setupLetsEncrypt(self, wo_domain, False, True, True, wo_acme_dns) httpsRedirect(self, wo_domain, True, True) + site_url_https(self, wo_domain) else: WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled" .format(wo_site_webroot), '{0}/conf/nginx/ssl.conf' .format(wo_site_webroot)) + site_url_https(self, wo_domain) if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " "check issues with `nginx -t` command") - Log.info(self, "Congratulations! Successfully " "Configured SSl for Site " " https://{0}".format(wo_domain)) @@ -1478,21 +1477,29 @@ class WOSiteUpdateController(CementBaseController): (data['wpfc'])) or (oldsitetype == 'wp' and data['multisite'] and data['wpfc'])): try: - plugin_data = '{"log_level":"INFO","log_filesize":5,' - '"enable_purge":1,"enable_map":0,"enable_log":0,' - '"enable_stamp":0,"purge_homepage_on_new":1,' - '"purge_homepage_on_edit":1,"purge_homepage_on_del":1,' - '"purge_archive_on_new":1,"purge_archive_on_edit":0,' - '"purge_archive_on_del":0,' - '"purge_archive_on_new_comment":0,' - '"purge_archive_on_deleted_comment":0,' - '"purge_page_on_mod":1,' - '"purge_page_on_new_comment":1,' - '"purge_page_on_deleted_comment":1,' - '"cache_method":"enable_fastcgi",' - '"purge_method":"get_request",' - '"redis_hostname":"127.0.0.1","redis_port":"6379",' - '"redis_prefix":"nginx-cache:"}' + plugin_data_object = {"log_level": "INFO", + "log_filesize": 5, + "enable_purge": 1, + "enable_map": "0", + "enable_log": 0, + "enable_stamp": 0, + "purge_homepage_on_new": 1, + "purge_homepage_on_edit": 1, + "purge_homepage_on_del": 1, + "purge_archive_on_new": 1, + "purge_archive_on_edit": 0, + "purge_archive_on_del": 0, + "purge_archive_on_new_comment": 0, + "purge_archive_on_deleted_comment": 0, + "purge_page_on_mod": 1, + "purge_page_on_new_comment": 1, + "purge_page_on_deleted_comment": 1, + "cache_method": "enable_fastcgi", + "purge_method": "get_request", + "redis_hostname": "127.0.0.1", + "redis_port": "6379", + "redis_prefix": "nginx-cache:"} + plugin_data = json.dumps(plugin_data_object) setupwp_plugin( self, 'nginx-helper', 'rt_wp_nginx_helper_options', plugin_data, data) @@ -1510,21 +1517,29 @@ class WOSiteUpdateController(CementBaseController): data['multisite'] and data['wpredis'])): try: - plugin_data = '{"log_level":"INFO","log_filesize":5,' - '"enable_purge":1,"enable_map":0,"enable_log":0,' - '"enable_stamp":0,"purge_homepage_on_new":1,' - '"purge_homepage_on_edit":1,"purge_homepage_on_del":1,' - '"purge_archive_on_new":1,"purge_archive_on_edit":0,' - '"purge_archive_on_del":0,' - '"purge_archive_on_new_comment":0,' - '"purge_archive_on_deleted_comment":0,' - '"purge_page_on_mod":1,' - '"purge_page_on_new_comment":1,' - '"purge_page_on_deleted_comment":1,' - '"cache_method":"enable_redis",' - '"purge_method":"get_request",' - '"redis_hostname":"127.0.0.1","redis_port":"6379",' - '"redis_prefix":"nginx-cache:"}' + plugin_data_object = {"log_level": "INFO", + "log_filesize": 5, + "enable_purge": 1, + "enable_map": "0", + "enable_log": 0, + "enable_stamp": 0, + "purge_homepage_on_new": 1, + "purge_homepage_on_edit": 1, + "purge_homepage_on_del": 1, + "purge_archive_on_new": 1, + "purge_archive_on_edit": 0, + "purge_archive_on_del": 0, + "purge_archive_on_new_comment": 0, + "purge_archive_on_deleted_comment": 0, + "purge_page_on_mod": 1, + "purge_page_on_new_comment": 1, + "purge_page_on_deleted_comment": 1, + "cache_method": "enable_redis", + "purge_method": "get_request", + "redis_hostname": "127.0.0.1", + "redis_port": "6379", + "redis_prefix": "nginx-cache:"} + plugin_data = json.dumps(plugin_data_object) setupwp_plugin( self, 'nginx-helper', 'rt_wp_nginx_helper_options', plugin_data, data) @@ -1538,20 +1553,29 @@ class WOSiteUpdateController(CementBaseController): return 1 else: try: - plugin_data = '{"log_level":"INFO","log_filesize":5,' - '"enable_purge":0,"enable_map":0,"enable_log":0,' - '"enable_stamp":0,"purge_homepage_on_new":1,' - '"purge_homepage_on_edit":1,"purge_homepage_on_del":1,' - '"purge_archive_on_new":1,"purge_archive_on_edit":0,' - '"purge_archive_on_del":0,' - '"purge_archive_on_new_comment":0,' - '"purge_archive_on_deleted_comment":0,' - '"purge_page_on_mod":1,"purge_page_on_new_comment":1,' - '"purge_page_on_deleted_comment":1,' - '"cache_method":"enable_redis",' - '"purge_method":"get_request",' - '"redis_hostname":"127.0.0.1",' - '"redis_port":"6379","redis_prefix":"nginx-cache:"}' + plugin_data_object = {"log_level": "INFO", + "log_filesize": 5, + "enable_purge": 0, + "enable_map": 0, + "enable_log": 0, + "enable_stamp": 0, + "purge_homepage_on_new": 1, + "purge_homepage_on_edit": 1, + "purge_homepage_on_del": 1, + "purge_archive_on_new": 1, + "purge_archive_on_edit": 0, + "purge_archive_on_del": 0, + "purge_archive_on_new_comment": 0, + "purge_archive_on_deleted_comment": 0, + "purge_page_on_mod": 1, + "purge_page_on_new_comment": 1, + "purge_page_on_deleted_comment": 1, + "cache_method": "enable_redis", + "purge_method": "get_request", + "redis_hostname": "127.0.0.1", + "redis_port": "6379", + "redis_prefix": "nginx-cache:"} + plugin_data = json.dumps(plugin_data_object) setupwp_plugin( self, 'nginx-helper', 'rt_wp_nginx_helper_options', plugin_data, data) @@ -1596,35 +1620,6 @@ class WOSiteUpdateController(CementBaseController): "`tail /var/log/wo/wordops.log` and please try again") return 1 - if oldcachetype != 'wpredis' and data['wpredis']: - try: - if installwp_plugin(self, 'redis-cache', data): - # add WP_CACHE_KEY_SALT if not already set - try: - Log.debug(self, "Updating wp-config.php.") - WOShellExec.cmd_exec(self, - "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set --add " - "WP_CACHE_KEY_SALT " - "\'{0}:\' --path={1}\"" - .format(wo_domain, - wo_site_webroot)) - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Updating wp-config.php failed.") - Log.warn(self, "Updating wp-config.php failed. " - "Could not append:" - "\ndefine( \'WP_CACHE_KEY_SALT\', " - "\'{0}:\' );".format(wo_domain) + - "\nPlease add manually") - except SiteError as e: - Log.debug(self, str(e)) - Log.info(self, Log.FAIL + "Update site failed." - "Check the log for details: " - "`tail /var/log/wo/wordops.log` and please try again") - return 1 - # Service Nginx Reload if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 597c197..4181afe 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1,25 +1,24 @@ -from wo.cli.plugins.stack import WOStackController -from wo.core.fileutils import WOFileUtils -from wo.core.mysql import * -from wo.core.shellexec import * -from wo.core.sslutils import SSL -from wo.core.variables import WOVariables -from wo.cli.plugins.sitedb import * -from wo.core.aptget import WOAptGet -from wo.core.git import WOGit -from wo.core.logging import Log -from wo.core.sendmail import WOSendMail -from wo.core.services import WOService -import subprocess -from subprocess import CalledProcessError -import os -import random -import string -import sys import getpass import glob +import os +import random +import json import re -import platform +import string +import subprocess +from subprocess import CalledProcessError + +from wo.cli.plugins.sitedb import * +from wo.cli.plugins.stack import WOStackController +from wo.core.aptget import WOAptGet +from wo.core.fileutils import WOFileUtils +from wo.core.git import WOGit +from wo.core.logging import Log +from wo.core.mysql import * +from wo.core.services import WOService +from wo.core.shellexec import CommandExecutionError, WOShellExec +from wo.core.sslutils import SSL +from wo.core.variables import WOVariables class SiteError(Exception): @@ -39,7 +38,7 @@ def pre_run_checks(self): try: Log.debug(self, "checking NGINX configuration ...") FNULL = open('/dev/null', 'w') - ret = subprocess.check_call(["nginx", "-t"], stdout=FNULL, + subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=FNULL, stderr=subprocess.STDOUT) except CalledProcessError as e: Log.debug(self, "{0}".format(str(e))) @@ -90,7 +89,7 @@ def setupdomain(self, data): try: Log.debug(self, "Checking generated nginx conf, please wait...") FNULL = open('/dev/null', 'w') - ret = subprocess.check_call(["nginx", "-t"], stdout=FNULL, + subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=FNULL, stderr=subprocess.STDOUT) Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") except CalledProcessError as e: @@ -154,8 +153,7 @@ def setupdatabase(self, data): try: wo_db_name = input('Enter the MySQL database name [{0}]: ' .format(wo_replace_dot)) - except EOFError as e: - Log.debug(self, "{0}".format(e)) + except EOFError: raise SiteError("Unable to input database name") if not wo_db_name: @@ -168,8 +166,7 @@ def setupdatabase(self, data): wo_db_password = getpass.getpass(prompt='Enter the MySQL database' ' password [{0}]: ' .format(wo_random)) - except EOFError as e: - Log.debug(self, "{0}".format(e)) + except EOFError: raise SiteError("Unable to input database credentials") if not wo_db_username: @@ -190,13 +187,13 @@ def setupdatabase(self, data): Log.debug(self, "Database already exists, Updating DB_NAME .. ") wo_db_name = (wo_db_name[0:6] + generate_random()) wo_db_username = (wo_db_name[0:6] + generate_random()) - except MySQLConnectionError as e: + except MySQLConnectionError: raise SiteError("MySQL Connectivity problem occured") try: WOMysql.execute(self, "create database `{0}`" .format(wo_db_name)) - except StatementExcecutionError as e: + except StatementExcecutionError: Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") raise SiteError("create database execution failed") # Create MySQL User @@ -208,7 +205,7 @@ def setupdatabase(self, data): "create user `{0}`@`{1}` identified by '{2}'" .format(wo_db_username, wo_mysql_grant_host, wo_db_password), log=False) - except StatementExcecutionError as e: + except StatementExcecutionError: Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") raise SiteError("creating user failed for database") @@ -219,7 +216,7 @@ def setupdatabase(self, data): "grant all privileges on `{0}`.* to `{1}`@`{2}`" .format(wo_db_name, wo_db_username, wo_mysql_grant_host)) - except StatementExcecutionError as e: + except StatementExcecutionError: Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") SiteError("grant privileges to user failed for database ") @@ -265,7 +262,7 @@ def setupwordpress(self, data): Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") raise SiteError("download WordPress core failed") - except CommandExecutionError as e: + except CommandExecutionError: Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") raise SiteError(self, "download WordPress core failed") @@ -281,8 +278,7 @@ def setupwordpress(self, data): "contain numbers, letters, and underscores") wo_wp_prefix = input('Enter the WordPress table prefix [wp_]: ' ) - except EOFError as e: - Log.debug(self, "{0}".format(e)) + except EOFError: raise SiteError("input table prefix failed") if not wo_wp_prefix: @@ -325,47 +321,8 @@ def setupwordpress(self, data): pass else: raise SiteError("generate wp-config failed for wp single site") - except CommandExecutionError as e: + except CommandExecutionError: raise SiteError("generate wp-config failed for wp single site") - try: - - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_CACHE_KEY_SALT " - "\'{0}:\'\"".format(wo_domain_name)) - - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_MEMORY_LIMIT " - "\'128M\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_MAX_MEMORY_LIMIT " - "\'256M\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set CONCATENATE_SCRIPTS " - "false\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_POST_REVISIONS " - "\'10\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set MEDIA_TRASH " - "true\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set EMPTY_TRASH_DAYS " - "\'15\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_AUTO_UPDATE_CORE " - "minor\"") - - except CommandExecutionError as e: - Log.error(self, "Unable to define extra variable in wp-config.php") - else: Log.debug(self, "Generating wp-config for WordPress multisite") Log.debug(self, "bash -c \"php {0} --allow-root " @@ -403,47 +360,48 @@ def setupwordpress(self, data): pass else: raise SiteError("generate wp-config failed for wp multi site") - except CommandExecutionError as e: + except CommandExecutionError: raise SiteError("generate wp-config failed for wp multi site") - try: + try: - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_CACHE_KEY_SALT " - "\'{0}:\'\"".format(wo_domain_name)) + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set WP_CACHE_KEY_SALT " + "\'{0}:\'\"".format(wo_domain_name)) - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_MEMORY_LIMIT " - "\'128M\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_MAX_MEMORY_LIMIT " - "\'256M\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set CONCATENATE_SCRIPTS " - "false\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_POST_REVISIONS " - "\'10\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set MEDIA_TRASH " - "true\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set EMPTY_TRASH_DAYS " - "\'15\'\"") - WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config set WP_AUTO_UPDATE_CORE " - "minor\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set WP_MEMORY_LIMIT " + "\'128M\'\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set WP_MAX_MEMORY_LIMIT " + "\'256M\'\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set CONCATENATE_SCRIPTS " + "false --raw\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set WP_POST_REVISIONS " + "\'10\'\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set MEDIA_TRASH " + "true --raw\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set EMPTY_TRASH_DAYS " + "\'15\'\"") + WOShellExec.cmd_exec(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config set WP_AUTO_UPDATE_CORE " + "minor\"") - except CommandExecutionError as e: - Log.error(self, "Unable to define extra variable in wp-config.php") + except CommandExecutionError as e: + Log.debug(self, str(e)) + Log.error(self, "Unable to define extra variable in wp-config.php") # WOFileUtils.mvfile(self, os.getcwd()+'/wp-config.php', # os.path.abspath(os.path.join(os.getcwd(), os.pardir))) @@ -457,6 +415,7 @@ def setupwordpress(self, data): shutil.move(os.getcwd()+'/wp-config.php', os.path.abspath(os.path.join(os.getcwd(), os.pardir))) except Exception as e: + Log.debug(self, str(e)) Log.error(self, 'Unable to move file from {0} to {1}' .format(os.getcwd()+'/wp-config.php', os.path.abspath(os.path.join(os.getcwd(), @@ -471,8 +430,7 @@ def setupwordpress(self, data): "periods and the @ symbol.") try: wo_wp_user = input('Enter WordPress username: ') - except EOFError as e: - Log.debug(self, "{0}".format(e)) + except EOFError: raise SiteError("input WordPress username failed") if not wo_wp_pass: wo_wp_pass = wo_random @@ -482,8 +440,7 @@ def setupwordpress(self, data): while not wo_wp_email: try: wo_wp_email = input('Enter WordPress email: ') - except EOFError as e: - Log.debug(self, "{0}".format(e)) + except EOFError: raise SiteError("input WordPress username failed") try: @@ -492,8 +449,7 @@ def setupwordpress(self, data): Log.info(self, "EMail not Valid in config, " "Please provide valid email id") wo_wp_email = input("Enter your email: ") - except EOFError as e: - Log.debug(self, "{0}".format(e)) + except EOFError: raise SiteError("input WordPress user email failed") Log.debug(self, "Setting up WordPress tables") @@ -520,7 +476,7 @@ def setupwordpress(self, data): else: raise SiteError( "setup WordPress tables failed for single site") - except CommandExecutionError as e: + except CommandExecutionError: raise SiteError("setup WordPress tables failed for single site") else: Log.debug(self, "Creating tables for WordPress multisite") @@ -552,7 +508,7 @@ def setupwordpress(self, data): else: raise SiteError( "setup WordPress tables failed for wp multi site") - except CommandExecutionError as e: + except CommandExecutionError: raise SiteError("setup WordPress tables failed for wp multi site") Log.debug(self, "Updating WordPress permalink") @@ -562,52 +518,61 @@ def setupwordpress(self, data): "rewrite structure " "/%year%/%monthnum%/%day%/%postname%/") except CommandExecutionError as e: + Log.debug(self, str(e)) raise SiteError("Update wordpress permalinks failed") """Install nginx-helper plugin """ installwp_plugin(self, 'nginx-helper', data) if data['wpfc']: - plugin_data = '{"log_level":"INFO","log_filesize":5,' - '"enable_purge":1,"enable_map":0,' - '"enable_log":0,"enable_stamp":0,' - '"purge_homepage_on_new":1,' - '"purge_homepage_on_edit":1,' - '"purge_homepage_on_del":1,' - '"purge_archive_on_new":1,' - '"purge_archive_on_edit":0,' - '"purge_archive_on_del":0,' - '"purge_archive_on_new_comment":0,' - '"purge_archive_on_deleted_comment":0,' - '"purge_page_on_mod":1,' - '"purge_page_on_new_comment":1,' - '"purge_page_on_deleted_comment":1,' - '"cache_method":"enable_fastcgi",' - '"purge_method":"get_request",' - '"redis_hostname":"127.0.0.1",' - '"redis_port":"6379",' - '"redis_prefix":"nginx-cache:"}' - setupwp_plugin(self, 'nginx-helper', - 'rt_wp_nginx_helper_options', plugin_data, data) + plugin_data_object = {"log_level": "INFO", + "log_filesize": 5, + "enable_purge": 1, + "enable_map": "0", + "enable_log": 0, + "enable_stamp": 0, + "purge_homepage_on_new": 1, + "purge_homepage_on_edit": 1, + "purge_homepage_on_del": 1, + "purge_archive_on_new": 1, + "purge_archive_on_edit": 0, + "purge_archive_on_del": 0, + "purge_archive_on_new_comment": 0, + "purge_archive_on_deleted_comment": 0, + "purge_page_on_mod": 1, + "purge_page_on_new_comment": 1, + "purge_page_on_deleted_comment": 1, + "cache_method": "enable_fastcgi", + "purge_method": "get_request", + "redis_hostname": "127.0.0.1", + "redis_port": "6379", + "redis_prefix": "nginx-cache:"} + plugin_data = json.dumps(plugin_data_object) + setupwp_plugin(self, "nginx-helper", + "rt_wp_nginx_helper_options", plugin_data, data) elif data['wpredis']: - plugin_data = '{"log_level":"INFO","log_filesize":5,' - '"enable_purge":1,"enable_map":0,' - '"enable_log":0,"enable_stamp":0,' - '"purge_homepage_on_new":1,' - '"purge_homepage_on_edit":1,' - '"purge_homepage_on_del":1,' - '"purge_archive_on_new":1,' - '"purge_archive_on_edit":0,' - '"purge_archive_on_del":0,' - '"purge_archive_on_new_comment":0,' - '"purge_archive_on_deleted_comment":0,' - '"purge_page_on_mod":1,' - '"purge_page_on_new_comment":1,' - '"purge_page_on_deleted_comment":1,' - '"cache_method":"enable_redis",' - '"purge_method":"get_request",' - '"redis_hostname":"127.0.0.1",' - '"redis_port":"6379",' - '"redis_prefix":"nginx-cache:"}' + plugin_data_object = {"log_level": "INFO", + "log_filesize": 5, + "enable_purge": 1, + "enable_map": "0", + "enable_log": 0, + "enable_stamp": 0, + "purge_homepage_on_new": 1, + "purge_homepage_on_edit": 1, + "purge_homepage_on_del": 1, + "purge_archive_on_new": 1, + "purge_archive_on_edit": 0, + "purge_archive_on_del": 0, + "purge_archive_on_new_comment": 0, + "purge_archive_on_deleted_comment": 0, + "purge_page_on_mod": 1, + "purge_page_on_new_comment": 1, + "purge_page_on_deleted_comment": 1, + "cache_method": "enable_redis", + "purge_method": "get_request", + "redis_hostname": "127.0.0.1", + "redis_port": "6379", + "redis_prefix": "nginx-cache:"} + plugin_data = json.dumps(plugin_data_object) setupwp_plugin(self, 'nginx-helper', 'rt_wp_nginx_helper_options', plugin_data, data) @@ -642,6 +607,7 @@ def setupwordpressnetwork(self, data): raise SiteError("setup WordPress network failed") except CommandExecutionError as e: + Log.debug(self, str(e)) Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") raise SiteError("setup WordPress network failed") Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") @@ -658,6 +624,7 @@ def installwp_plugin(self, plugin_name, data): "--allow-root install " "{0}".format(plugin_name)) except CommandExecutionError as e: + Log.debug(self, str(e)) raise SiteError("plugin installation failed") try: @@ -670,6 +637,7 @@ def installwp_plugin(self, plugin_name, data): else '' )) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("plugin activation failed") return 1 @@ -693,6 +661,7 @@ def uninstallwp_plugin(self, plugin_name, data): "--allow-root uninstall " "{0}".format(plugin_name)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("plugin uninstall failed") @@ -710,6 +679,7 @@ def setupwp_plugin(self, plugin_name, plugin_option, plugin_data, data): "{0} \'{1}\' --format=json" .format(plugin_option, plugin_data)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("plugin setup failed") else: try: @@ -720,6 +690,7 @@ def setupwp_plugin(self, plugin_name, plugin_option, plugin_data, data): .format(plugin_option, plugin_data )) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("plugin setup failed") @@ -781,6 +752,7 @@ def sitebackup(self, data): "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") raise SiteError("mysqldump failed to backup database") except CommandExecutionError as e: + Log.debug(self, str(e)) Log.info(self, "[" + Log.ENDC + "Fail" + Log.OKBLUE + "]") raise SiteError("mysqldump failed to backup database") Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") @@ -861,7 +833,7 @@ def site_package_check(self, stype): if stype in ['mysql', 'wp', 'wpsubdir', 'wpsubdomain']: Log.debug(self, "Setting apt_packages variable for MySQL") - if not WOShellExec.cmd_exec(self, "mysqladmin ping"): + if not WOShellExec.cmd_exec(self, "/usr/bin/mysqladmin ping"): apt_packages = apt_packages + WOVariables.wo_mysql packages = packages + [["https://raw.githubusercontent.com/" "major/MySQLTuner-perl/master/" @@ -1001,6 +973,7 @@ def updatewpuserpassword(self, wo_domain, wo_site_webroot): is_wp = WOShellExec.cmd_exec(self, "wp --allow-root core" " version") except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("is WordPress site? check command failed ") # Exit if wo_domain is not wordpress install @@ -1020,6 +993,7 @@ def updatewpuserpassword(self, wo_domain, wo_site_webroot): WOShellExec.cmd_exec(self, "wp --allow-root user list " "--fields=user_login | grep -v user_login") except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("fetch wp userlist command failed") if not wo_wp_user: @@ -1030,6 +1004,7 @@ def updatewpuserpassword(self, wo_domain, wo_site_webroot): "--fields=user_login | grep {0}$ " .format(wo_wp_user)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("if wp user exists check command failed") if is_user_exist: @@ -1051,6 +1026,7 @@ def updatewpuserpassword(self, wo_domain, wo_site_webroot): " --user_pass={1}" .format(wo_wp_user, wo_wp_pass)) except CommandExecutionError as e: + Log.debug(self, str(e)) raise SiteError("wp user password update command failed") Log.info(self, "Password updated successfully") @@ -1100,6 +1076,7 @@ def logwatch(self, logfiles): print(data[0], data[1], zlib.decompress(base64.decodestring(data[2]))) except Exception as e: + Log.debug(self, str(e)) Log.info(time.time(), 'caught exception rendering a new log line in %s' % filename) @@ -1240,10 +1217,12 @@ def deleteDB(self, dbname, dbuser, dbhost, exit=True): errormsg='Unable to drop database {0}' .format(dbname)) except StatementExcecutionError as e: + Log.debug(self, str(e)) Log.debug(self, "drop database failed") Log.info(self, "Database {0} not dropped".format(dbname)) except MySQLConnectionError as e: + Log.debug(self, str(e)) Log.debug(self, "Mysql Connection problem occured") if dbuser != 'root': @@ -1253,14 +1232,17 @@ def deleteDB(self, dbname, dbuser, dbhost, exit=True): "drop user `{0}`@`{1}`" .format(dbuser, dbhost)) except StatementExcecutionError as e: + Log.debug(self, str(e)) Log.debug(self, "drop database user failed") Log.info(self, "Database {0} not dropped".format(dbuser)) try: WOMysql.execute(self, "flush privileges") except StatementExcecutionError as e: + Log.debug(self, str(e)) Log.debug(self, "drop database failed") Log.info(self, "Database {0} not dropped".format(dbname)) except Exception as e: + Log.debug(self, str(e)) Log.error(self, "Error occured while deleting database", exit) @@ -1308,6 +1290,7 @@ def removeAcmeConf(self, domain): "-d {0} --ecc" .format(domain)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Cert removal failed") WOFileUtils.rm(self, '/etc/letsencrypt/renewal/{0}_ecc' @@ -1323,12 +1306,41 @@ def removeAcmeConf(self, domain): WOFileUtils.rm(self, '/etc/nginx/conf.d/force-ssl-{0}.conf.disabled' .format(domain)) - WOGit.add(self, ["/etc/letsencrypt"], msg="Deleted {0} " .format(domain)) +def site_url_https(self, domain): + if os.path.isfile('/var/www/{0}/wp-config.php'.format(domain)): + wo_site_webroot = ('/var/www/{0}'.format(domain)) + Log.info(self, "Checking if site url already " + "use https, please wait...") + WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) + wo_siteurl = WOShellExec.cmd_exec_stdout(self, + "php {0} option get siteurl " + .format(WOVariables.wo_wpcli_path) + + "--allow-root --quiet") + test_url = re.split(":", wo_siteurl) + if not (test_url[0] == 'https'): + try: + WOShellExec.cmd_exec(self, "php {0} option update siteurl " + "\'https://{1}\' --allow-root".format( + WOVariables.wo_wpcli_path, domain)) + WOShellExec.cmd_exec(self, "php {0} option update home " + "\'https://{1}\' --allow-root".format( + WOVariables.wo_wpcli_path, domain)) + except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("migration to https failed") + Log.info( + self, "Site address updated " + "successfully to https://{0}".format(domain)) + else: + Log.info( + self, "Site address was already using https") + + def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='', dbhost=''): """ @@ -1372,10 +1384,16 @@ def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False, 'keylength')) 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" - Log.info(self, "Issuing SSL cert with acme.sh") + validation_mode = "Webroot challenge" + Log.debug(self, "Validation : Webroot mode") if subdomain: + Log.info(self, "Issuing subdomain SSL cert with acme.sh") + Log.info(self, "Validation mode : {0}".format(validation_mode)) ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " "--config-home " "'/etc/letsencrypt/config' " @@ -1386,6 +1404,8 @@ def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False, acme_mode, keylenght)) elif wildcard: + Log.info(self, "Issuing Wildcard SSL cert with acme.sh") + Log.info(self, "Validation mode : {0}".format(validation_mode)) ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " "--config-home " "'/etc/letsencrypt/config' " @@ -1396,6 +1416,8 @@ def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False, wo_acme_dns, keylenght)) else: + Log.info(self, "Issuing domain SSL cert with acme.sh") + Log.info(self, "Validation mode : {0}".format(validation_mode)) ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " "--config-home " "'/etc/letsencrypt/config' " @@ -1405,25 +1427,26 @@ def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False, .format(wo_domain_name, acme_mode, keylenght)) if ssl: + Log.info(self, "Deploying SSL cert with acme.sh") + Log.debug(self, "Cert deployment for domain: {0}" + .format(wo_domain_name)) try: - Log.info(self, "Deploying SSL cert with acme.sh") - Log.debug(self, "Cert deployment for domain: {0}" - .format(wo_domain_name)) - sslsetup = 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)) + + 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.info( self, "Adding /var/www/{0}/conf/nginx/ssl.conf" .format(wo_domain_name)) @@ -1439,7 +1462,7 @@ def setupLetsEncrypt(self, wo_domain_name, subdomain=False, wildcard=False, "ssl_stapling_verify on;\n" .format(WOVariables.wo_ssl_live, wo_domain_name)) sslconf.close() - #updateSiteInfo(self, wo_domain_name, ssl=True) + # updateSiteInfo(self, wo_domain_name, ssl=True) WOGit.add(self, ["/etc/letsencrypt"], msg="Adding letsencrypt folder") @@ -1467,7 +1490,7 @@ def renewLetsEncrypt(self, wo_domain_name): "--renew -d {0} --ecc --force" .format(wo_domain_name)) - mail_list = '' + # mail_list = '' if not ssl: Log.error(self, "ERROR : Let's Encrypt certificate renewal FAILED!", False) @@ -1553,6 +1576,7 @@ def httpsRedirect(self, wo_domain_name, redirect=True, wildcard=False): Log.debug(self, "Error occured while generating " "/etc/nginx/conf.d/force-ssl-{0}.conf" .format(wo_domain_name)) + else: try: Log.info( @@ -1601,11 +1625,10 @@ def archivedCertificateHandle(self, domain): "{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) + "\nPlease select an option from below?" "\n\t1: Reinstall existing certificate" - "\n\t2: Keep the existing certificate for now" - "\n\t3: Renew & replace the certificate (limit ~5 per 7 days)" + "\n\t2: Renew & replace the certificate (limit ~5 per 7 days)" "") check_prompt = input( - "\nType the appropriate number [1-3] 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" .format(WOVariables.wo_ssl_live, domain)): Log.error( @@ -1613,7 +1636,7 @@ def archivedCertificateHandle(self, domain): .format(WOVariables.wo_ssl_live, domain)) if check_prompt == "1": - Log.info(self, "Issuing SSL cert with acme.sh") + Log.info(self, "Reinstalling SSL cert with acme.sh") ssl = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " "/etc/letsencrypt/acme.sh " "--config-home " @@ -1625,7 +1648,7 @@ def archivedCertificateHandle(self, domain): "{0}/{1}/fullchain.pem " "--ca-file {0}/{1}/ca.pem " "--reloadcmd " - "\"service nginx restart\" " + "\"nginx -t && service nginx restart\" " .format(WOVariables.wo_ssl_live, domain)) if ssl: @@ -1651,25 +1674,12 @@ def archivedCertificateHandle(self, domain): .format(WOVariables.wo_ssl_live, domain)) sslconf.close() - updateSiteInfo(self, domain, ssl=True) - except IOError as e: Log.debug(self, str(e)) Log.debug(self, "Error occured while generating " "ssl.conf") elif (check_prompt == "2"): - Log.info(self, "Using Existing Certificate files") - if not os.path.isfile("{0}/{1}/fullchain.pem" - .format(WOVariables.wo_ssl_live, domain)): - Log.error(self, "Certificate files not found. Skipping.\n" - "Please check if following file exist" - "\n\t/etc/letsencrypt/live/{0}/fullchain.pem\n\t" - "/etc/letsencrypt/live/{0}/key.pem".format(domain)) - - updateSiteInfo(self, domain, ssl=True) - - elif (check_prompt == "3"): Log.info(self, "Issuing SSL cert with acme.sh") ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " "--config-home " @@ -1694,7 +1704,7 @@ def archivedCertificateHandle(self, domain): "ssl_trusted_certificate " "{0}/{1}/ca.pem;\n" "--reloadcmd " - "\"service nginx restart\" " + "\"nginx -t && service nginx restart\" " .format(WOVariables.wo_ssl_live, domain)) except IOError as e: diff --git a/wo/cli/plugins/sitedb.py b/wo/cli/plugins/sitedb.py index 4048b26..9e21e13 100644 --- a/wo/cli/plugins/sitedb.py +++ b/wo/cli/plugins/sitedb.py @@ -5,8 +5,6 @@ from sqlalchemy.ext.declarative import declarative_base from wo.core.logging import Log from wo.core.database import db_session from wo.cli.plugins.models import SiteDB -import sys -import glob def addNewSite(self, site, stype, cache, path, diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index bbd036a..a1ccaf0 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -1,36 +1,38 @@ """Stack Plugin for WordOps""" -from cement.core.controller import CementBaseController, expose from cement.core import handler, hook -from wo.cli.plugins.site_functions import * -from wo.core.variables import WOVariables -from wo.core.aptget import WOAptGet -from wo.core.download import WODownload -from wo.core.shellexec import WOShellExec, CommandExecutionError -from wo.core.fileutils import WOFileUtils -from wo.core.apt_repo import WORepo -from wo.core.extract import WOExtract -from wo.core.mysql import WOMysql -from wo.core.addswap import WOSwap -from wo.core.git import WOGit -from wo.core.checkfqdn import check_fqdn -from pynginxconfig import NginxConfig -from wo.core.services import WOService -import random -import string +from cement.core.controller import CementBaseController, expose + +import codecs import configparser -import shutil import os import pwd -import grp -import codecs -import platform +import random +import shutil +import string +import re +import requests + import psutil -from wo.cli.plugins.stack_services import WOStackStatusController -from wo.cli.plugins.stack_migrate import WOStackMigrateController -from wo.cli.plugins.stack_upgrade import WOStackUpgradeController -from wo.core.logging import Log +# from pynginxconfig import NginxConfig +from wo.cli.plugins.site_functions import * from wo.cli.plugins.sitedb import * +from wo.cli.plugins.stack_migrate import WOStackMigrateController +from wo.cli.plugins.stack_services import WOStackStatusController +from wo.cli.plugins.stack_upgrade import WOStackUpgradeController +from wo.core.addswap import WOSwap +from wo.core.apt_repo import WORepo +from wo.core.aptget import WOAptGet +from wo.core.cron import WOCron +from wo.core.download import WODownload +from wo.core.extract import WOExtract +from wo.core.fileutils import WOFileUtils +from wo.core.git import WOGit +from wo.core.logging import Log +from wo.core.mysql import WOMysql +from wo.core.services import WOService +from wo.core.shellexec import CommandExecutionError, WOShellExec +from wo.core.variables import WOVariables def wo_stack_hook(app): @@ -97,7 +99,7 @@ class WOStackController(CementBaseController): if set(WOVariables.wo_mysql).issubset(set(apt_packages)): # add mariadb repository excepted on raspbian and ubuntu 19.04 - if (not WOVariables.wo_platform_distro == 'raspbian'): + if (not WOVariables.wo_distro == 'raspbian'): Log.info(self, "Adding repository for MySQL, please wait...") mysql_pref = ("Package: *\nPin: origin " "sfo1.mirrors.digitalocean.com" @@ -115,7 +117,7 @@ class WOStackController(CementBaseController): # generate random 24 characters root password chars = ''.join(random.sample(string.ascii_letters, 24)) # configure MySQL non-interactive install - if (not WOVariables.wo_platform_distro == 'raspbian'): + if (not WOVariables.wo_distro == 'raspbian'): Log.debug(self, "Pre-seeding MySQL") Log.debug(self, "echo \"mariadb-server-10.3 " "mysql-server/root_password " @@ -129,6 +131,7 @@ class WOStackController(CementBaseController): .format(chars=chars), log=False) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error("Failed to initialize MySQL package") Log.debug(self, "echo \"mariadb-server-10.3 " @@ -143,6 +146,7 @@ class WOStackController(CementBaseController): .format(chars=chars), log=False) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error("Failed to initialize MySQL package") else: Log.debug(self, "Pre-seeding MySQL") @@ -158,6 +162,7 @@ class WOStackController(CementBaseController): .format(chars=chars), log=False) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error("Failed to initialize MySQL package") Log.debug(self, "echo \"mariadb-server-10.1 " @@ -172,7 +177,8 @@ class WOStackController(CementBaseController): .format(chars=chars), log=False) except CommandExecutionError as e: - Log.error("Failed to initialize MySQL package") + Log.debug(self, "{0}".format(e)) + Log.error(self, "Failed to initialize MySQL package") # generate my.cnf root credentials mysql_config = """ [client] @@ -192,7 +198,7 @@ class WOStackController(CementBaseController): # add nginx repository if set(WOVariables.wo_nginx).issubset(set(apt_packages)): - if (WOVariables.wo_platform_distro == 'ubuntu'): + if (WOVariables.wo_distro == 'ubuntu'): Log.info(self, "Adding repository for NGINX, please wait...") WORepo.add(self, ppa=WOVariables.wo_nginx_repo) Log.debug(self, 'Adding ppa for Nginx') @@ -205,7 +211,7 @@ class WOStackController(CementBaseController): # add php repository if (set(WOVariables.wo_php73).issubset(set(apt_packages)) or set(WOVariables.wo_php).issubset(set(apt_packages))): - if (WOVariables.wo_platform_distro == 'ubuntu'): + if (WOVariables.wo_distro == 'ubuntu'): Log.info(self, "Adding repository for PHP, please wait...") Log.debug(self, 'Adding ppa for PHP') WORepo.add(self, ppa=WOVariables.wo_php_repo) @@ -226,7 +232,7 @@ class WOStackController(CementBaseController): # add redis repository if set(WOVariables.wo_redis).issubset(set(apt_packages)): Log.info(self, "Adding repository for Redis, please wait...") - if WOVariables.wo_platform_distro == 'ubuntu': + if WOVariables.wo_distro == 'ubuntu': Log.debug(self, 'Adding ppa for redis') WORepo.add(self, ppa=WOVariables.wo_redis_repo) else: @@ -237,43 +243,18 @@ class WOStackController(CementBaseController): """Post activity after installation of packages""" if (apt_packages): + # Nginx configuration if set(WOVariables.wo_nginx).issubset(set(apt_packages)): - if set(["nginx"]).issubset(set(apt_packages)): - # Fix for white screen death with NGINX PLUS - if not WOFileUtils.grep(self, '/etc/nginx/fastcgi_params', - 'SCRIPT_FILENAME'): - with open('/etc/nginx/fastcgi_params', - encoding='utf-8', mode='a') as wo_nginx: - wo_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' - '\t$request_filename;\n') - if not (os.path.isfile('/etc/nginx/common/wpfc-php72.conf')): - # Change WordOpsVersion in nginx.conf file - WOFileUtils.searchreplace(self, "/etc/nginx/nginx.conf", - "# add_header", - "add_header") - - WOFileUtils.searchreplace(self, "/etc/nginx/nginx.conf", - "\"WordOps\"", - "\"WordOps v{0}\"" - .format(WOVariables.wo_version)) - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/conf.d/blockips.conf') - wo_nginx = open('/etc/nginx/conf.d/blockips.conf', - encoding='utf-8', mode='w') - self.app.render( - (data), 'blockips.mustache', out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/conf.d/fastcgi.conf') - wo_nginx = open('/etc/nginx/conf.d/fastcgi.conf', - encoding='utf-8', mode='w') - self.app.render( - (data), 'fastcgi.mustache', out=wo_nginx) - wo_nginx.close() + # Fix for white screen death with NGINX PLUS + if not WOFileUtils.grep(self, '/etc/nginx/fastcgi_params', + 'SCRIPT_FILENAME'): + with open('/etc/nginx/fastcgi_params', + encoding='utf-8', mode='a') as wo_nginx: + wo_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' + '\t$request_filename;\n') + if os.path.isfile('/etc/nginx/nginx.conf'): data = dict(php="9000", debug="9001", php7="9070", debug7="9170") Log.debug(self, 'Writting the nginx configuration to ' @@ -284,7 +265,6 @@ class WOStackController(CementBaseController): (data), 'upstream.mustache', out=wo_nginx) wo_nginx.close() - if not (os.path.isfile('/etc/nginx/conf.d/stub_status.conf')): data = dict(phpconf=True if WOAptGet.is_installed(self, 'php7.2-fpm') else False) @@ -296,7 +276,6 @@ class WOStackController(CementBaseController): (data), 'stub_status.mustache', out=wo_nginx) wo_nginx.close() - if not (os.path.isfile('/etc/nginx/conf.d/webp.conf')): data = dict() Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/conf.d/webp.conf') @@ -316,21 +295,16 @@ class WOStackController(CementBaseController): out=wo_nginx) wo_nginx.close() - # Setup Nginx common directory + # Setup Nginx common directory if not os.path.exists('/etc/nginx/common'): Log.debug(self, 'Creating directory' '/etc/nginx/common') os.makedirs('/etc/nginx/common') + if os.path.exists('/etc/nginx/common'): data = dict(webroot=WOVariables.wo_webroot) - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/acl.conf') - wo_nginx = open('/etc/nginx/common/acl.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'acl.mustache', - out=wo_nginx) - wo_nginx.close() + # Common Configuration Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/locations-wo.conf') wo_nginx = open('/etc/nginx/common/locations-wo.conf', @@ -339,6 +313,15 @@ class WOStackController(CementBaseController): out=wo_nginx) wo_nginx.close() + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpsubdir.conf') + wo_nginx = open('/etc/nginx/common/wpsubdir.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'wpsubdir.mustache', + out=wo_nginx) + wo_nginx.close() + + # PHP 7.2 conf Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/php72.conf') wo_nginx = open('/etc/nginx/common/php72.conf', @@ -371,17 +354,10 @@ class WOStackController(CementBaseController): out=wo_nginx) wo_nginx.close() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpsubdir.conf') - wo_nginx = open('/etc/nginx/common/wpsubdir.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpsubdir.mustache', - out=wo_nginx) - wo_nginx.close() + # PHP 7.3 conf + if os.path.isdir("/etc/nginx/common"): + data = dict() - # php73 conf - if not os.path.isfile("/etc/nginx/common/php73.conf"): - # data = dict() Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/php73.conf') wo_nginx = open('/etc/nginx/common/php73.conf', @@ -414,6 +390,17 @@ class WOStackController(CementBaseController): out=wo_nginx) wo_nginx.close() + # create redis conf + data = dict() + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/redis-php72.conf') + wo_nginx = open('/etc/nginx/common/redis-php72.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'redis.mustache', + out=wo_nginx) + wo_nginx.close() + + data = dict() Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/redis-php73.conf') wo_nginx = open('/etc/nginx/common/redis-php73.conf', @@ -422,22 +409,58 @@ class WOStackController(CementBaseController): out=wo_nginx) wo_nginx.close() - if not os.path.isfile("/etc/nginx/common/locations-wo.conf"): - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/locations-wo.conf') - wo_nginx = open('/etc/nginx/common/locations-wo.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'locations.mustache', - out=wo_nginx) - wo_nginx.close() - - if not os.path.isfile("/etc/nginx/common/release"): with open("/etc/nginx/common/release", "a") as release_file: release_file.write("v{0}" .format(WOVariables.wo_version)) release_file.close() + # Following files should not be overwrited + + if not os.path.isfile('/etc/nginx/common/acl.conf'): + data = dict(webroot=WOVariables.wo_webroot) + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/acl.conf') + wo_nginx = open('/etc/nginx/common/acl.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'acl.mustache', + out=wo_nginx) + wo_nginx.close() + if not os.path.isfile('/etc/nginx/conf.d/blockips.conf'): + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/conf.d/blockips.conf') + wo_nginx = open('/etc/nginx/conf.d/blockips.conf', + encoding='utf-8', mode='w') + self.app.render( + (data), 'blockips.mustache', out=wo_nginx) + wo_nginx.close() + + if not os.path.isfile('/etc/nginx/conf.d/fastcgi.conf'): + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/conf.d/fastcgi.conf') + wo_nginx = open('/etc/nginx/conf.d/fastcgi.conf', + encoding='utf-8', mode='w') + self.app.render( + (data), 'fastcgi.mustache', out=wo_nginx) + wo_nginx.close() + + # add redis cache format if not already done + if (os.path.isfile("/etc/nginx/nginx.conf") and + not os.path.isfile("/etc/nginx/conf.d" + "/redis.conf")): + with open("/etc/nginx/conf.d/" + "redis.conf", "a") as redis_file: + redis_file.write("# Log format Settings\n" + "log_format rt_cache_redis " + "'$remote_addr " + "$upstream_response_time " + "$srcache_fetch_status " + "[$time_local] '\n" + "'$http_host \"$request\" $status" + " $body_bytes_sent '\n" + "'\"$http_referer\" " + "\"$http_user_agent\"';\n") + # Nginx-Plus does not have nginx # package structure like this # So creating directories @@ -464,7 +487,7 @@ class WOStackController(CementBaseController): passwd = ''.join([random.choice (string.ascii_letters + string.digits) - for n in range(6)]) + for n in range(16)]) try: WOShellExec.cmd_exec(self, "printf \"WordOps:" "$(openssl passwd -crypt " @@ -473,6 +496,7 @@ class WOStackController(CementBaseController): "2>/dev/null" .format(password=passwd)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Failed to save HTTP Auth") # Create Symbolic link for 22222 @@ -552,12 +576,15 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error( self, "Failed to generate HTTPS " "certificate for 22222") + server_ip = requests.get('http://v4.wordops.eu') if not os.path.isfile('{0}22222/conf/nginx/ssl.conf' .format(WOVariables.wo_webroot)): + with open("/var/www/22222/conf/nginx/" "ssl.conf", "a") as php_file: php_file.write("ssl_certificate " @@ -569,7 +596,12 @@ class WOStackController(CementBaseController): WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git") WOService.reload_service(self, 'nginx') + if set(["nginx"]).issubset(set(apt_packages)): + + print("WordOps backend configuration was successful\n" + "You can access it on : https://{0}:22222" + .format(server_ip)) print("HTTP Auth User Name: WordOps" + "\nHTTP Auth Password : {0}".format(passwd)) WOService.reload_service(self, 'nginx') @@ -578,129 +610,17 @@ class WOStackController(CementBaseController): "Name: WordOps"] + ["HTTP Auth Password : {0}" .format(passwd)]) + self.msg = (self.msg + ["WordOps backend is available " + "on https://{0}:22222 " + "or https://{1}:22222" + .format(server_ip.text, + WOVariables.wo_fqdn)]) else: WOService.restart_service(self, 'nginx') - # create redis conf is redis is installed - if WOAptGet.is_installed(self, 'redis-server'): - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/common/" - "redis-php72.conf")): - - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/redis-php72.conf') - wo_nginx = open('/etc/nginx/common/redis-php72.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'redis.mustache', - out=wo_nginx) - wo_nginx.close() - - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/common/" - "redis-php73.conf")): - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/redis-php73.conf') - wo_nginx = open('/etc/nginx/common/redis-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'redis-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - # add redis upstream if not available in upstream.conf - if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): - if not WOFileUtils.grep(self, "/etc/nginx/conf.d/" - "upstream.conf", - "redis"): - with open("/etc/nginx/conf.d/upstream.conf", - "a") as redis_file: - redis_file.write("upstream redis {\n" - " server 127.0.0.1:6379;\n" - " keepalive 10;\n}\n") - - # add redis cache format if not already done - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/conf.d" - "/redis.conf")): - with open("/etc/nginx/conf.d/" - "redis.conf", "a") as redis_file: - redis_file.write("# Log format Settings\n" - "log_format rt_cache_redis " - "'$remote_addr " - "$upstream_response_time " - "$srcache_fetch_status " - "[$time_local] '\n" - "'$http_host \"$request\" $status" - " $body_bytes_sent '\n" - "'\"$http_referer\" " - "\"$http_user_agent\"';\n") - # setup nginx common folder for php7 - if self.app.pargs.php73: - if (os.path.isdir("/etc/nginx/common") and - not os.path.isfile("/etc/nginx/common/php73.conf")): - data = dict() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/php73.conf') - wo_nginx = open('/etc/nginx/common/php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpcommon-php73.conf') - wo_nginx = open('/etc/nginx/common/wpcommon-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpcommon-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpfc-php73.conf') - wo_nginx = open('/etc/nginx/common/wpfc-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpfc-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpsc-php73.conf') - wo_nginx = open('/etc/nginx/common/wpsc-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpsc-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - if (os.path.isdir("/etc/nginx/common") and - not os.path.isfile("/etc/nginx/common/" - "redis-php73.conf")): - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/redis-php73.conf') - wo_nginx = open('/etc/nginx/common/redis-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'redis-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): - if not WOFileUtils.grep(self, "/etc/nginx/conf.d/" - "upstream.conf", - "php73"): - with open("/etc/nginx/conf.d/" - "upstream.conf", "a") as php_file: - php_file.write("upstream php73 {\nserver unix:" - "/var/run/php/php73-fpm.sock;\n}\n" - "upstream debug73 {\nserver " - "127.0.0.1:9173;\n}\n") # create nginx configuration for redis if set(WOVariables.wo_redis).issubset(set(apt_packages)): - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/common/" - "redis-php72.conf")): - + if os.path.isdir('/etc/nginx/common'): data = dict() Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/redis-php72.conf') @@ -751,6 +671,7 @@ class WOStackController(CementBaseController): config['PHP']['post_max_size'] = '100M' config['PHP']['upload_max_filesize'] = '100M' config['PHP']['max_execution_time'] = '300' + config['PHP']['max_input_time'] = '300' config['PHP']['max_input_vars'] = '20000' config['Date']['date.timezone'] = WOVariables.wo_timezone config['opcache']['opcache.enable'] = '1' @@ -758,7 +679,8 @@ class WOStackController(CementBaseController): config['opcache']['opcache.max_accelerated_files'] = '10000' config['opcache']['opcache.memory_consumption'] = '256' config['opcache']['opcache.save_comments'] = '1' - config['opcache']['opcache.revalidate_freq'] = '2' + config['opcache']['opcache.revalidate_freq'] = '5' + config['opcache']['opcache.consistency_checks'] = '0' config['opcache']['opcache.validate_timestamps'] = '1' with open('/etc/php/7.2/fpm/php.ini', encoding='utf-8', mode='w') as configfile: @@ -807,7 +729,8 @@ class WOStackController(CementBaseController): encoding='utf-8', mode='a') as myfile: myfile.write("\nphp_admin_value[open_basedir] " "= \"/var/www/:/usr/share/php/:" - "/tmp/:/var/run/nginx-cache/\"\n") + "/tmp/:/var/run/nginx-cache/:" + "/dev/shm:/dev/urandom\"\n") # Generate /etc/php/7.2/fpm/pool.d/www-two.conf WOFileUtils.copyfile(self, "/etc/php/7.2/fpm/pool.d/www.conf", @@ -912,6 +835,7 @@ class WOStackController(CementBaseController): config['PHP']['post_max_size'] = '100M' config['PHP']['upload_max_filesize'] = '100M' config['PHP']['max_execution_time'] = '300' + config['PHP']['max_input_time'] = '300' config['PHP']['max_input_vars'] = '20000' config['Date']['date.timezone'] = WOVariables.wo_timezone config['opcache']['opcache.enable'] = '1' @@ -919,7 +843,8 @@ class WOStackController(CementBaseController): config['opcache']['opcache.max_accelerated_files'] = '10000' config['opcache']['opcache.memory_consumption'] = '256' config['opcache']['opcache.save_comments'] = '1' - config['opcache']['opcache.revalidate_freq'] = '2' + config['opcache']['opcache.revalidate_freq'] = '5' + config['opcache']['opcache.consistency_checks'] = '0' config['opcache']['opcache.validate_timestamps'] = '1' with open('/etc/php/7.3/fpm/php.ini', encoding='utf-8', mode='w') as configfile: @@ -968,7 +893,8 @@ class WOStackController(CementBaseController): encoding='utf-8', mode='a') as myfile: myfile.write("\nphp_admin_value[open_basedir] " "= \"/var/www/:/usr/share/php/:" - "/tmp/:/var/run/nginx-cache/\"\n") + "/tmp/:/var/run/nginx-cache/:" + "/dev/shm:/dev/urandom\"\n") # Generate /etc/php/7.3/fpm/pool.d/www-two.conf WOFileUtils.copyfile(self, "/etc/php/7.3/fpm/pool.d/www.conf", @@ -1067,25 +993,19 @@ class WOStackController(CementBaseController): encoding='utf-8', mode='w') config_file.write(config) config_file.close() - else: - try: - WOShellExec.cmd_exec(self, "sed -i \"/#max_conn" - "ections/a wait_timeout = 30 \\n" - "interactive_timeout = 60 \\n" - "performance_schema = 0\\n" - "query_cache_type = 1 \" " - "/etc/mysql/my.cnf") - except CommandExecutionError as e: - Log.error(self, "Unable to update MySQL file") WOFileUtils.chmod(self, "/usr/bin/mysqltuner", 0o775) - + WOCron.setcron_weekly(self, 'mysqlcheck -Aos --auto-repair ' + '> /dev/null 2>&1', + comment='MySQL optimization cronjob ' + 'added by WordOps') WOGit.add(self, ["/etc/mysql"], msg="Adding MySQL into Git") WOService.reload_service(self, 'mysql') # create fail2ban configuration files if set(WOVariables.wo_fail2ban).issubset(set(apt_packages)): if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"): + data = dict() Log.debug(self, "Setting up fail2ban jails configuration") fail2ban_config = open('/etc/fail2ban/jail.d/custom.conf', encoding='utf-8', mode='w') @@ -1132,12 +1052,54 @@ class WOStackController(CementBaseController): "PassivePorts " " " " 49000 50000") + # proftpd TLS configuration + if not os.path.isdir("/etc/proftpd/ssl"): + WOFileUtils.mkdir(self, "/etc/proftpd/ssl") + + try: + WOShellExec.cmd_exec(self, "openssl genrsa -out " + "/etc/proftpd/ssl/proftpd.key 2048") + WOShellExec.cmd_exec(self, "openssl req -new -batch " + "-subj /commonName=localhost/ " + "-key /etc/proftpd/ssl/proftpd.key " + "-out /etc/proftpd/ssl/proftpd.csr") + WOFileUtils.mvfile(self, "/etc/proftpd/ssl/proftpd.key", + "/etc/proftpd/ssl/proftpd.key.org") + WOShellExec.cmd_exec(self, "openssl rsa -in " + "/etc/proftpd/ssl/proftpd.key.org " + "-out /etc/proftpd/ssl/proftpd.key") + WOShellExec.cmd_exec(self, "openssl x509 -req -days " + "3652 -in /etc/proftpd/ssl/proftpd.csr " + "-signkey /etc/proftpd/ssl/proftpd.key " + " -out /etc/proftpd/ssl/proftpd.crt") + except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) + Log.error( + self, "Failed to generate SSL " + "certificate for Proftpd") + WOFileUtils.chmod(self, "/etc/proftpd/ssl/proftpd.key", 0o700) + WOFileUtils.chmod(self, "/etc/proftpd/ssl/proftpd.crt", 0o700) + data = dict() + Log.debug(self, 'Writting the proftpd configuration to ' + 'file /etc/proftpd/tls.conf') + wo_proftpdconf = open('/etc/proftpd/tls.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'proftpd-tls.mustache', + out=wo_proftpdconf) + wo_proftpdconf.close() + WOFileUtils.searchreplace(self, "/etc/proftpd/" + "proftpd.conf", + "#Include /etc/proftpd/tls.conf", + "Include /etc/proftpd/tls.conf") + WOService.restart_service(self, 'proftpd') + # add rule for proftpd with UFW if WOAptGet.is_installed(self, 'ufw'): try: WOShellExec.cmd_exec(self, "ufw allow " "49000:50000/tcp") except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to add UFW rule") if os.path.isfile("/etc/fail2ban/jail.d/custom.conf"): @@ -1265,6 +1227,7 @@ class WOStackController(CementBaseController): "flush privileges;", log=False) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) Log.info( self, "fail to setup mysql user for netdata") WOService.restart_service(self, 'netdata') @@ -1281,12 +1244,15 @@ class WOStackController(CementBaseController): 'wo-dashboard.tar.gz', '{0}22222/htdocs' .format(WOVariables.wo_webroot)) - if WOVariables.wo_wan != 'eth0': - WOFileUtils.searchreplace(self, "{0}22222/htdocs/index.php" + wo_wan = os.popen("/sbin/ip -4 route get 8.8.8.8 | " + "grep -oP \"dev [^[:space:]]+ \" " + "| cut -d ' ' -f 2").read() + if (wo_wan != 'eth0' and wo_wan != ''): + WOFileUtils.searchreplace(self, + "{0}22222/htdocs/index.php" .format(WOVariables.wo_webroot), "eth0", - "{0}".format(WOVariables.wo_wan)) - + "{0}".format(wo_wan)) Log.debug(self, "Setting Privileges to " "{0}22222/htdocs" .format(WOVariables.wo_webroot)) @@ -1306,7 +1272,8 @@ class WOStackController(CementBaseController): .format(WOVariables.wo_webroot)) WOExtract.extract(self, '/var/lib/wo/tmp/extplorer.tar.gz', '/var/lib/wo/tmp/') - shutil.move('/var/lib/wo/tmp/extplorer-2.1.11', + shutil.move('/var/lib/wo/tmp/extplorer-{0}' + .format(WOVariables.wo_extplorer), '{0}22222/htdocs/files' .format(WOVariables.wo_webroot)) Log.debug(self, "Setting Privileges to " @@ -1386,6 +1353,7 @@ class WOStackController(CementBaseController): '/anemometer/install.sql' .format(WOVariables.wo_webroot)) except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) raise SiteError("Unable to import Anemometer database") WOMysql.execute(self, 'grant select on' @@ -1425,7 +1393,8 @@ class WOStackController(CementBaseController): # phpredisadmin if any('/var/lib/wo/tmp/pra.tar.gz' == x[1] for x in packages): - if not os.path.exists('{0}22222/htdocs/cache/redis' + if not os.path.exists('{0}22222/htdocs/cache/' + 'redis/phpRedisAdmin' .format(WOVariables.wo_webroot)): Log.debug(self, "Creating new directory " "{0}22222/htdocs/cache/redis" @@ -1572,6 +1541,7 @@ class WOStackController(CementBaseController): "/master/mysqltuner.pl", "/usr/bin/mysqltuner", "MySQLTuner"]] + else: Log.debug(self, "MySQL connection is already alive") Log.info(self, "MySQL connection is already alive") @@ -1636,7 +1606,8 @@ class WOStackController(CementBaseController): # PHPREDISADMIN if self.app.pargs.phpredisadmin: - if not os.path.isdir('/var/www/22222/htdocs/cache/redis'): + if not os.path.isdir('/var/www/22222/htdocs/' + 'cache/redis/phpRedisAdmin'): Log.debug( self, "Setting packages variable for phpRedisAdmin") self.app.pargs.composer = True @@ -1652,11 +1623,9 @@ class WOStackController(CementBaseController): # ADMINER if self.app.pargs.adminer: - if not os.path.isdir('{0}22222/htdocs/db/adminer' - .format(WOVariables.wo_webroot)): - Log.debug(self, "Setting packages variable for Adminer ") - packages = packages + [["https://github.com/vrana/adminer/" - "releases/download/v{0}" + Log.debug(self, "Setting packages variable for Adminer ") + packages = packages + [["https://github.com/vrana/adminer/" + "releases/download/v{0}" "/adminer-{0}.php" .format(WOVariables.wo_adminer), "{0}22222/" @@ -1667,12 +1636,9 @@ class WOStackController(CementBaseController): "/vrana/adminer/master/designs/" "pepa-linha/adminer.css", "{0}22222/" - "htdocs/db/adminer/adminer.css" - .format(WOVariables.wo_webroot), - "Adminer theme"]] - else: - Log.debug(self, "Adminer already installed") - Log.info(self, "Adminer already installed") + "htdocs/db/adminer/adminer.css" + .format(WOVariables.wo_webroot), + "Adminer theme"]] # Netdata if self.app.pargs.netdata: @@ -1698,7 +1664,8 @@ class WOStackController(CementBaseController): "/var/lib/wo/tmp/wo-dashboard.tar.gz", "WordOps Dashboard"], ["https://github.com/soerennb/" - "extplorer/archive/v2.1.11.tar.gz", + "extplorer/archive/v{0}.tar.gz" + .format(WOVariables.wo_extplorer), "/var/lib/wo/tmp/extplorer.tar.gz", "eXtplorer"]] else: @@ -1748,13 +1715,18 @@ class WOStackController(CementBaseController): 'Anemometer'] ] except Exception as e: - pass + Log.debug(self, "{0}".format(e)) if (apt_packages) or (packages): Log.debug(self, "Calling pre_pref") self.pre_pref(apt_packages) if (apt_packages): - WOSwap.add(self) + meminfo = (os.popen('cat /proc/meminfo ' + '| grep MemTotal').read()).split(":") + memsplit = re.split(" kB", meminfo[1]) + wo_mem = int(memsplit[0]) + if (wo_mem < 4000000): + WOSwap.add(self) Log.info(self, "Updating apt-cache, please wait...") WOAptGet.update(self) Log.info(self, "Installing packages, please wait...") @@ -1773,40 +1745,123 @@ class WOStackController(CementBaseController): WOShellExec.cmd_exec(self, "systemctl enable redis-server") if os.path.isfile("/etc/redis/redis.conf"): wo_ram = psutil.virtual_memory().total / (1024 * 1024) - wo_swap = psutil.swap_memory().total / (1024 * 1024) - if wo_ram < 512: + if wo_ram < 1024: Log.debug(self, "Setting maxmemory variable to " "{0} in redis.conf" .format(int(wo_ram*1024*1024*0.1))) - WOShellExec.cmd_exec(self, "sed -i 's/# maxmemory" - " /maxmemory {0}/'" - " /etc/redis/redis.conf" - .format(int(wo_ram*1024*1024*0.1))) + WOFileUtils.searchreplace(self, + "/etc/redis/redis.conf", + "# maxmemory ", + "maxmemory {0}" + .format + (int(wo_ram*1024*1024*0.1))) Log.debug( self, "Setting maxmemory-policy variable to " "allkeys-lru in redis.conf") - WOShellExec.cmd_exec(self, "sed -i 's/# maxmemory-" - "policy.*/maxmemory-policy " - "allkeys-lru/' " - "/etc/redis/redis.conf") + WOFileUtils.searchreplace(self, + "/etc/redis/redis.conf", + "# maxmemory-policy " + "noeviction", + "maxmemory-policy " + "allkeys-lru") + Log.debug( + self, "Setting tcp-backlog variable to " + "in redis.conf") + WOFileUtils.searchreplace(self, + "/etc/redis/redis.conf", + "tcp-backlog 511", + "tcp-backlog 32768") WOService.restart_service(self, 'redis-server') else: Log.debug(self, "Setting maxmemory variable to {0} " "in redis.conf" .format(int(wo_ram*1024*1024*0.2))) - WOShellExec.cmd_exec(self, "sed -i 's/# maxmemory " - "/maxmemory {0}/' " - "/etc/redis/redis.conf" - .format(int(wo_ram*1024*1024*0.2))) + WOFileUtils.searchreplace(self, + "/etc/redis/redis.conf", + "# maxmemory ", + "maxmemory {0}" + .format + (int(wo_ram*1024*1024*0.1))) Log.debug( self, "Setting maxmemory-policy variable " "to allkeys-lru in redis.conf") - WOShellExec.cmd_exec(self, "sed -i 's/# maxmemory-" - "policy.*/maxmemory-policy " - "allkeys-lru/' " - "/etc/redis/redis.conf") + WOFileUtils.searchreplace(self, + "/etc/redis/redis.conf", + "# maxmemory-policy " + "noeviction", + "maxmemory-policy " + "allkeys-lru") WOService.restart_service(self, 'redis-server') + if 'mariadb-server' in apt_packages: + # setting innodb memory usage + wo_ram = psutil.virtual_memory().total / (1024 * 1024) + wo_ram_innodb = int(wo_ram*0.3) + wo_ram_log_buffer = int(wo_ram_innodb*0.25) + wo_ram_log_size = int(wo_ram_log_buffer*0.5) + # replacing default values + if os.path.isfile("/etc/mysql/my.cnf"): + Log.debug(self, "Tuning MySQL configuration") + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "innodb_buffer_pool_size = 256M", + "innodb_buffer_pool_size = {0}M" + .format(wo_ram_innodb)) + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "innodb_log_buffer_size = 8M", + "innodb_log_buffer_size = {0}M" + .format(wo_ram_log_buffer)) + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "#innodb_log_file_size = 50M", + "innodb_log_file_size = {0}M" + .format(wo_ram_log_size)) + WOFileUtils.searchreplace(self, + "/etc/mysql/my.cnf", + "wait_timeout " + "= 600", + "wait_timeout " + "= 120") + # disabling mariadb binlog + WOFileUtils.searchreplace(self, + "/etc/mysql/my.cnf", + "log_bin " + "= /var/log/mysql/" + "mariadb-bin", + "#log_bin " + " = /var/log/" + "mysql/mariadb-bin") + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + 'log_bin_index ' + "= /var/log/mysql/" + "mariadb-bin.index", + "#log_bin_index " + "= /var/log/mysql/" + "mariadb-bin.index") + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "expire_logs_days = 10", + "#expire_logs_days " + "= 10") + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "max_binlog_size " + "= 100M", + "#max_binlog_size " + "= 100M") + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "innodb_open_files =" + " 400", + "innodb_open_files =" + " 16000") + WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", + "innodb_io_capacity =" + " 400", + "innodb_io_capacity =" + " 16000") + WOService.stop_service(self, 'mysql') + WOFileUtils.mvfile(self, '/var/lib/mysql/ib_logfile0', + '/var/lib/mysql/ib_logfile0.bak') + WOFileUtils.mvfile(self, '/var/lib/mysql/ib_logfile1', + '/var/lib/mysql/ib_logfile1.bak') + WOService.start_service(self, 'mysql') + if disp_msg: if (self.msg): for msg in self.msg: @@ -2081,24 +2136,18 @@ class WOStackController(CementBaseController): WOVariables.wo_php_extra else: apt_packages = apt_packages + WOVariables.wo_php73 - else: - Log.error(self, "Cannot Purge PHP 7.3. not found.") # fail2ban if self.app.pargs.fail2ban: if WOAptGet.is_installed(self, 'fail2ban'): Log.debug(self, "Purge apt_packages variable of Fail2ban") apt_packages = apt_packages + WOVariables.wo_fail2ban - else: - Log.error(self, "Fail2ban not found") # proftpd if self.app.pargs.proftpd: if WOAptGet.is_installed(self, 'proftpd-basic'): Log.debug(self, "Purge apt_packages variable for ProFTPd") apt_packages = apt_packages + ["proftpd-basic"] - else: - Log.error(self, "ProFTPd not found") # WP-CLI if self.app.pargs.wpcli: diff --git a/wo/cli/plugins/stack_migrate.py b/wo/cli/plugins/stack_migrate.py index 38bb394..a81d2b4 100644 --- a/wo/cli/plugins/stack_migrate.py +++ b/wo/cli/plugins/stack_migrate.py @@ -6,7 +6,6 @@ from wo.core.variables import WOVariables from wo.core.aptget import WOAptGet from wo.core.shellexec import WOShellExec from wo.core.apt_repo import WORepo -from wo.core.services import WOService import configparser import os diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index 7f3e4f8..0344c09 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -9,7 +9,6 @@ from wo.core.fileutils import WOFileUtils from wo.core.shellexec import WOShellExec from wo.core.extract import WOExtract from wo.core.download import WODownload -import configparser import os import shutil @@ -50,7 +49,7 @@ class WOStackUpgradeController(CementBaseController): @expose(hide=True) def upgrade_php56(self): - if WOVariables.wo_platform_distro == "ubuntu": + if WOVariables.wo_distro == "ubuntu": if os.path.isfile("/etc/apt/sources.list.d/ondrej-php5-5_6-{0}." "list".format(WOVariables.wo_platform_codename)): Log.error(self, "Unable to find PHP 5.5") @@ -69,7 +68,7 @@ class WOStackUpgradeController(CementBaseController): if start_upgrade != "Y" and start_upgrade != "y": Log.error(self, "Not starting PHP package update") - if WOVariables.wo_platform_distro == "ubuntu": + if WOVariables.wo_distro == "ubuntu": WORepo.remove(self, ppa="ppa:ondrej/php5") WORepo.add(self, ppa=WOVariables.wo_php_repo) diff --git a/wo/cli/templates/kerneltweaks-service.mustache b/wo/cli/templates/kerneltweaks-service.mustache deleted file mode 100644 index 60f8de9..0000000 --- a/wo/cli/templates/kerneltweaks-service.mustache +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Linux kernel tweaks - -# append here other services you want netdata to wait for them to start -After=network.target - -[Service] -Type=simple -User=root -ExecStart=/opt/kerneltweaks.sh - -[Install] -WantedBy=multi-user.target diff --git a/wo/cli/templates/nginx-core.mustache b/wo/cli/templates/nginx-core.mustache index e262d87..dd4631e 100644 --- a/wo/cli/templates/nginx-core.mustache +++ b/wo/cli/templates/nginx-core.mustache @@ -1,61 +1,193 @@ -## -# WordOps Settings -## +user www-data; +worker_processes auto; +worker_cpu_affinity auto; +worker_rlimit_nofile 100000; +pid /run/nginx.pid; -server_tokens off; -reset_timedout_connection on; -add_header X-Powered-By "WordOps {{version}}"; +pcre_jit on; -# Limit Request -limit_req_status 403; -limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; - -# Proxy Settings -# set_real_ip_from proxy-server-ip; -# real_ip_header X-Forwarded-For; - -fastcgi_read_timeout 300; -client_max_body_size 100m; - -# SSL Settings -ssl_protocols TLSv1.2; -ssl_ciphers 'EECDH+CHACHA20:EECDH+AESGCM:EECDH+AES'; -ssl_session_cache shared:SSL:50m; -ssl_session_timeout 1d; -ssl_session_tickets off; -{{#Ubuntu}} -ssl_prefer_server_ciphers on; -{{/Ubuntu}} - -# Log format Settings -log_format rt_cache '$remote_addr $upstream_response_time $upstream_cache_status [$time_local] ' -'$http_host "$request" $status $body_bytes_sent ' -'"$http_referer" "$http_user_agent"'; +events { + multi_accept on; + worker_connections 50000; + accept_mutex on; + use epoll; +} -# GZip settings -gzip_vary on; -gzip_proxied any; -gzip_comp_level 6; -gzip_buffers 16 8k; -gzip_http_version 1.1; -# Compress all output labeled with one of the following MIME-types. -gzip_types +http { + ## + # WordOps Settings + ## + + sendfile on; + sendfile_max_chunk 512k; + + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 8; + keepalive_requests 500; + keepalive_disable msie6; + + lingering_time 20s; + lingering_timeout 5s; + + # Nginx AIO : See - https://www.nginx.com/blog/thread-pools-boost-performance-9x/ + # http://nginx.org/en/docs/http/ngx_http_core_module.html#aio + aio threads; + + server_tokens off; + reset_timedout_connection on; + more_set_headers "X-Powered-By : WordOps"; + + # Limit Request + limit_req_status 403; + limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; + + # Proxy Settings + # set_real_ip_from proxy-server-ip; + # real_ip_header X-Forwarded-For; + + fastcgi_read_timeout 300; + client_max_body_size 100m; + + # ngx_vts_module + vhost_traffic_status_zone; + + # tls dynamic records patch directive + ssl_dyn_rec_enable on; + + + ## + # SSL Settings + ## + + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_prefer_server_ciphers on; + ssl_ciphers 'TLS13+AESGCM+AES256:TLS13+AESGCM+AES128:TLS13+CHACHA20:EECDH+AESGCM:EECDH+CHACHA20'; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ecdh_curve X25519:P-521:P-384:P-256; + # Previous TLS v1.2 configuration + # ssl_protocols TLSv1.2; + # ssl_ciphers EECDH+CHACHA20:EECDH+AESGCM:EECDH+AES; + + # Common security headers + more_set_headers "X-Frame-Options : SAMEORIGIN"; + more_set_headers "X-Xss-Protection : 1; mode=block"; + more_set_headers "X-Content-Type-Options : nosniff"; + more_set_headers "Referrer-Policy : strict-origin-when-cross-origin"; + more_set_headers "X-Download-Options : noopen"; + + # oscp settings + resolver 8.8.8.8 1.1.1.1 8.8.4.4 1.0.0.1 valid=300s; + resolver_timeout 10; + ssl_stapling on; + + ## + # Basic Settings + ## + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # Logging Settings + ## + + access_log off; + error_log /var/log/nginx/error.log; + + # Log format Settings + log_format rt_cache '$remote_addr $upstream_response_time $upstream_cache_status [$time_local] ' + '$http_host "$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" "$server_protocol"'; + + ## + # Gzip Settings + ## + + # mitigation for CRIME/BREACH attacks + gzip off; + + ## + # Brotli Settings + ## + + brotli on; + brotli_static on; + brotli_buffers 16 8k; + brotli_min_length 64000; + brotli_comp_level 4; + brotli_types application/atom+xml + application/geo+json application/javascript application/json + application/ld+json + application/manifest+json + application/rdf+xml application/rss+xml application/vnd.ms-fontobject + application/wasm + application/x-font-opentype + application/x-font-truetype application/x-font-ttf + application/x-javascript application/x-web-app-manifest+json application/xhtml+xml application/xml + application/xml+rss + font/eot font/opentype + font/otf + image/bmp image/svg+xml + image/vnd.microsoft.icon image/x-icon + image/x-win-bitmap + text/cache-manifest + text/calendar text/css + text/javascript + text/markdown text/plain + text/vcard + text/vnd.rim.location.xloc + text/vtt text/x-component - text/xml - text/javascript; - # text/html is always compressed by HttpGzipModule + text/x-cross-domain-policy + text/xml; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} + + +#mail { +# # See sample authentication script at: +# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript +# +# # auth_http localhost/auth.php; +# # pop3_capabilities "TOP" "USER"; +# # imap_capabilities "IMAP4rev1" "UIDPLUS"; +# +# server { +# listen localhost:110; +# protocol pop3; +# proxy on; +# } +# +# server { +# listen localhost:143; +# protocol imap; +# proxy on; +# } +#} diff --git a/wo/cli/templates/proftpd-tls.mustache b/wo/cli/templates/proftpd-tls.mustache new file mode 100644 index 0000000..6e3f9cf --- /dev/null +++ b/wo/cli/templates/proftpd-tls.mustache @@ -0,0 +1,12 @@ + +TLSEngine on +TLSLog /var/log/proftpd/tls.log +TLSProtocol TLSv1.2 +TLSCipherSuite AES256+EECDH:AES256+EDH +TLSOptions NoCertRequest AllowClientRenegotiations NoSessionReuseRequired +TLSRSACertificateFile /etc/proftpd/ssl/proftpd.crt +TLSRSACertificateKeyFile /etc/proftpd/ssl/proftpd.key +TLSVerifyClient off +TLSRequired on +RequireValidShell no + \ No newline at end of file diff --git a/wo/cli/templates/upstream.mustache b/wo/cli/templates/upstream.mustache index 26e06b9..686a6a5 100644 --- a/wo/cli/templates/upstream.mustache +++ b/wo/cli/templates/upstream.mustache @@ -74,3 +74,13 @@ upstream netdata { server 127.0.0.1:19999; keepalive 64; } + +#------------------------------- +# Redis +#------------------------------- + +# Redis cache upstream +upstream redis { + server 127.0.0.1:6379; + keepalive 10; +} diff --git a/wo/cli/templates/kerneltweaks-script.mustache b/wo/cli/templates/wo-kernel-script.mustache similarity index 52% rename from wo/cli/templates/kerneltweaks-script.mustache rename to wo/cli/templates/wo-kernel-script.mustache index 4071530..581a70d 100644 --- a/wo/cli/templates/kerneltweaks-script.mustache +++ b/wo/cli/templates/wo-kernel-script.mustache @@ -1,7 +1,9 @@ #!/usr/bin/env bash -# Kernel tweak script launched by kerneltweak systemd service -# script path after installation /opt/kerneltweaks.sh +# WordOps Kernel tweaks script +# script path after installation /opt/wo-kernel.sh +# Netdata Memory tweak echo 1 >/sys/kernel/mm/ksm/run echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs +# Redis disable transparent_hugepage echo never > /sys/kernel/mm/transparent_hugepage/enabled diff --git a/wo/cli/templates/wo-kernel-service.mustache b/wo/cli/templates/wo-kernel-service.mustache new file mode 100644 index 0000000..f64f650 --- /dev/null +++ b/wo/cli/templates/wo-kernel-service.mustache @@ -0,0 +1,14 @@ +[Unit] +Description=WordOps kernel tweaks +# append here other services you want netdata to wait for them to start +After=syslog.target network.target remote-fs.target nss-lookup.target + +[Service] +Type=simple +User=root +ExecStart=/opt/wo-kernel.sh +StandardOutput=null + +[Install] +WantedBy=multi-user.target +Alias=wo-kernel.service \ No newline at end of file diff --git a/wo/core/addswap.py b/wo/core/addswap.py index 02df054..ad0c14c 100644 --- a/wo/core/addswap.py +++ b/wo/core/addswap.py @@ -1,5 +1,4 @@ """WordOps Swap Creation""" -from wo.core.variables import WOVariables from wo.core.shellexec import WOShellExec from wo.core.fileutils import WOFileUtils from wo.core.aptget import WOAptGet diff --git a/wo/core/aptget.py b/wo/core/aptget.py index 75e0e11..ce66dff 100644 --- a/wo/core/aptget.py +++ b/wo/core/aptget.py @@ -1,6 +1,5 @@ """WordOps package installation using apt-get module.""" import apt -import apt_pkg import sys import subprocess from wo.core.logging import Log @@ -74,6 +73,7 @@ class WOAptGet(): stdout=sys.stdout).communicate() except Exception as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to check for packages upgrades") def dist_upgrade(self): @@ -105,6 +105,7 @@ class WOAptGet(): "`tail /var/log/wo/wordops.log` " "and please try again...") except Exception as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Error while installing packages, " "apt-get exited with error") @@ -135,6 +136,7 @@ class WOAptGet(): "and please try again...") except Exception as e: + Log.debug(self, "{0}".format(e)) Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " @@ -168,6 +170,7 @@ class WOAptGet(): "and please try again...") except Exception as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Error while installing packages, " "apt-get exited with error") @@ -244,5 +247,6 @@ class WOAptGet(): WORepo.remove(self, repo_url=repo_url) return False except Exception as e: + Log.debug(self, "{0}".format(e)) Log.error(self, "Error while downloading packages, " "apt-get exited with error") diff --git a/wo/core/checkfqdn.py b/wo/core/checkfqdn.py index 9add740..c9d4ff1 100644 --- a/wo/core/checkfqdn.py +++ b/wo/core/checkfqdn.py @@ -1,6 +1,5 @@ from wo.core.shellexec import WOShellExec from wo.core.variables import WOVariables -import os def check_fqdn(self, wo_host): @@ -13,7 +12,7 @@ def check_fqdn(self, wo_host): WOShellExec.cmd_exec(self, "sed -i \"1i\\127.0.0.1 {0}\" /etc/hosts" .format(wo_host)) - if WOVariables.wo_platform_distro == 'debian': + if WOVariables.wo_distro == 'debian': WOShellExec.cmd_exec(self, "/etc/init.d/hostname.sh start") else: WOShellExec.cmd_exec(self, "service hostname restart") diff --git a/wo/core/download.py b/wo/core/download.py index 36d3d7a..d81b277 100644 --- a/wo/core/download.py +++ b/wo/core/download.py @@ -33,12 +33,12 @@ class WODownload(): Log.error(self, "Unable to download file, {0}" .format(filename)) return False - except urllib.error.HTTPError as e: + except urllib.HTTPError.error as e: Log.error(self, "Package download failed. {0}" .format(pkg_name)) Log.debug(self, "[{err}]".format(err=str(e.reason))) return False - except urllib.error.ContentTooShortError as e: + except urllib.ContentTooShortError.error as e: Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) Log.error(self, "Package download failed. The amount of the" " downloaded data is less than " diff --git a/wo/core/fileutils.py b/wo/core/fileutils.py index a7a4c29..efc13c6 100644 --- a/wo/core/fileutils.py +++ b/wo/core/fileutils.py @@ -1,9 +1,6 @@ """WordOps file utils core classes.""" import shutil import os -import sys -import glob -import shutil import pwd import fileinput from wo.core.logging import Log diff --git a/wo/core/mysql.py b/wo/core/mysql.py index c289405..e168e85 100644 --- a/wo/core/mysql.py +++ b/wo/core/mysql.py @@ -1,9 +1,7 @@ """WordOps MySQL core classes.""" import pymysql from pymysql import connections, DatabaseError, Error -import configparser from os.path import expanduser -import sys import os from wo.core.logging import Log from wo.core.variables import WOVariables diff --git a/wo/core/nginxhashbucket.py b/wo/core/nginxhashbucket.py index a4ec755..921fe1f 100644 --- a/wo/core/nginxhashbucket.py +++ b/wo/core/nginxhashbucket.py @@ -3,7 +3,6 @@ from wo.core.fileutils import WOFileUtils import math import os import fileinput -import re import subprocess diff --git a/wo/core/services.py b/wo/core/services.py index a6e4c04..e47aca1 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -1,10 +1,8 @@ """WordOps Service Manager""" -import os -import sys import subprocess from subprocess import Popen from wo.core.logging import Log -import pystache + class WOService(): diff --git a/wo/core/shellexec.py b/wo/core/shellexec.py index 77b3dcf..77ba8a5 100644 --- a/wo/core/shellexec.py +++ b/wo/core/shellexec.py @@ -1,7 +1,5 @@ """WordOps Shell Functions""" from wo.core.logging import Log -import os -import sys import subprocess @@ -37,11 +35,11 @@ class WOShellExec(): .format(cmd_stdout, cmd_stderr)) return False except OSError as e: - Log.debug(self, str(e)) - raise CommandExecutionError + Log.debug(self, str(e)) + raise CommandExecutionError except Exception as e: - Log.debug(self, str(e)) - raise CommandExecutionError + Log.debug(self, str(e)) + raise CommandExecutionError def invoke_editor(self, filepath, errormsg=''): """ diff --git a/wo/core/variables.py b/wo/core/variables.py index 750bf7f..cf3474e 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -3,7 +3,6 @@ import platform import socket import configparser import os -import psutil import datetime @@ -11,32 +10,25 @@ class WOVariables(): """Intialization of core variables""" # WordOps version - wo_version = "3.9.6.2" + wo_version = "3.9.7" # WordOps packages versions wo_wp_cli = "2.2.0" - wo_adminer = "4.7.1" + wo_adminer = "4.7.2" wo_phpmyadmin = "4.9.0.1" + wo_extplorer = "2.1.13" # Get WPCLI path - wo_wpcli_path = os.popen('command -v wp | tr "\n" " "').read() - if wo_wpcli_path == '': - wo_wpcli_path = '/usr/local/bin/wp ' - - # get wan network interface name - wo_wan = os.popen("/sbin/ip -4 route get 8.8.8.8 | " - "grep -oP \"dev [^[:space:]]+ \" " - "| cut -d ' ' -f 2").read() - if wo_wan == '': - wo_wan = 'eth0' + wo_wpcli_path = '/usr/local/bin/wp' # Current date and time of System wo_date = datetime.datetime.now().strftime('%d%b%Y%H%M%S') # WordOps core variables - wo_platform_distro = os.popen("lsb_release -si " - "| tr -d \'\\n\'").read().lower() + wo_distro = os.popen("/usr/bin/lsb_release -si " + "| tr -d \'\\n\'").read().lower() wo_platform_version = platform.linux_distribution()[1] - wo_platform_codename = os.popen("lsb_release -sc | tr -d \'\\n\'").read() + wo_platform_codename = os.popen( + "/usr/bin/lsb_release -sc | tr -d \'\\n\'").read() # Get timezone of system if os.path.isfile('/etc/timezone'): @@ -68,7 +60,7 @@ class WOVariables(): try: wo_user = config['user']['name'] wo_email = config['user']['email'] - except Exception as e: + except Exception: wo_user = input("Enter your name: ") wo_email = input("Enter your email: ") os.system("/usr/bin/git config --global user.name {0}".format(wo_user)) @@ -85,21 +77,16 @@ class WOVariables(): if [cnfpath] == config.read(cnfpath): try: wo_mysql_host = config.get('client', 'host') - except configparser.NoOptionError as e: + except configparser.NoOptionError: wo_mysql_host = "localhost" else: wo_mysql_host = "localhost" # WordOps stack installation variables # Nginx repo and packages - if wo_platform_distro == 'ubuntu': - if wo_platform_codename == 'trusty': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/xUbuntu_14.04/ /") - else: - wo_nginx_repo = "ppa:wordops/nginx-wo" - elif wo_platform_distro == 'debian': + if wo_distro == 'ubuntu': + wo_nginx_repo = "ppa:wordops/nginx-wo" + elif wo_distro == 'debian': if wo_platform_codename == 'jessie': wo_nginx_repo = ("deb http://download.opensuse.org" "/repositories/home:" @@ -120,7 +107,7 @@ class WOVariables(): wo_nginx_key = '188C9FB063F0247A' # PHP repo and packages - if wo_platform_distro == 'ubuntu': + if wo_distro == 'ubuntu': wo_php_repo = "ppa:ondrej/php" wo_php = ["php7.2-fpm", "php7.2-curl", "php7.2-gd", "php7.2-imap", "php7.2-readline", "php7.2-common", "php7.2-recode", @@ -156,7 +143,7 @@ class WOVariables(): wo_php_key = 'AC0E47584A7A714D' # MySQL repo and packages - if wo_platform_distro == 'ubuntu': + if wo_distro == 'ubuntu': wo_mysql_repo = ("deb [arch=amd64,ppc64el] " "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/ubuntu {codename} main" @@ -166,12 +153,17 @@ class WOVariables(): "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/debian {codename} main" .format(codename=wo_platform_codename)) - wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] - wo_fail2ban = ["fail2ban", "python3-pyinotify"] + if wo_platform_codename == 'jessie': + wo_mysql = ["mariadb-server", "percona-toolkit", + "python3-mysql.connector"] + else: + wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] + + wo_fail2ban = ["fail2ban"] # Redis repo details - if wo_platform_distro == 'ubuntu': + if wo_distro == 'ubuntu': wo_redis_repo = ("ppa:chris-lea/redis-server") else: