diff --git a/.travis.yml b/.travis.yml index de3333cd..f2a02038 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ notifications: - slack: rtcamp:MGteQ7CA6kFIsNbMIarkeWxa + slack: easyengine:76AI30tP8P8AcNTaWaQ9ZAT7 webhooks: urls: - https://webhooks.gitter.im/e/bd77a26eab56de803949 diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c29d5aba..d990aedb 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,16 @@ +v3.4.0 - Jan 6, 2015 +- Added Let's Encrypt support + - ee site create example.com [--wp/..] --letsencrypt + - ee site update example.com --letsencrypt=on/off/renew + - Automatic renew of certs through cron + - Mail notification added on certs renew + - Alias command: --le +- Added HTTP/2 support + - ee stack install/remove/purge --nginxmainline +- Check SSL cert status/expiry date in site info + - ee site info example.com +- Update autocompletion and man page + v3.3.15 - Dec 9, 2015 - Upgrade wp-cli version to 0.21.1 diff --git a/config/bash_completion.d/ee_auto.rc b/config/bash_completion.d/ee_auto.rc index 0b7011cc..14b62d95 100644 --- a/config/bash_completion.d/ee_auto.rc +++ b/config/bash_completion.d/ee_auto.rc @@ -74,7 +74,7 @@ _ee_complete() # HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE "install" | "purge" | "remove" ) COMPREPLY=( $(compgen \ - -W "--pagespeed --web --admin --mail --nginx --php --mysql --postfix --wpcli --phpmyadmin --adminer --utils --all --mailscanner --hhvm --redis --phpredisadmin" \ + -W "--pagespeed --web --admin --mail --nginx --nginxmainline --php --mysql --postfix --wpcli --phpmyadmin --adminer --utils --all --mailscanner --hhvm --redis --phpredisadmin" \ -- $cur) ) ;; "upgrade" ) @@ -165,13 +165,13 @@ _ee_complete() "create") COMPREPLY=( $(compgen \ - -W "--user --pass --email --html --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --proxy= --pagespeed --wpredis" \ + -W "--user --pass --email --html --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --proxy= --pagespeed --wpredis --letsencrypt -le" \ -- $cur) ) ;; "update") COMPREPLY=( $(compgen \ - -W "--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --hhvm=off --pagespeed --pagespeed=off --wpredis" \ + -W "--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --hhvm=off --pagespeed --pagespeed=off --wpredis --letsencrypt --letsencrypt=off --letsencrypt=renew" \ -- $cur) ) ;; "delete") @@ -217,9 +217,9 @@ _ee_complete() "--wp") if [ ${COMP_WORDS[1]} != "debug" ]; then if [ ${COMP_WORDS[2]} == "create" ]; then - retlist="--wp --wpsc --w3tc --wpfc --pagespeed --hhvm --user --email --pass --wpredis" + retlist="--wp --wpsc --w3tc --wpfc --pagespeed --hhvm --user --email --pass --wpredis --letsencrypt" elif [ ${COMP_WORDS[2]} == "update" ]; then - retlist="--wp --w3tc --wpfc --wpsc --pagespeed --hhvm --pagespeed=off --hhvm=off --wpredis" + retlist="--wp --w3tc --wpfc --wpsc --pagespeed --hhvm --pagespeed=off --hhvm=off --wpredis --letsencrypt --letsencrypt=off --letsencrypt=renew" else retlist="" fi @@ -236,9 +236,9 @@ _ee_complete() "--wpsubdir" | "--wpsubdomain") if [ ${COMP_WORDS[1]} != "debug" ]; then if [ ${COMP_WORDS[2]} == "create" ]; then - retlist="--wpsc --w3tc --wpfc --pagespeed --hhvm --user --email --pass --wpredis" + retlist="--wpsc --w3tc --wpfc --pagespeed --hhvm --user --email --pass --wpredis --letsencrypt" elif [ ${COMP_WORDS[2]} == "update" ]; then - retlist="--w3tc --wpfc --wpsc --pagespeed --hhvm --pagespeed=off --hhvm=off --wpredis" + retlist="--w3tc --wpfc --wpsc --pagespeed --hhvm --pagespeed=off --hhvm=off --wpredis --letsencrypt --letsencrypt=off --letsencrypt=renew" else retlist="" fi @@ -254,7 +254,7 @@ _ee_complete() "--pagespeed" | "--hhvm" | "--wpredis" | "--w3tc" | "--wpfc" | "--wpsc" | "--wpsubdir" | "--wpsubdomain" | "--user" | "--pass" | "--email" | "--wp") if [ ${COMP_WORDS[2]} == "create" ]; then - retlist="--user --pass --email --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --pagespeed --experimenal --wpredis" + retlist="--user --pass --email --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --pagespeed --experimenal --wpredis --letsencrypt" else retlist="" fi @@ -267,7 +267,7 @@ _ee_complete() "--pagespeed" | "--hhvm" | "--wpredis" | "--w3tc" | "--wpfc") if [ ${COMP_WORDS[2]} == "update" ]; then - retlist="--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --hhvm=off --pagespeed --pagespeed=off --experimenal --wpredis" + retlist="--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --hhvm=off --pagespeed --pagespeed=off --experimenal --wpredis --letsencrypt --letsencrypt=off --letsencrypt=renew" else retlist="" fi @@ -320,7 +320,7 @@ _ee_complete() elif [ ${COMP_WORDS[2]} == "delete" ]; then retlist="--db --files --force" elif [ ${COMP_WORDS[2]} == "update" ]; then - retlist="--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --hhvm=off --pagespeed --pagespeed=off --wpredis" + retlist="--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --hhvm=off --pagespeed --pagespeed=off --wpredis --letsencrypt --letsencrypt=off --letsencrypt=renew" else retlist="" fi @@ -369,7 +369,7 @@ _ee_complete() case "$mprev" in "--user" | "--email" | "--pass") if [ ${COMP_WORDS[2]} == "create" ]; then - retlist="--user --pass --email --html --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --pagespeed --wpredis" + retlist="--user --pass --email --html --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc --hhvm --pagespeed --wpredis --letsencrypt" fi ret="${retlist[@]/$prev}" COMPREPLY=( $(compgen \ diff --git a/docs/ee.8 b/docs/ee.8 index 7b5d0658..d437fb81 100644 --- a/docs/ee.8 +++ b/docs/ee.8 @@ -5,15 +5,15 @@ .SH SYNOPSIS ee [ --version | --help | info | stack | site | debug | update | clean | import_slow_log | log | secure | sync] .TP -ee stack [ install | remove | purge | migrate | upgrade] [ --web | --mail | --all | --nginx | --php | --mysql | --admin | --postfix | --mailscanner | --adminer | --redis | --hhvm | --phpmyadmin | --phpredisadmin | --wpcli | --utils ] +ee stack [ install | remove | purge | migrate | upgrade] [ --web | --mail | --all | --nginx | --nginxmainline | --php | --mysql | --admin | --postfix | --mailscanner | --adminer | --redis | --hhvm | --phpmyadmin | --phpredisadmin | --wpcli | --utils ] .TP ee stack [ status | start | stop | reload | restart ] [--all | --nginx | --php | --mysql | --devcot | --web | --postfix | --memcache | --redis] .TP ee site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ] .TP -ee site create example.com [ --html | --php | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --w3tc | --wpfc | --wpredis | --hhvm | --pagespeed ]] +ee site create example.com [ --html | --php | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --w3tc | --wpfc | --wpredis | --hhvm | --pagespeed | --letsencrypt/-le]] .TP -ee site update example.com [ --php | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --w3tc | --wpfc | --wpredis | --hhvm | --pagespeed ] [--password]] +ee site update example.com [ --php | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --w3tc | --wpfc | --wpredis | --hhvm | --pagespeed ] [--password] [--letsencrypt=on/off/renew]] .TP ee site delete example.com [--db | --files | --all | --no-prompt | --force/-f ] .TP @@ -307,12 +307,12 @@ Report bugs at .B Harshad .I \ .br -.B Shital -.I \ -.br .B Prabuddha .I \ .br +.B Shital +.I \ +.br .B Rajdeep Sharma .I \ .br diff --git a/ee/cli/plugins/secure.py b/ee/cli/plugins/secure.py index ee1f069f..b10b09a6 100644 --- a/ee/cli/plugins/secure.py +++ b/ee/cli/plugins/secure.py @@ -1,5 +1,6 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook +from ee.core.aptget import EEAptGet from ee.core.shellexec import EEShellExec from ee.core.variables import EEVariables from ee.core.logging import Log @@ -95,14 +96,16 @@ class EESecureController(CementBaseController): self.app.pargs.user_input = port if EEVariables.ee_platform_distro == 'ubuntu': EEShellExec.cmd_exec(self, "sed -i \"s/listen.*/listen " - "{port} default_server ssl spdy;/\" " + "{port} default_server ssl {http2};/\" " "/etc/nginx/sites-available/22222" - .format(port=self.app.pargs.user_input)) + .format(port=self.app.pargs.user_input,http2=("http2" if + EEAptGet.is_installed(self,'nginx-mainline') else "spdy"))) if EEVariables.ee_platform_distro == 'debian': EEShellExec.cmd_exec(self, "sed -i \"s/listen.*/listen " - "{port} default_server ssl;/\" " + "{port} default_server ssl {http2};/\" " "/etc/nginx/sites-available/22222" - .format(port=self.app.pargs.user_input)) + .format(port=self.app.pargs.user_input,http2=("http2" if + EEAptGet.is_installed(self,'nginx-mainline') else "spdy"))) EEGit.add(self, ["/etc/nginx"], msg="Adding changed secure port into Git") if not EEService.reload_service(self, 'nginx'): diff --git a/ee/cli/plugins/site.py b/ee/cli/plugins/site.py index 45c8709c..1be91214 100644 --- a/ee/cli/plugins/site.py +++ b/ee/cli/plugins/site.py @@ -1,6 +1,8 @@ # """EasyEngine site controller.""" from cement.core.controller import CementBaseController, expose from cement.core import handler, hook +from ee.core.cron import EECron +from ee.core.sslutils import SSL from ee.core.variables import EEVariables from ee.core.domainvalidate import ValidateDomain from ee.core.fileutils import EEFileUtils @@ -155,11 +157,18 @@ class EESiteController(CementBaseController): ee_site_webroot = '' pagespeed = ("enabled" if siteinfo.is_pagespeed else "disabled") - + ssl = ("enabled" if siteinfo.is_ssl else "disabled") + if (ssl == "enabled"): + sslprovider = "Lets Encrypt" + sslexpiry = str(SSL.getExpirationDate(self,ee_domain)) + else: + sslprovider = '' + sslexpiry = '' data = dict(domain=ee_domain, webroot=ee_site_webroot, accesslog=access_log, errorlog=error_log, dbname=ee_db_name, dbuser=ee_db_user, dbpass=ee_db_pass, hhvm=hhvm, pagespeed=pagespeed, + ssl=ssl, sslprovider=sslprovider, sslexpiry= sslexpiry, type=sitetype + " " + cachetype + " ({0})" .format("enabled" if siteinfo.is_enabled else "disabled")) @@ -354,6 +363,8 @@ class EESiteCreateController(CementBaseController): dict(help="create HHVM site", action='store_true')), (['--pagespeed'], dict(help="create pagespeed site", action='store_true')), + (['-le','--letsencrypt'], + dict(help="configure letsencrypt ssl for the site", action='store_true')), (['--user'], dict(help="provide user for wordpress site")), (['--email'], @@ -717,6 +728,58 @@ class EESiteCreateController(CementBaseController): Log.error(self, "Check logs for reason " "`tail /var/log/ee/ee.log` & Try Again!!!") + if self.app.pargs.letsencrypt : + if (not self.app.pargs.experimental): + if stype in ['wpsubdomain']: + Log.warn(self, "Wildcard domains are not supported in Lets Encrypt.\nWP SUBDOMAIN site will get SSL for primary site only.") + + Log.info(self, "Letsencrypt is currently in beta phase." + " \nDo you wish" + " to enable SSl now for {0}?".format(ee_domain)) + + # Check prompt + check_prompt = input("Type \"y\" to continue [n]:") + if check_prompt != "Y" and check_prompt != "y": + data['letsencrypt'] = False + letsencrypt = False + else: + data['letsencrypt'] = True + letsencrypt = True + else: + data['letsencrypt'] = True + letsencrypt = True + + if data['letsencrypt'] is True: + setupLetsEncrypt(self, ee_domain) + httpsRedirect(self,ee_domain) + Log.info(self,"Creating Cron Job for cert auto-renewal") + EECron.setcron_daily(self,'ee site update {0} --le=renew --min_expiry_limit 30 2> /dev/null'.format(ee_domain),'Renew ' + 'letsencrypt SSL cert. Set by EasyEngine') + + if not EEService.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(ee_domain)) + + if (SSL.getExpirationDays(self,ee_domain)>0): + Log.info(self, "Your cert will expire within " + str(SSL.getExpirationDays(self,ee_domain)) + " days.") + else: + Log.warn(self, "Your cert already EXPIRED ! .PLEASE renew soon . ") + + # Add nginx conf folder into GIT + EEGit.add(self, ["{0}/conf/nginx".format(ee_site_webroot)], + msg="Adding letsencrypts config of site: {0}" + .format(ee_domain)) + updateSiteInfo(self, ee_domain, ssl=letsencrypt) + + elif data['letsencrypt'] is False: + Log.info(self, "Not using Let\'s encrypt for Site " + " http://{0}".format(ee_domain)) + + + class EESiteUpdateController(CementBaseController): class Meta: @@ -761,6 +824,12 @@ class EESiteUpdateController(CementBaseController): dict(help='Use PageSpeed for site', action='store' or 'store_const', choices=('on', 'off'), const='on', nargs='?')), + (['-le','--letsencrypt'], + dict(help="configure letsencrypt ssl for the site", + action='store' or 'store_const', + choices=('on', 'off', 'renew'), const='on', nargs='?')), + (['--min_expiry_limit'], + dict(help="pass minimum expiry days to renew let's encrypt cert")), (['--proxy'], dict(help="update to proxy site", nargs='+')), (['--experimental'], @@ -784,7 +853,7 @@ class EESiteUpdateController(CementBaseController): if not (pargs.php or pargs.mysql or pargs.wp or pargs.wpsubdir or pargs.wpsubdomain or pargs.w3tc or pargs.wpfc or - pargs.wpsc or pargs.hhvm or pargs.pagespeed or pargs.wpredis): + pargs.wpsc or pargs.hhvm or pargs.pagespeed or pargs.wpredis or pargs.letsencrypt): Log.error(self, "Please provide options to update sites.") if pargs.all: @@ -809,6 +878,7 @@ class EESiteUpdateController(CementBaseController): def doupdatesite(self, pargs): hhvm = None pagespeed = None + letsencrypt = False data = dict() try: @@ -826,7 +896,7 @@ class EESiteUpdateController(CementBaseController): proxyinfo = proxyinfo.split(':') host = proxyinfo[0].strip() port = '80' if len(proxyinfo) < 2 else proxyinfo[1].strip() - elif stype is None and not pargs.proxy: + elif stype is None and not (pargs.proxy or pargs.letsencrypt): stype, cache = 'html', 'basic' elif stype and pargs.proxy: Log.error(self, "--proxy can not be used with other site types") @@ -854,6 +924,7 @@ class EESiteUpdateController(CementBaseController): oldcachetype = check_site.cache_type old_hhvm = check_site.is_hhvm old_pagespeed = check_site.is_pagespeed + check_ssl = check_site.is_ssl if (pargs.password and not (pargs.html or pargs.php or pargs.mysql or pargs.wp or @@ -1007,6 +1078,7 @@ class EESiteUpdateController(CementBaseController): data['pagespeed'] = False pagespeed = False + if pargs.pagespeed: if pagespeed is old_pagespeed: if pagespeed is False: @@ -1017,6 +1089,66 @@ class EESiteUpdateController(CementBaseController): "site") pargs.pagespeed = False + #--letsencrypt=renew code goes here + if pargs.letsencrypt == "renew" and not pargs.min_expiry_limit: + if check_ssl: + renewLetsEncrypt(self,ee_domain) + else: + Log.error(self,"Cannot RENEW ! SSL is not configured for given site .") + + Log.info(self, "SUCCESS: Certificate was successfully renewed For" + " https://{0}".format(ee_domain)) + if (SSL.getExpirationDays(self,ee_domain)>0): + Log.info(self, "Your cert will expire within " + str(SSL.getExpirationDays(self,ee_domain)) + " days.") + Log.info(self, "Expiration DATE: " + str(SSL.getExpirationDate(self,ee_domain))) + + else: + Log.warn(self, "Your cert already EXPIRED ! .PLEASE renew soon . ") + + if pargs.min_expiry_limit: + if not int(pargs.min_expiry_limit)>0 or not int(pargs.min_expiry_limit)< 90: + Log.error(self,'INVALID --min_expiry_limit argument provided. Please use range 1-89 .') + + if not pargs.letsencrypt == "renew": + Log.error(self,'--min_expiry_limit parameter cannot be used as a standalone. Provide --le=renew') + + if not check_ssl: + Log.error(self,"Cannot RENEW ! SSL is not configured for given site .") + + expiry_days = SSL.getExpirationDays(self,ee_domain) + min_expiry_days = int(pargs.min_expiry_limit) + if (expiry_days <= min_expiry_days): + renewLetsEncrypt(self,ee_domain) + Log.info(self, "SUCCESS: Certificate was successfully renewed For" + " https://{0}".format(ee_domain)) + else: + Log.info(self, "Not renewing SSL .") + + if (SSL.getExpirationDays(self,ee_domain)>0): + Log.info(self, "Your cert will expire within " + str(SSL.getExpirationDays(self,ee_domain)) + " days.") + Log.info(self, "Expiration DATE: " + str(SSL.getExpirationDate(self,ee_domain))) + + else: + Log.warn(self, "Your cert already EXPIRED ! .PLEASE renew soon . ") + return 0 + + if pargs.letsencrypt: + if pargs.letsencrypt == 'on': + data['letsencrypt'] = True + letsencrypt = True + elif pargs.letsencrypt == 'off': + data['letsencrypt'] = False + letsencrypt = False + + if letsencrypt is check_ssl: + if letsencrypt is False: + Log.error(self, "SSl is not configured for given " + "site") + elif letsencrypt is True: + Log.error(self, "SSl is already configured for given " + "site") + pargs.letsencrypt = False + if pargs.hhvm: if hhvm is old_hhvm: if hhvm is False: @@ -1044,7 +1176,7 @@ class EESiteUpdateController(CementBaseController): data['pagespeed'] = False pagespeed = False - if pargs.pagespeed=="on" or pargs.hhvm=="on": + if pargs.pagespeed=="on" or pargs.hhvm=="on" or pargs.letsencrypt=="on": if pargs.hhvm == "on": if (not pargs.experimental): Log.info(self, "HHVM is experimental feature and it may not" @@ -1085,7 +1217,33 @@ class EESiteUpdateController(CementBaseController): data['pagespeed'] = True pagespeed = True - if data['currcachetype'] != 'wpredis' and pargs.wpredis: + if pargs.letsencrypt == "on": + + if (not pargs.experimental): + + if oldsitetype in ['wpsubdomain']: + Log.warn(self, "Wildcard domains are not supported in Lets Encrypt.\nWP SUBDOMAIN site will get SSL for primary site only.") + + Log.info(self, "Letsencrypt is currently in beta phase." + " \nDo you wish" + " to enable SSl now for {0}?".format(ee_domain)) + + # Check prompt + check_prompt = input("Type \"y\" to continue [n]:") + if check_prompt != "Y" and check_prompt != "y": + Log.info(self, "Not using letsencrypt for site") + data['letsencrypt'] = False + letsencrypt = False + else: + data['letsencrypt'] = True + letsencrypt = True + else: + data['letsencrypt'] = True + letsencrypt = True + + + + if pargs.wpredis and data['currcachetype'] != 'wpredis': if (not pargs.experimental): Log.info(self, "Redis is experimental feature and it may not" " work with all plugins of your site.\nYou can " @@ -1113,32 +1271,32 @@ class EESiteUpdateController(CementBaseController): data['ee_db_user'] = check_site.db_user data['ee_db_pass'] = check_site.db_password data['ee_db_host'] = check_site.db_host - - try: - pre_run_checks(self) - except SiteError as e: - Log.debug(self, str(e)) - Log.error(self, "NGINX configuration check failed.") - data['old_pagespeed_status'] = check_site.is_pagespeed - try: - sitebackup(self, data) - except Exception as e: - Log.debug(self, str(e)) - Log.info(self, Log.FAIL + "Check logs for reason " + if not pargs.letsencrypt: + try: + pre_run_checks(self) + except SiteError as e: + Log.debug(self, str(e)) + Log.error(self, "NGINX configuration check failed.") + + try: + sitebackup(self, data) + except Exception as e: + Log.debug(self, str(e)) + Log.info(self, Log.FAIL + "Check logs for reason " "`tail /var/log/ee/ee.log` & Try Again!!!") - return 1 + return 1 - # setup NGINX configuration, and webroot - try: - setupdomain(self, data) - except SiteError as e: - Log.debug(self, str(e)) - Log.info(self, Log.FAIL + "Update site failed." + # setup NGINX configuration, and webroot + try: + setupdomain(self, data) + except SiteError as e: + Log.debug(self, str(e)) + Log.info(self, Log.FAIL + "Update site failed." "Check logs for reason" "`tail /var/log/ee/ee.log` & Try Again!!!") - return 1 + return 1 if 'proxy' in data.keys() and data['proxy']: updateSiteInfo(self, ee_domain, stype=stype, cache=cache, @@ -1151,6 +1309,60 @@ class EESiteUpdateController(CementBaseController): if pargs.pagespeed: operateOnPagespeed(self, data) + if pargs.letsencrypt: + if data['letsencrypt'] is True: + if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled" + .format(ee_site_webroot)): + setupLetsEncrypt(self, ee_domain) + + else: + EEFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled" + .format(ee_site_webroot), + '{0}/conf/nginx/ssl.conf' + .format(ee_site_webroot)) + + httpsRedirect(self,ee_domain) + Log.info(self,"Creating Cron Job for cert auto-renewal") + EECron.setcron_daily(self,'ee site update {0} --le=renew --min_expiry_limit 30 2> /dev/null'.format(ee_domain),'Renew' + ' letsencrypt SSL cert. Set by EasyEngine') + + if not EEService.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(ee_domain)) + + if (SSL.getExpirationDays(self,ee_domain)>0): + Log.info(self, "Your cert will expire within " + str(SSL.getExpirationDays(self,ee_domain)) + " days.") + else: + Log.warn(self, "Your cert already EXPIRED ! .PLEASE renew soon . ") + + elif data['letsencrypt'] is False: + if os.path.isfile("{0}/conf/nginx/ssl.conf" + .format(ee_site_webroot)): + Log.info(self,'Setting Nginx configuration') + EEFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf" + .format(ee_site_webroot), + '{0}/conf/nginx/ssl.conf.disabled' + .format(ee_site_webroot)) + httpsRedirect(self,ee_domain,False) + if not EEService.reload_service(self, 'nginx'): + Log.error(self, "service nginx reload failed. " + "check issues with `nginx -t` command") + Log.info(self,"Removing Cron Job set for cert auto-renewal") + EECron.remove_cron(self,'ee site update {0} --le=renew --min_expiry_limit 30 2> \/dev\/null'.format(ee_domain)) + Log.info(self, "Successfully Disabled SSl for Site " + " http://{0}".format(ee_domain)) + + + # Add nginx conf folder into GIT + EEGit.add(self, ["{0}/conf/nginx".format(ee_site_webroot)], + msg="Adding letsencrypts config of site: {0}" + .format(ee_domain)) + updateSiteInfo(self, ee_domain, ssl=letsencrypt) + return 0 + if stype == oldsitetype and cache == oldcachetype: # Service Nginx Reload diff --git a/ee/cli/plugins/site_functions.py b/ee/cli/plugins/site_functions.py index 8ce33970..68b5a536 100644 --- a/ee/cli/plugins/site_functions.py +++ b/ee/cli/plugins/site_functions.py @@ -2,11 +2,13 @@ from ee.cli.plugins.stack import EEStackController from ee.core.fileutils import EEFileUtils from ee.core.mysql import * from ee.core.shellexec import * +from ee.core.sslutils import SSL from ee.core.variables import EEVariables from ee.cli.plugins.sitedb import * from ee.core.aptget import EEAptGet from ee.core.git import EEGit from ee.core.logging import Log +from ee.core.sendmail import EESendMail from ee.core.services import EEService import subprocess from subprocess import CalledProcessError @@ -676,7 +678,7 @@ def site_package_check(self, stype): Log.debug(self, "Setting apt_packages variable for Nginx") # Check if server has nginx-custom package - if not EEAptGet.is_installed(self, 'nginx-custom'): + if not (EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self, 'nginx-mainline')): # check if Server has nginx-plus installed if EEAptGet.is_installed(self, 'nginx-plus'): # do something @@ -1181,3 +1183,156 @@ def operateOnPagespeed(self, data): EEGit.add(self, ["{0}/conf/nginx".format(ee_site_webroot)], msg="Adding Pagespeed config of site: {0}" .format(ee_domain_name)) + +def cloneLetsEncrypt(self): + letsencrypt_repo = "https://github.com/letsencrypt/letsencrypt" + + try: + Log.info(self, "Downloading {0:20}".format("LetsEncrypt"), end=' ') + EEFileUtils.chdir(self, '/opt/') + EEShellExec.cmd_exec(self, "git clone {0}".format(letsencrypt_repo)) + Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + + Log.OKBLUE + "]")) + return True + except Exception as e: + Log.debug(self, "[{err}]".format(err=str(e.reason))) + Log.error(self, "Unable to download file, LetsEncrypt") + return False + +def setupLetsEncrypt(self, ee_domain_name): + ee_wp_email = EEVariables.ee_email + while not ee_wp_email: + try: + ee_wp_email = input('Enter WordPress email: ') + except EOFError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("input wordpress username failed") + + if not os.path.isdir("/opt/letsencrypt"): + cloneLetsEncrypt(self) + EEFileUtils.chdir(self, '/opt/letsencrypt') + EEShellExec.cmd_exec(self, "git pull") + + ssl = EEShellExec.cmd_exec(self, "./letsencrypt-auto certonly --webroot -w /var/www/{0}/htdocs/ -d {0} -d www.{0} " + .format(ee_domain_name) + + "--email {0} --text --agree-tos".format(ee_wp_email)) + if ssl: + Log.info(self, "Let's Encrypt successfully setup for your site") + Log.info(self, "Your certificate and chain have been saved at " + "/etc/letsencrypt/live/{0}/fullchain.pem".format(ee_domain_name)) + Log.info(self, "Configuring Nginx SSL configuration") + + try: + Log.info(self, "Adding /var/www/{0}/conf/nginx/ssl.conf".format(ee_domain_name)) + + sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" + .format(ee_domain_name), + encoding='utf-8', mode='w') + sslconf.write("listen 443 ssl {http2};\n".format(http2=("http2" if + EEAptGet.is_installed(self,'nginx-mainline') else "spdy")) + + "ssl on;\n" + "ssl_certificate /etc/letsencrypt/live/{0}/fullchain.pem;\n" + "ssl_certificate_key /etc/letsencrypt/live/{0}/privkey.pem;\n" + .format(ee_domain_name)) + sslconf.close() + # updateSiteInfo(self, ee_domain_name, ssl=True) + + EEGit.add(self, ["/etc/letsencrypt"], + msg="Adding letsencrypt folder") + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "ssl.conf") + else: + Log.error(self, "Unable to setup, Let\'s Encrypt", False) + Log.error(self, "Please make sure that your site is pointed to \n" + "same server on which you are running Let\'s Encrypt Client " + "\n to allow it to verify the site automatically.") + +def renewLetsEncrypt(self, ee_domain_name): + + ee_wp_email = EEVariables.ee_email + while not ee_wp_email: + try: + ee_wp_email = input('Enter email address: ') + except EOFError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("Input wordpress email failed") + + if not os.path.isdir("/opt/letsencrypt"): + cloneLetsEncrypt(self) + EEFileUtils.chdir(self, '/opt/letsencrypt') + EEShellExec.cmd_exec(self, "git pull") + + Log.info(self, "Renewing SSl cert for https://{0}".format(ee_domain_name)) + + ssl = EEShellExec.cmd_exec(self, "./letsencrypt-auto --renew certonly --webroot -w /var/www/{0}/htdocs/ -d {0} -d www.{0} " + .format(ee_domain_name) + + "--email {0} --text --agree-tos".format(ee_wp_email)) + mail_list = '' + if not ssl: + Log.error(self,"ERROR : Cannot RENEW SSL cert !",False) + if (SSL.getExpirationDays(self,ee_domain_name)>0): + Log.error(self, "Your current cert will expire within " + str(SSL.getExpirationDays(self,ee_domain_name)) + " days.",False) + else: + Log.error(self, "Your current cert already EXPIRED !",False) + + EESendMail("easyengine@{0}".format(ee_domain_name), ee_wp_email, "[FAIL] SSL cert renewal {0}".format(ee_domain_name), + "Hey Hi,\n\nSSL Certificate renewal for https://{0} was unsuccessful.".format(ee_domain_name) + + "\nPlease check easyengine log for reason. Your SSL Expiry date : " + + str(SSL.getExpirationDate(self,ee_domain_name)) + + "\n\nFor support visit https://easyengine.io/support/ .\n\nYour's faithfully,\nEasyEngine",files=mail_list, + port=25, isTls=False) + Log.error(self, "Check logs for reason " + "`tail /var/log/ee/ee.log` & Try Again!!!") + + EEGit.add(self, ["/etc/letsencrypt"], + msg="Adding letsencrypt folder") + EESendMail("easyengine@{0}".format(ee_domain_name), ee_wp_email, "[SUCCESS] SSL cert renewal {0}".format(ee_domain_name), + "Hey Hi,\n\nYour SSL Certificate has been renewed for https://{0} .".format(ee_domain_name) + + "\nYour SSL will Expire on : " + + str(SSL.getExpirationDate(self,ee_domain_name)) + + "\n\nYour's faithfully,\nEasyEngine",files=mail_list, + port=25, isTls=False) + +#redirect= False to disable https redirection +def httpsRedirect(self,ee_domain_name,redirect=True): + if redirect: + if os.path.isfile("/etc/nginx/conf.d/force-ssl-{0}.conf.disabled".format(ee_domain_name)): + EEFileUtils.mvfile(self, "/etc/nginx/conf.d/force-ssl-{0}.conf.disabled".format(ee_domain_name), + "/etc/nginx/conf.d/force-ssl-{0}.conf".format(ee_domain_name)) + else: + try: + Log.info(self, "Adding /etc/nginx/conf.d/force-ssl-{0}.conf".format(ee_domain_name)) + + sslconf = open("/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(ee_domain_name), + encoding='utf-8', mode='w') + sslconf.write("server {\n" + "\tlisten 80;\n" + + "\tserver_name www.{0} {0};\n".format(ee_domain_name) + + "\treturn 301 https://{0}".format(ee_domain_name)+"$request_uri;\n}" ) + sslconf.close() + # Nginx Configation into GIT + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "/etc/nginx/conf.d/force-ssl-{0}.conf".format(ee_domain_name)) + + Log.info(self, "Added HTTPS Force Redirection for Site " + " http://{0}".format(ee_domain_name)) + EEGit.add(self, + ["/etc/nginx"], msg="Adding /etc/nginx/conf.d/force-ssl-{0}.conf".format(ee_domain_name)) + else: + if os.path.isfile("/etc/nginx/conf.d/force-ssl-{0}.conf".format(ee_domain_name)): + EEFileUtils.mvfile(self, "/etc/nginx/conf.d/force-ssl-{0}.conf".format(ee_domain_name), + "/etc/nginx/conf.d/force-ssl-{0}.conf.disabled".format(ee_domain_name)) + Log.info(self, "Disabled HTTPS Force Redirection for Site " + " http://{0}".format(ee_domain_name)) + + + + + + diff --git a/ee/cli/plugins/sitedb.py b/ee/cli/plugins/sitedb.py index c81b1249..4fc3fd35 100644 --- a/ee/cli/plugins/sitedb.py +++ b/ee/cli/plugins/sitedb.py @@ -63,7 +63,7 @@ def updateSiteInfo(self, site, stype='', cache='', webroot='', if q.is_enabled != enabled: q.is_enabled = enabled - if ssl and q.is_ssl != ssl: + if q.is_ssl != ssl: q.is_ssl = ssl if db_name and q.db_name != db_name: diff --git a/ee/cli/plugins/stack.py b/ee/cli/plugins/stack.py index 6564fd9f..60a3349a 100644 --- a/ee/cli/plugins/stack.py +++ b/ee/cli/plugins/stack.py @@ -2,6 +2,7 @@ from cement.core.controller import CementBaseController, expose from cement.core import handler, hook +from ee.cli.plugins.site_functions import * from ee.core.variables import EEVariables from ee.core.aptget import EEAptGet from ee.core.download import EEDownload @@ -30,6 +31,7 @@ from ee.cli.plugins.stack_services import EEStackStatusController from ee.cli.plugins.stack_migrate import EEStackMigrateController from ee.cli.plugins.stack_upgrade import EEStackUpgradeController from ee.core.logging import Log +from ee.cli.plugins.sitedb import * def ee_stack_hook(app): @@ -56,6 +58,8 @@ class EEStackController(CementBaseController): dict(help='Install mail scanner stack', action='store_true')), (['--nginx'], dict(help='Install Nginx stack', action='store_true')), + (['--nginxmainline'], + dict(help='Install Nginx mainline stack', action='store_true')), (['--php'], dict(help='Install PHP stack', action='store_true')), (['--mysql'], @@ -168,6 +172,12 @@ class EEStackController(CementBaseController): Log.debug(self, 'Adding ppa of Nginx') EERepo.add_key(self, EEVariables.ee_nginx_key) + if set(["nginx-mainline"]).issubset(set(apt_packages)): + Log.info(self, "Adding repository for NGINX MAINLINE, please wait...") + EERepo.add(self, repo_url=EEVariables.ee_nginx_dev_repo) + Log.debug(self, 'Adding ppa of Nginx-mainline') + EERepo.add_key(self, EEVariables.ee_nginx_key) + if set(EEVariables.ee_php).issubset(set(apt_packages)): Log.info(self, "Adding repository for PHP, please wait...") # Add repository for php @@ -223,7 +233,8 @@ class EEStackController(CementBaseController): msg="Adding Postfix into Git") EEService.reload_service(self, 'postfix') - if set(EEVariables.ee_nginx).issubset(set(apt_packages)): + if set(EEVariables.ee_nginx).issubset(set(apt_packages)) or set(EEVariables.ee_nginx_dev)\ + .issubset(set(apt_packages)) : if set(["nginx-plus"]).issubset(set(apt_packages)): # Fix for white screen death with NGINX PLUS if not EEFileUtils.grep(self, '/etc/nginx/fastcgi_params', @@ -233,6 +244,26 @@ class EEStackController(CementBaseController): ee_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' '\t$request_filename;\n') + if os.path.isfile('/etc/nginx/sites-available/22222'): + http2 = "http2" if EEAptGet.is_installed(self,'nginx-mainline') else "spdy" + if not EEShellExec.cmd_exec(self, "grep -q \'{http2}\' /etc/nginx/sites-available/22222".format(http2=http2)): + Log.debug(self, 'Setting http2/spdy in 22222') + EEShellExec.cmd_exec(self, "sed -i 's/http2\|spdy/{0}/g' /etc/nginx/sites-available/22222".format(http2)) + + sites = getAllsites(self) + if sites: + for site in sites: + site_name = site.sitename + siteinfo = getSiteInfo(self, site_name) + ssl = ("enabled" if siteinfo.is_ssl else "disabled") + if (ssl == "enabled"): + if os.path.isfile('/var/www/{0}/conf/nginx/ssl.conf'.format(site_name)): + http2 =("http2" if EEAptGet.is_installed(self,'nginx-mainline') else "spdy") + if not EEShellExec.cmd_exec(self, "grep -q \'{http2}\' /var/www/{site}/conf/nginx/ssl.conf".format(http2=http2,site=site_name)): + Log.debug(self, 'Modifying http2/spdy parameter in /var/www/{0}/conf/nginx/ssl.conf'.format(site_name)) + EEShellExec.cmd_exec(self, "sed -i 's/http2\|spdy/{http2}/g' /var/www/{site}/conf/nginx/ssl.conf".format(http2=http2,site=site_name)) + + if not (os.path.isfile('/etc/nginx/common/wpfc.conf')): # Change EasyEngine Version in nginx.conf file EEFileUtils.searchreplace(self, "/etc/nginx/nginx.conf", @@ -273,7 +304,8 @@ class EEStackController(CementBaseController): '/etc/nginx/common') os.makedirs('/etc/nginx/common') - data = dict(webroot=EEVariables.ee_webroot) + http2 = ("http2" if set(["nginx-mainline"]).issubset(set(apt_packages)) else "spdy") + data = dict(webroot=EEVariables.ee_webroot,http2=http2) Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/acl.conf') ee_nginx = open('/etc/nginx/common/acl.conf', @@ -339,7 +371,7 @@ class EEStackController(CementBaseController): ee_nginx.close() # Nginx-Plus does not have nginx package structure like this - # So craeting directories + # So creating directories if set(["nginx-plus"]).issubset(set(apt_packages)): Log.info(self, "Installing EasyEngine Configurations for" "NGINX PLUS") @@ -483,6 +515,8 @@ class EEStackController(CementBaseController): else: self.msg = (self.msg + ["HTTP Auth User Name: easyengine"] + ["HTTP Auth Password : {0}".format(passwd)]) + else: + EEService.restart_service(self, 'nginx') if EEAptGet.is_installed(self,'redis-server'): if os.path.isfile("/etc/nginx/nginx.conf") and (not @@ -1576,7 +1610,7 @@ class EEStackController(CementBaseController): and (not self.app.pargs.pagespeed) and (not self.app.pargs.adminer) and (not self.app.pargs.utils) and (not self.app.pargs.mailscanner) and (not self.app.pargs.all) - and (not self.app.pargs.redis) and + and (not self.app.pargs.redis) and (not self.app.pargs.nginxmainline) and (not self.app.pargs.phpredisadmin)): self.app.pargs.web = True self.app.pargs.admin = True @@ -1634,7 +1668,7 @@ class EEStackController(CementBaseController): Log.info(self, "Mail server is already installed") if self.app.pargs.pagespeed: - if not EEAptGet.is_installed(self, 'nginx-custom'): + if not (EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self, 'nginx-mainline')): self.app.pargs.nginx = True else: Log.info(self, "Nginx already installed") @@ -1649,7 +1683,7 @@ class EEStackController(CementBaseController): if self.app.pargs.nginx: Log.debug(self, "Setting apt_packages variable for Nginx") - if not EEAptGet.is_installed(self, 'nginx-custom'): + if not (EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self, 'nginx-mainline')): if not EEAptGet.is_installed(self, 'nginx-plus'): apt_packages = apt_packages + EEVariables.ee_nginx else: @@ -1660,6 +1694,25 @@ class EEStackController(CementBaseController): else: Log.debug(self, "Nginx already installed") Log.info(self, "Nginx already installed") + + if self.app.pargs.nginxmainline: + if EEVariables.ee_nginx_dev_repo == None: + Log.error(self, "NGINX Mainline Version is not supported in wheezy") + + Log.debug(self, "Setting apt_packages variable for Nginx") + + if not (EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self, 'nginx-mainline')): + if not EEAptGet.is_installed(self, 'nginx-plus'): + apt_packages = apt_packages + EEVariables.ee_nginx_dev + else: + Log.info(self, "NGINX PLUS Detected ...") + apt = ["nginx-plus"] + EEVariables.ee_nginx + #apt_packages = apt_packages + EEVariables.ee_nginx + self.post_pref(apt, packages) + else: + Log.debug(self, "Nginx already installed") + Log.info(self, "Nginx already installed") + if self.app.pargs.php: Log.debug(self, "Setting apt_packages variable for PHP") if not EEAptGet.is_installed(self, 'php5-fpm'): @@ -1856,7 +1909,7 @@ class EEStackController(CementBaseController): (not self.app.pargs.adminer) and (not self.app.pargs.utils) and (not self.app.pargs.mailscanner) and (not self.app.pargs.all) and (not self.app.pargs.pagespeed) and (not self.app.pargs.redis) and - (not self.app.pargs.phpredisadmin)): + (not self.app.pargs.phpredisadmin) and (not self.app.pargs.nginxmainline)): self.app.pargs.web = True self.app.pargs.admin = True @@ -1897,8 +1950,17 @@ class EEStackController(CementBaseController): packages = packages + ['/etc/nginx/conf.d/pagespeed.conf'] if self.app.pargs.nginx: - Log.debug(self, "Removing apt_packages variable of Nginx") - apt_packages = apt_packages + EEVariables.ee_nginx + if EEAptGet.is_installed(self, 'nginx-custom'): + Log.debug(self, "Removing apt_packages variable of Nginx") + apt_packages = apt_packages + EEVariables.ee_nginx + else: + Log.error(self,"Cannot Remove! Nginx Stable version not found.") + if self.app.pargs.nginxmainline: + if EEAptGet.is_installed(self, 'nginx-mainline'): + Log.debug(self, "Removing apt_packages variable of Nginx MAINLINE") + apt_packages = apt_packages + EEVariables.ee_nginx_dev + else: + Log.error(self,"Cannot Remove! Nginx Mainline version not found.") if self.app.pargs.php: Log.debug(self, "Removing apt_packages variable of PHP") apt_packages = apt_packages + EEVariables.ee_php @@ -1959,6 +2021,11 @@ class EEStackController(CementBaseController): ' operation : ') if ee_prompt == 'YES' or ee_prompt == 'yes': + + if (set(["nginx-mainline"]).issubset(set(apt_packages)) or + set(["nginx-custom"]).issubset(set(apt_packages))) : + EEService.stop_service(self, 'nginx') + if len(packages): EEFileUtils.remove(self, packages) EEAptGet.auto_remove(self) @@ -1969,6 +2036,11 @@ class EEStackController(CementBaseController): EEAptGet.remove(self, apt_packages) EEAptGet.auto_remove(self) + if set(["nginx-mainline"]).issubset(set(apt_packages)): + Log.info(self, "Removing repository for NGINX MAINLINE,") + EERepo.remove(self, repo_url=EEVariables.ee_nginx_dev_repo) + + Log.info(self, "Successfully removed packages") @expose(help="Purge packages") @@ -1986,7 +2058,7 @@ class EEStackController(CementBaseController): (not self.app.pargs.adminer) and (not self.app.pargs.utils) and (not self.app.pargs.mailscanner) and (not self.app.pargs.all) and (not self.app.pargs.pagespeed) and (not self.app.pargs.redis) and - (not self.app.pargs.phpredisadmin)): + (not self.app.pargs.phpredisadmin) and (not self.app.pargs.nginxmainline)): self.app.pargs.web = True self.app.pargs.admin = True @@ -2027,8 +2099,17 @@ class EEStackController(CementBaseController): packages = packages + ['/etc/nginx/conf.d/pagespeed.conf'] if self.app.pargs.nginx: - Log.debug(self, "Purge apt_packages variable of Nginx") - apt_packages = apt_packages + EEVariables.ee_nginx + if EEAptGet.is_installed(self, 'nginx-custom'): + Log.debug(self, "Purge apt_packages variable of Nginx") + apt_packages = apt_packages + EEVariables.ee_nginx + else: + Log.error(self,"Cannot Purge! Nginx Stable version not found.") + if self.app.pargs.nginxmainline: + if EEAptGet.is_installed(self, 'nginx-mainline'): + Log.debug(self, "Purge apt_packages variable of Nginx Mainline") + apt_packages = apt_packages + EEVariables.ee_nginx_dev + else: + Log.error(self,"Cannot Purge! Nginx Mainline version not found.") if self.app.pargs.php: Log.debug(self, "Purge apt_packages variable PHP") apt_packages = apt_packages + EEVariables.ee_php @@ -2088,6 +2169,11 @@ class EEStackController(CementBaseController): 'operation :') if ee_prompt == 'YES' or ee_prompt == 'yes': + + if (set(["nginx-mainline"]).issubset(set(apt_packages)) or + set(["nginx-custom"]).issubset(set(apt_packages))) : + EEService.stop_service(self, 'nginx') + if len(apt_packages): Log.info(self, "Purging packages, please wait...") EEAptGet.remove(self, apt_packages, purge=True) @@ -2097,6 +2183,11 @@ class EEStackController(CementBaseController): EEFileUtils.remove(self, packages) EEAptGet.auto_remove(self) + if set(["nginx-mainline"]).issubset(set(apt_packages)): + Log.info(self, "Removing repository for NGINX MAINLINE,") + EERepo.remove(self, repo_url=EEVariables.ee_nginx_dev_repo) + + Log.info(self, "Successfully purged packages") def load(app): diff --git a/ee/cli/plugins/stack_services.py b/ee/cli/plugins/stack_services.py index 75b53646..45a947bf 100644 --- a/ee/cli/plugins/stack_services.py +++ b/ee/cli/plugins/stack_services.py @@ -33,7 +33,7 @@ class EEStackStatusController(CementBaseController): self.app.pargs.postfix = True if self.app.pargs.nginx: - if EEAptGet.is_installed(self, 'nginx-custom'): + if EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self,'nginx-mainline'): services = services + ['nginx'] else: Log.info(self, "Nginx is not installed") @@ -104,7 +104,7 @@ class EEStackStatusController(CementBaseController): self.app.pargs.postfix = True if self.app.pargs.nginx: - if EEAptGet.is_installed(self, 'nginx-custom'): + if EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self,'nginx-mainline'): services = services + ['nginx'] else: Log.info(self, "Nginx is not installed") @@ -175,7 +175,7 @@ class EEStackStatusController(CementBaseController): self.app.pargs.postfix = True if self.app.pargs.nginx: - if EEAptGet.is_installed(self, 'nginx-custom'): + if EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self,'nginx-mainline'): services = services + ['nginx'] else: Log.info(self, "Nginx is not installed") @@ -247,7 +247,7 @@ class EEStackStatusController(CementBaseController): self.app.pargs.hhvm = True if self.app.pargs.nginx: - if EEAptGet.is_installed(self, 'nginx-custom'): + if EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self,'nginx-mainline'): services = services + ['nginx'] else: Log.info(self, "Nginx is not installed") @@ -318,7 +318,7 @@ class EEStackStatusController(CementBaseController): self.app.pargs.postfix = True if self.app.pargs.nginx: - if EEAptGet.is_installed(self, 'nginx-custom'): + if EEAptGet.is_installed(self, 'nginx-custom') or EEAptGet.is_installed(self,'nginx-mainline'): services = services + ['nginx'] else: Log.info(self, "Nginx is not installed") diff --git a/ee/cli/templates/22222.mustache b/ee/cli/templates/22222.mustache index 3893b90e..24c3a05b 100644 --- a/ee/cli/templates/22222.mustache +++ b/ee/cli/templates/22222.mustache @@ -2,7 +2,7 @@ server { - listen 22222 default_server ssl spdy; + listen 22222 default_server ssl {{http2}}; access_log /var/log/nginx/22222.access.log rt_cache; error_log /var/log/nginx/22222.error.log; diff --git a/ee/cli/templates/locations.mustache b/ee/cli/templates/locations.mustache index b9d9fc63..df651d7a 100644 --- a/ee/cli/templates/locations.mustache +++ b/ee/cli/templates/locations.mustache @@ -22,6 +22,9 @@ location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gi } # Security settings for better privacy # Deny hidden files +location ~ /\.well-known { + allow all; +} location ~ /\. { deny all; access_log off; diff --git a/ee/cli/templates/siteinfo.mustache b/ee/cli/templates/siteinfo.mustache index 7875709d..3e8b1960 100644 --- a/ee/cli/templates/siteinfo.mustache +++ b/ee/cli/templates/siteinfo.mustache @@ -3,6 +3,9 @@ Information about {{domain}}: Nginx configuration {{type}} {{enable}} {{#pagespeed}}Pagespeed {{pagespeed}}{{/pagespeed}} {{#hhvm}}HHVM {{hhvm}}{{/hhvm}} +{{#ssl}}SSL {{ssl}}{{/ssl}} +{{#sslprovider}}SSL PROVIDER {{sslprovider}}{{/sslprovider}} +{{#sslexpiry}}SSL EXPIRY DATE {{sslexpiry}}{{/sslexpiry}} access_log {{accesslog}} error_log {{errorlog}} {{#webroot}}Webroot {{webroot}}{{/webroot}} diff --git a/ee/core/cron.py b/ee/core/cron.py new file mode 100644 index 00000000..9c419a1f --- /dev/null +++ b/ee/core/cron.py @@ -0,0 +1,32 @@ +from ee.core.shellexec import EEShellExec +from ee.core.logging import Log + +""" +Set CRON on LINUX system. +""" + +class EECron(): + def setcron_daily(self,cmd,comment='Cron set by EasyEngine',user='root',min=0,hour=12): + if not EEShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)): + + EEShellExec.cmd_exec(self, "/bin/bash -c \"crontab -l " + "2> /dev/null | {{ cat; echo -e" + " \\\"" + "\\n0 12 * * * " + "{0}".format(cmd) + + " # {0}".format(comment)+ + "\\\"; } | crontab -\"") + Log.debug(self, "Cron set") + + + + def remove_cron(self,cmd): + if EEShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)): + if not EEShellExec.cmd_exec(self, "/bin/bash -c " + "\"crontab " + "-l | sed '/{0}/d'" + "| crontab -\"" + .format(cmd)): + Log.error(self, "Failed to remove crontab entry",False) + else: + Log.debug(self, "Cron not found") diff --git a/ee/core/shellexec.py b/ee/core/shellexec.py index f82352fd..b68076cc 100644 --- a/ee/core/shellexec.py +++ b/ee/core/shellexec.py @@ -29,6 +29,8 @@ class EEShellExec(): "replace")) if proc.returncode == 0: + Log.debug(self, "Command Output: {0}, \nCommand Error: {1}" + .format(cmd_stdout, cmd_stderr)) return True else: Log.debug(self, "Command Output: {0}, \nCommand Error: {1}" @@ -50,3 +52,32 @@ class EEShellExec(): except OSError as e: Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) raise CommandExecutionError + + + def cmd_exec_stdout(self, command, errormsg='', log=True): + """Run shell command from Python""" + try: + log and Log.debug(self, "Running command: {0}".format(command)) + + with subprocess.Popen([command], stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=True) as proc: + (cmd_stdout_bytes, cmd_stderr_bytes) = proc.communicate() + (cmd_stdout, cmd_stderr) = (cmd_stdout_bytes.decode('utf-8', + "replace"), + cmd_stderr_bytes.decode('utf-8', + "replace")) + + if proc.returncode == 0: + Log.debug(self, "Command Output: {0}, \nCommand Error: {1}" + .format(cmd_stdout, cmd_stderr)) + return cmd_stdout + else: + Log.debug(self, "Command Output: {0}, \nCommand Error: {1}" + .format(cmd_stdout, cmd_stderr)) + return cmd_stdout + except OSError as e: + Log.debug(self, str(e)) + raise CommandExecutionError + except Exception as e: + Log.debug(self, str(e)) + raise CommandExecutionError \ No newline at end of file diff --git a/ee/core/sslutils.py b/ee/core/sslutils.py new file mode 100644 index 00000000..305f4f76 --- /dev/null +++ b/ee/core/sslutils.py @@ -0,0 +1,41 @@ +import os +from ee.core.shellexec import EEShellExec +from ee.core.logging import Log + + +class SSL: + + def getExpirationDays(self,domain): + # check if exist + if not os.path.isfile('/etc/letsencrypt/live/{0}/cert.pem' + .format(domain)): + Log.error(self,'File Not Found : /etc/letsencrypt/live/{0}/cert.pem' + .format(domain),False) + Log.error(self, "Check logs for reason " + "`tail /var/log/ee/ee.log` & Try Again!!!") + + + current_date = EEShellExec.cmd_exec_stdout(self, "date -d \"now\" +%s") + expiration_date = EEShellExec.cmd_exec_stdout(self, "date -d \"`openssl x509 -in /etc/letsencrypt/live/{0}/cert.pem" + " -text -noout|grep \"Not After\"|cut -c 25-`\" +%s".format(domain)) + + days_left = int((int(expiration_date) - int(current_date))/ 86400) + if (days_left > 0): + return days_left + else: + # return "Certificate Already Expired ! Please Renew soon." + return -1 + + def getExpirationDate(self,domain): + # check if exist + if not os.path.isfile('/etc/letsencrypt/live/{0}/cert.pem' + .format(domain)): + Log.error(self,'File Not Found : /etc/letsencrypt/live/{0}/cert.pem' + .format(domain),False) + Log.error(self, "Check logs for reason " + "`tail /var/log/ee/ee.log` & Try Again!!!") + + expiration_date = EEShellExec.cmd_exec_stdout(self, "date -d \"`openssl x509 -in /etc/letsencrypt/live/{0}/cert.pem" + " -text -noout|grep \"Not After\"|cut -c 25-`\" ".format(domain)) + return expiration_date + diff --git a/ee/core/variables.py b/ee/core/variables.py index 5cb73187..a0f76234 100644 --- a/ee/core/variables.py +++ b/ee/core/variables.py @@ -12,13 +12,13 @@ class EEVariables(): """Intialization of core variables""" # EasyEngine version - ee_version = "3.3.15" + ee_version = "3.4.0" # EasyEngine packages versions ee_wp_cli = "0.21.1" ee_adminer = "4.2.1" - ee_roundcube = "1.1.3" + ee_roundcube = "1.1.4" ee_vimbadmin = "3.0.12" # Get WPCLI path @@ -83,22 +83,31 @@ class EEVariables(): else: ee_mysql_host = "localhost" - # EasyEngine stack installation varibales + # EasyEngine stack installation variables # Nginx repo and packages if ee_platform_codename == 'precise': ee_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" "/rtCamp:/EasyEngine/xUbuntu_12.04/ /") + ee_nginx_dev_repo = ("deb http://download.opensuse.org/repositories/home:" + "/rtCamp:/EasyEngine-dev/xUbuntu_12.04/ /") elif ee_platform_codename == 'trusty': ee_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" "/rtCamp:/EasyEngine/xUbuntu_14.04/ /") + ee_nginx_dev_repo = ("deb http://download.opensuse.org/repositories/home:" + "/rtCamp:/EasyEngine-dev/xUbuntu_14.04/ /") elif ee_platform_codename == 'wheezy': ee_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" "/rtCamp:/EasyEngine/Debian_7.0/ /") + ee_nginx_dev_repo = None elif ee_platform_codename == 'jessie': ee_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" "/rtCamp:/EasyEngine/Debian_8.0/ /") + ee_nginx_dev_repo = ("deb http://download.opensuse.org/repositories/home:" + "/rtCamp:/EasyEngine-dev/Debian_8.0/ /") + ee_nginx = ["nginx-custom", "nginx-common"] + ee_nginx_dev = ["nginx-mainline", "nginx-common"] ee_nginx_key = '3050AC3CD2AE6F03' # PHP repo and packages diff --git a/install b/install index d682967e..083deeed 100644 --- a/install +++ b/install @@ -48,7 +48,7 @@ fi # Define variables for later use ee_branch=$1 readonly ee_version_old="2.2.3" -readonly ee_version_new="3.3.15" +readonly ee_version_new="3.4.0" readonly ee_log_dir=/var/log/ee/ readonly ee_install_log=/var/log/ee/install.log readonly ee_linux_distro=$(lsb_release -i | awk '{print $3}') @@ -490,6 +490,14 @@ function ee_update_latest() fi fi + #Fix For --letsencrypt + if [ -f /etc/nginx/common/locations.conf ]; then + grep -0 'location ~ \/\\.well-known' /etc/nginx/common/locations.conf &>> /dev/null + if [ $? -ne 0 ]; then + sed -i 's/# Deny hidden files/# Deny hidden files\nlocation ~ \/\\.well-known {\n allow all;\n}\n /g' /etc/nginx/common/locations.conf &>> /dev/null + fi + fi + # Fix for 3.3.2 renamed nginx.conf nginx -V 2>&1 &>>/dev/null if [[ $? -eq 0 ]]; then @@ -512,6 +520,11 @@ function ee_update_latest() fi fi + #Fix For ssl_ciphers + if [ -f /etc/nginx/nginx.conf ]; then + sed -i 's/HIGH:!aNULL:!MD5:!kEDH;/ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;/' /etc/nginx/nginx.conf + fi + } diff --git a/setup.py b/setup.py index 30d99520..caa47e00 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,7 @@ import os import glob import configparser import re +import shutil conf = [] templates = [] @@ -53,8 +54,11 @@ except Exception as e: os.system("git config --global user.name {0}".format(ee_user)) os.system("git config --global user.email {0}".format(ee_email)) +if not os.path.isfile('/root/.gitconfig'): + shutil.copy2(os.path.expanduser("~")+'/.gitconfig', '/root/.gitconfig') + setup(name='ee', - version='3.3.15', + version='3.4.0', description=long_description, long_description=long_description, classifiers=[],