feat: convert WordOps from Nginx to OpenLiteSpeed + LSPHP + LSCache
Some checks failed
CI / test WordOps (ubuntu-22.04) (push) Has been cancelled
CI / test WordOps (ubuntu-24.04) (push) Has been cancelled

Complete conversion of the WordOps stack from Nginx + PHP-FPM to
OpenLiteSpeed + LSPHP + LSCache. This is a full rewrite across all 7
phases of the codebase:

- Foundation: OLS paths, variables, services, removed pynginxconfig dep
- Templates: 11 new OLS mustache templates, removed nginx-specific ones
- Stack: stack_pref, stack, stack_services, stack_upgrade, stack_migrate
- Site: site_functions, site, site_create, site_update
- Plugins: debug, info, log, clean rewritten for OLS
- SSL/ACME: acme.sh deploy uses lswsctrl, OLS vhssl blocks
- Other: secure, backup, clone, install script

Additional features:
- Debian 13 (trixie) support
- PHP 8.5 support
- WP Fort Knox mu-plugin integration (wo secure --lockdown/--unlock)
- --nginx CLI flag preserved for backward compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 18:55:16 +01:00
parent aa127070e1
commit fa5bf17eb8
42 changed files with 2328 additions and 2926 deletions

View File

@@ -16,8 +16,6 @@ from wo.core.mysql import WOMysql
from wo.core.services import WOService
from wo.core.shellexec import WOShellExec
from wo.core.variables import WOVar
from wo.core.nginx import check_config
from wo.core.git import WOGit
def wo_stack_hook(app):
@@ -40,7 +38,7 @@ class WOStackController(CementBaseController):
(['--security'],
dict(help='Install security tools stack', action='store_true')),
(['--nginx'],
dict(help='Install Nginx stack', action='store_true')),
dict(help='Install OpenLiteSpeed stack', action='store_true')),
(['--php'],
dict(help='Install PHP 7.2 stack', action='store_true')),
(['--mysql'],
@@ -84,16 +82,13 @@ class WOStackController(CementBaseController):
dict(help='Install phpRedisAdmin', action='store_true')),
(['--proftpd'],
dict(help='Install ProFTPd', action='store_true')),
(['--ngxblocker'],
dict(help='Install Nginx Ultimate Bad Bot Blocker',
action='store_true')),
(['--cheat'],
dict(help='Install cheat.sh', action='store_true')),
(['--nanorc'],
dict(help='Install nanorc syntax highlighting',
action='store_true')),
(['--brotli'],
dict(help='Enable/Disable Brotli compression for Nginx',
dict(help='Enable/Disable Brotli compression for OpenLiteSpeed',
action='store_true')),
(['--force'],
dict(help='Force install/remove/purge without prompt',
@@ -136,6 +131,7 @@ class WOStackController(CementBaseController):
pargs.php82 = True
pargs.php83 = True
pargs.php84 = True
pargs.php85 = True
pargs.redis = True
pargs.proftpd = True
@@ -162,7 +158,6 @@ class WOStackController(CementBaseController):
if pargs.security:
pargs.fail2ban = True
pargs.clamav = True
pargs.ngxblocker = True
if pargs.php:
if self.app.config.has_section('php'):
@@ -171,13 +166,13 @@ class WOStackController(CementBaseController):
current_php = config_php_ver.replace(".", "")
setattr(self.app.pargs, 'php{0}'.format(current_php), True)
# Nginx
# OpenLiteSpeed
if pargs.nginx:
Log.debug(self, "Setting apt_packages variable for Nginx")
if not WOAptGet.is_exec(self, 'nginx'):
apt_packages = apt_packages + WOVar.wo_nginx
Log.debug(self, "Setting apt_packages variable for OpenLiteSpeed")
if not os.path.isfile('/usr/local/lsws/bin/openlitespeed'):
apt_packages = apt_packages + WOVar.wo_ols
else:
Log.debug(self, "Nginx already installed")
Log.debug(self, "OpenLiteSpeed already installed")
# Redis
if pargs.redis:
@@ -194,12 +189,14 @@ class WOStackController(CementBaseController):
'php82': WOVar.wo_php82,
'php83': WOVar.wo_php83,
'php84': WOVar.wo_php84,
'php85': WOVar.wo_php85,
}
for parg_version, version in WOVar.wo_php_versions.items():
if getattr(pargs, parg_version, False):
short_ver = version.replace('.', '')
Log.debug(self, f"Setting apt_packages variable for PHP {version}")
if not WOAptGet.is_installed(self, f'php{version}-fpm'):
if not WOAptGet.is_installed(self, f'lsphp{short_ver}'):
apt_packages = apt_packages + wo_vars[parg_version] + WOVar.wo_php_extra
else:
Log.debug(self, f"PHP {version} already installed")
@@ -287,23 +284,25 @@ class WOStackController(CementBaseController):
# brotli
if pargs.brotli:
Log.wait(self, "Enabling Brotli")
WOGit.add(self, ["/etc/nginx"], msg="Commiting pending changes")
if os.path.exists('/etc/nginx/conf.d/brotli.conf.disabled'):
WOFileUtils.mvfile(self, '/etc/nginx/conf.d/brotli.conf.disabled',
'/etc/nginx/conf.d/brotli.conf')
ols_conf = '/usr/local/lsws/conf/httpd_config.conf'
if os.path.isfile(ols_conf):
if WOFileUtils.grepcheck(self, ols_conf, 'enableBr.*0'):
WOFileUtils.searchreplace(
self, ols_conf,
'enableBr 0',
'enableBr 1')
WOFileUtils.searchreplace(
self, ols_conf,
'enableGzipCompress 1',
'enableGzipCompress 0')
Log.valide(self, "Enabling Brotli")
WOService.restart_service(self, "lsws")
else:
Log.failed(self, "Enabling Brotli")
Log.error(self, "Brotli is already enabled")
else:
Log.failed(self, "Enabling Brotli")
Log.error(self, "Brotli is already enabled")
if os.path.exists('/etc/nginx/conf.d/gzip.conf'):
WOFileUtils.mvfile(self, '/etc/nginx/conf.d/gzip.conf',
'/etc/nginx/conf.d/gzip.conf.disabled')
if check_config(self):
Log.valide(self, "Enabling Brotli")
WOGit.add(self, ["/etc/nginx"], msg="Enabling Brotli")
WOService.reload_service(self, "nginx")
else:
Log.failed(self, "Enabling Brotli")
WOGit.rollback(self, ["/etc/nginx"])
Log.error(self, "OpenLiteSpeed is not installed")
# PHPMYADMIN
if pargs.phpmyadmin:
@@ -433,22 +432,6 @@ class WOStackController(CementBaseController):
Log.debug(self, "eXtplorer is already installed")
Log.info(self, "eXtplorer is already installed")
# ultimate ngx_blocker
if pargs.ngxblocker:
if not WOAptGet.is_exec(self, 'nginx'):
pargs.nginx = True
if not os.path.isdir('/etc/nginx/bots.d'):
Log.debug(self, "Setting packages variable for ngxblocker")
packages = packages + \
[["https://raw.githubusercontent.com/"
"mitchellkrogza/nginx-ultimate-bad-bot-blocker"
"/master/install-ngxblocker",
"/usr/local/sbin/install-ngxblocker",
"ngxblocker"]]
else:
Log.debug(self, "ngxblocker is already installed")
Log.info(self, "ngxblocker is already installed")
# cheat.sh
if pargs.cheat:
if ((not os.path.exists('/usr/local/bin/cht.sh')) and
@@ -473,28 +456,18 @@ class WOStackController(CementBaseController):
if pargs.utils:
if not WOMysql.mariadb_ping(self):
pargs.mysql = True
if not (WOAptGet.is_installed(self, 'php7.2-fpm') or
WOAptGet.is_installed(self, 'php7.3-fpm') or
WOAptGet.is_installed(self, 'php7.4-fpm') or
WOAptGet.is_installed(self, 'php8.0-fpm') or
WOAptGet.is_installed(self, 'php8.1-fpm') or
WOAptGet.is_installed(self, 'php8.2-fpm') or
WOAptGet.is_installed(self, 'php8.3-fpm') or
WOAptGet.is_installed(self, 'php8.4-fpm')):
# Check if any LSPHP version is installed
if not any(WOAptGet.is_installed(
self, 'lsphp{0}'.format(v.replace('.', '')))
for v in WOVar.wo_php_versions.values()):
pargs.php = True
Log.debug(self, "Setting packages variable for utils")
packages = packages + [[
"https://raw.githubusercontent.com"
"/rtCamp/eeadmin/master/cache/nginx/"
"clean.php",
"{0}22222/htdocs/cache/nginx/clean.php"
"https://raw.github.com/rlerdorf/"
"opcache-status/master/opcache.php",
"{0}22222/htdocs/cache/opcache/opcache.php"
.format(WOVar.wo_webroot),
"clean.php"],
["https://raw.github.com/rlerdorf/"
"opcache-status/master/opcache.php",
"{0}22222/htdocs/cache/opcache/opcache.php"
.format(WOVar.wo_webroot),
"opcache.php"],
"opcache.php"],
["https://raw.github.com/amnuts/"
"opcache-gui/master/index.php",
"{0}22222/htdocs/cache/opcache/opgui.php"
@@ -522,12 +495,6 @@ class WOStackController(CementBaseController):
if (apt_packages):
Log.debug(self, "Calling pre_pref")
pre_pref(self, apt_packages)
# meminfo = (os.popen('/bin/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.wait(self, "Updating apt-cache ")
WOAptGet.update(self)
Log.valide(self, "Updating apt-cache ")
@@ -574,13 +541,13 @@ class WOStackController(CementBaseController):
if pargs.all:
pargs.web = True
pargs.admin = True
pargs.php73 = True
pargs.php74 = True
pargs.php80 = True
pargs.php81 = True
pargs.php82 = True
pargs.php83 = True
pargs.php84 = True
pargs.php85 = True
pargs.fail2ban = True
pargs.proftpd = True
pargs.utils = True
@@ -607,13 +574,12 @@ class WOStackController(CementBaseController):
pargs.fail2ban = True
pargs.clamav = True
pargs.ufw = True
pargs.ngxblocker = True
# NGINX
# OpenLiteSpeed
if pargs.nginx:
if WOAptGet.is_installed(self, 'nginx-custom'):
Log.debug(self, "Removing apt_packages variable of Nginx")
apt_packages = apt_packages + WOVar.wo_nginx
if WOAptGet.is_installed(self, 'openlitespeed'):
Log.debug(self, "Removing apt_packages variable of OpenLiteSpeed")
apt_packages = apt_packages + WOVar.wo_ols
# Create a dictionary that maps PHP versions to corresponding variables.
wo_vars = {
@@ -623,20 +589,25 @@ class WOStackController(CementBaseController):
'php82': WOVar.wo_php82,
'php83': WOVar.wo_php83,
'php84': WOVar.wo_php84,
'php85': WOVar.wo_php85,
}
# Loop through all versions.
for parg_version, version in WOVar.wo_php_versions.items():
# Check if this version is present in pargs.
if getattr(pargs, parg_version):
short_ver = version.replace('.', '')
Log.debug(self, f"Setting apt_packages variable for PHP {version}")
if WOAptGet.is_installed(self, f'php{version}-fpm'):
if WOAptGet.is_installed(self, f'lsphp{short_ver}'):
apt_packages += wo_vars[parg_version]
# Check if other versions are installed.
if not any(WOAptGet.is_installed(self, f'php{other_version}-fpm') for
other_version in WOVar.wo_php_versions.values() if other_version != version):
if not any(WOAptGet.is_installed(
self, 'lsphp{0}'.format(
other_version.replace('.', '')))
for other_version in WOVar.wo_php_versions.values()
if other_version != version):
apt_packages += WOVar.wo_php_extra
else:
@@ -689,23 +660,25 @@ class WOStackController(CementBaseController):
# brotli
if pargs.brotli:
Log.wait(self, "Disabling Brotli")
WOGit.add(self, ["/etc/nginx"], msg="Commiting pending changes")
if os.path.exists('/etc/nginx/conf.d/brotli.conf'):
WOFileUtils.mvfile(self, '/etc/nginx/conf.d/brotli.conf',
'/etc/nginx/conf.d/brotli.conf.disabled')
ols_conf = '/usr/local/lsws/conf/httpd_config.conf'
if os.path.isfile(ols_conf):
if WOFileUtils.grepcheck(self, ols_conf, 'enableBr.*1'):
WOFileUtils.searchreplace(
self, ols_conf,
'enableBr 1',
'enableBr 0')
WOFileUtils.searchreplace(
self, ols_conf,
'enableGzipCompress 0',
'enableGzipCompress 1')
Log.valide(self, "Disabling Brotli")
WOService.restart_service(self, "lsws")
else:
Log.failed(self, "Disabling Brotli")
Log.error(self, "Brotli is already disabled")
else:
Log.failed(self, "Disabling Brotli")
Log.error(self, "Brotli is already disabled")
if os.path.exists('/etc/nginx/conf.d/gzip.conf.disabled'):
WOFileUtils.mvfile(self, '/etc/nginx/conf.d/gzip.conf.disabled',
'/etc/nginx/conf.d/gzip.conf')
if check_config(self):
Log.valide(self, "Disabling Brotli")
WOGit.add(self, ["/etc/nginx"], msg="Disabling Brotli")
WOService.reload_service(self, "nginx")
else:
Log.failed(self, "Disabling Brotli")
WOGit.rollback(self, ["/etc/nginx"])
Log.error(self, "OpenLiteSpeed is not installed")
# UFW
if pargs.ufw:
@@ -774,8 +747,6 @@ class WOStackController(CementBaseController):
.format(WOVar.wo_webroot),
'{0}22222/htdocs/cache/opcache'
.format(WOVar.wo_webroot),
'{0}22222/htdocs/cache/nginx/'
'clean.php'.format(WOVar.wo_webroot),
'/usr/bin/pt-query-advisor',
'{0}22222/htdocs/db/anemometer'
.format(WOVar.wo_webroot)]
@@ -800,16 +771,6 @@ class WOStackController(CementBaseController):
.format(WOVar.wo_webroot),
'{0}22222/htdocs/index.html'
.format(WOVar.wo_webroot)]
# ngxblocker
if pargs.ngxblocker:
if os.path.isfile('/usr/local/sbin/setup-ngxblocker'):
packages = packages + [
'/usr/local/sbin/setup-ngxblocker',
'/usr/local/sbin/install-ngxblocker',
'/usr/local/sbin/update-ngxblocker',
'/etc/nginx/conf.d/globalblacklist.conf',
'/etc/nginx/conf.d/botblocker-nginx-settings.conf',
'/etc/nginx/bots.d']
if (packages) or (apt_packages):
if (not pargs.force):
@@ -821,8 +782,8 @@ class WOStackController(CementBaseController):
if start_remove != "Y" and start_remove != "y":
Log.error(self, "Not starting stack removal")
if 'nginx-custom' in apt_packages:
WOService.stop_service(self, 'nginx')
if 'openlitespeed' in apt_packages:
WOService.stop_service(self, 'lsws')
if 'mariadb-server' in apt_packages:
WOMysql.backupAll(self)
@@ -904,6 +865,7 @@ class WOStackController(CementBaseController):
pargs.php82 = True
pargs.php83 = True
pargs.php84 = True
pargs.php85 = True
pargs.fail2ban = True
pargs.proftpd = True
pargs.utils = True
@@ -929,15 +891,14 @@ class WOStackController(CementBaseController):
pargs.fail2ban = True
pargs.clamav = True
pargs.ufw = True
pargs.ngxblocker = True
# NGINX
# OpenLiteSpeed
if pargs.nginx:
if WOAptGet.is_installed(self, 'nginx-custom'):
Log.debug(self, "Add Nginx to apt_packages list")
apt_packages = apt_packages + WOVar.wo_nginx
if WOAptGet.is_installed(self, 'openlitespeed'):
Log.debug(self, "Add OpenLiteSpeed to apt_packages list")
apt_packages = apt_packages + WOVar.wo_ols
else:
Log.info(self, "Nginx is not installed")
Log.info(self, "OpenLiteSpeed is not installed")
wo_vars = {
'php74': WOVar.wo_php74,
@@ -946,12 +907,14 @@ class WOStackController(CementBaseController):
'php82': WOVar.wo_php82,
'php83': WOVar.wo_php83,
'php84': WOVar.wo_php84,
'php85': WOVar.wo_php85,
}
for parg_version, version in WOVar.wo_php_versions.items():
if getattr(pargs, parg_version, False):
short_ver = version.replace('.', '')
Log.debug(self, f"Setting apt_packages variable for PHP {version}")
if not WOAptGet.is_installed(self, f'php{version}-fpm'):
if WOAptGet.is_installed(self, f'lsphp{short_ver}'):
apt_packages = apt_packages + wo_vars[parg_version]
else:
Log.debug(self, f"PHP {version} already purged")
@@ -1075,8 +1038,6 @@ class WOStackController(CementBaseController):
.format(WOVar.wo_webroot),
'{0}22222/htdocs/cache/opcache'
.format(WOVar.wo_webroot),
'{0}22222/htdocs/cache/nginx/'
'clean.php'.format(WOVar.wo_webroot),
'/usr/bin/pt-query-advisor',
'{0}22222/htdocs/db/anemometer'
.format(WOVar.wo_webroot)
@@ -1096,17 +1057,6 @@ class WOStackController(CementBaseController):
'{0}22222/htdocs/index.php'
.format(WOVar.wo_webroot)]
# ngxblocker
if pargs.ngxblocker:
if os.path.isfile('/usr/local/sbin/setup-ngxblocker'):
packages = packages + [
'/usr/local/sbin/setup-ngxblocker',
'/usr/local/sbin/install-ngxblocker',
'/usr/local/sbin/update-ngxblocker',
'/etc/nginx/conf.d/globalblacklist.conf',
'/etc/nginx/conf.d/botblocker-nginx-settings.conf',
'/etc/nginx/bots.d']
if (packages) or (apt_packages):
if (not pargs.force):
start_purge = input('Are you sure you to want to'
@@ -1118,8 +1068,8 @@ class WOStackController(CementBaseController):
if start_purge != "Y" and start_purge != "y":
Log.error(self, "Not starting stack purge")
if "nginx-custom" in apt_packages:
WOService.stop_service(self, 'nginx')
if "openlitespeed" in apt_packages:
WOService.stop_service(self, 'lsws')
if "fail2ban" in apt_packages:
WOService.stop_service(self, 'fail2ban')