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

@@ -13,7 +13,6 @@ 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.nginxhashbucket import hashbucket
from wo.core.services import WOService
from wo.core.shellexec import CommandExecutionError, WOShellExec
from wo.core.sslutils import SSL
@@ -66,46 +65,26 @@ def pre_pref(self, apt_packages):
with os.fdopen(os.open(conf_path, os.O_WRONLY | os.O_CREAT, 0o600), 'w', encoding='utf-8') as configfile:
config.write(configfile)
# add nginx repository
if set(WOVar.wo_nginx).issubset(set(apt_packages)):
if (WOVar.wo_distro == 'ubuntu'):
Log.info(self, "Adding repository for NGINX, please wait...")
WORepo.add(self, ppa=WOVar.wo_nginx_repo)
Log.debug(self, 'Adding ppa for Nginx')
else:
if not os.path.exists('/etc/apt/sources.list.d/wordops.list'):
Log.info(self, "Adding repository for NGINX, please wait...")
Log.debug(self, 'Adding repository for Nginx')
WORepo.add(self, repo_url=WOVar.wo_nginx_repo, repo_name="wordops")
# add OpenLiteSpeed repository
if set(WOVar.wo_ols).issubset(set(apt_packages)):
if not os.path.exists('/etc/apt/sources.list.d/openlitespeed.list'):
Log.info(self, "Adding repository for OpenLiteSpeed, please wait...")
Log.debug(self, 'Adding repository for OpenLiteSpeed')
WORepo.add(self, repo_url=WOVar.wo_ols_repo, repo_name="openlitespeed")
# add php repository
if (('php7.3-fpm' in apt_packages) or
('php7.2-fpm' in apt_packages) or
('php7.4-fpm' in apt_packages) or
('php8.0-fpm' in apt_packages) or
('php8.1-fpm' in apt_packages) or
('php8.2-fpm' in apt_packages) or
('php8.3-fpm' in apt_packages) or
('php8.4-fpm' in apt_packages)):
if (WOVar.wo_distro == 'ubuntu'):
Log.debug(self, 'Adding ppa for PHP')
Log.info(self, "Adding repository for PHP, please wait...")
WORepo.add(self, ppa=WOVar.wo_php_repo)
else:
# Add repository for php
if (WOVar.wo_platform_codename == 'buster'):
php_pref = ("Package: *\nPin: origin "
"packages.sury.org"
"\nPin-Priority: 1000\n")
with open(
'/etc/apt/preferences.d/'
'PHP.pref', mode='w',
encoding='utf-8') as php_pref_file:
php_pref_file.write(php_pref)
if not os.path.exists('/etc/apt/sources.list.d/php.list'):
Log.debug(self, 'Adding repo_url of php for debian')
Log.info(self, "Adding repository for PHP, please wait...")
WORepo.add(self, repo_url=WOVar.wo_php_repo, repo_name="php")
# add LSPHP repository (same as OLS repo)
lsphp_in_packages = False
for version in list(WOVar.wo_php_versions.values()):
short_ver = version.replace('.', '')
if 'lsphp{0}'.format(short_ver) in apt_packages:
lsphp_in_packages = True
break
if lsphp_in_packages:
if not os.path.exists('/etc/apt/sources.list.d/openlitespeed.list'):
Log.info(self, "Adding repository for LSPHP, please wait...")
Log.debug(self, 'Adding repository for LSPHP')
WORepo.add(self, repo_url=WOVar.wo_ols_repo, repo_name="openlitespeed")
# add redis repository
if set(WOVar.wo_redis).issubset(set(apt_packages)):
@@ -116,287 +95,133 @@ def pre_pref(self, apt_packages):
def post_pref(self, apt_packages, packages, upgrade=False):
"""Post activity after installation of packages"""
if (apt_packages):
# Nginx configuration
if set(WOVar.wo_nginx).issubset(set(apt_packages)):
Log.wait(self, "Configuring Nginx")
# Nginx main configuration
ngxcnf = '/etc/nginx/conf.d'
ngxcom = '/etc/nginx/common'
# OpenLiteSpeed configuration
if set(WOVar.wo_ols).issubset(set(apt_packages)):
Log.wait(self, "Configuring OpenLiteSpeed")
ols_conf = WOVar.wo_ols_conf_dir
ols_vhost = WOVar.wo_ols_vhost_dir
ngxroot = '/var/www/'
WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git")
data = dict(tls13=True, release=WOVar.wo_version)
WOGit.add(self, ["/usr/local/lsws/conf"],
msg="Adding OpenLiteSpeed into Git")
# Create vhost directory structure
if not os.path.exists(ols_vhost):
os.makedirs(ols_vhost)
# Determine default PHP version
default_php_short = '84'
for ver_key, ver_num in WOVar.wo_php_versions.items():
short = ver_num.replace('.', '')
if os.path.exists('/usr/local/lsws/lsphp{0}/bin/lsphp'.format(short)):
default_php_short = short
break
# Deploy main httpd_config.conf
data = dict(
server_name=WOVar.wo_fqdn,
release=WOVar.wo_version,
backend_port='22222',
default_php_short=default_php_short)
WOTemplate.deploy(self,
'/etc/nginx/nginx.conf',
'nginx-core.mustache', data, overwrite=True)
'{0}/httpd_config.conf'.format(ols_conf),
'ols-httpd.mustache', data, overwrite=True)
if not os.path.isfile('{0}/gzip.conf.disabled'.format(ngxcnf)):
data = dict(release=WOVar.wo_version)
WOTemplate.deploy(self, '{0}/gzip.conf'.format(ngxcnf),
'gzip.mustache', data)
# Deploy extApp configs for all PHP versions
WOConf.olscommon(self)
if not os.path.isfile('{0}/brotli.conf'.format(ngxcnf)):
WOTemplate.deploy(self,
'{0}/brotli.conf.disabled'
.format(ngxcnf),
'brotli.mustache', data)
# Create log and cert folder for backend
if not os.path.exists('{0}22222/logs'.format(ngxroot)):
Log.debug(self, "Creating directory "
"{0}22222/logs".format(ngxroot))
os.makedirs('{0}22222/logs'.format(ngxroot))
WOTemplate.deploy(self, '{0}/tweaks.conf'.format(ngxcnf),
'tweaks.mustache', data)
if not os.path.exists('{0}22222/cert'.format(ngxroot)):
Log.debug(self, "Creating directory "
"{0}22222/cert".format(ngxroot))
os.makedirs('{0}22222/cert'.format(ngxroot))
# 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 WOFileUtils.grep(self, '/etc/nginx/fastcgi_params',
'HTTP_HOST'):
WOFileUtils.textappend(self, '/etc/nginx/fastcgi_params',
'# Fix for HTTP/3 QUIC HTTP_HOST\n'
'fastcgi_param\tHTTP_HOST\t$host;\n')
if not WOFileUtils.grep(self, '/etc/nginx/proxy_params',
'X-Forwarded-Host'):
WOFileUtils.textappend(self, '/etc/nginx/proxy_params',
'proxy_set_header X-Forwarded-Host $host;\n')
if not WOFileUtils.grep(self, '/etc/nginx/proxy_params',
'X-Forwarded-Port'):
WOFileUtils.textappend(self, '/etc/nginx/proxy_params',
'proxy_set_header X-Forwarded-Port $server_port;\n')
try:
data = dict(php="9000", debug="9001",
php7="9070", debug7="9170",
release=WOVar.wo_version)
WOTemplate.deploy(
self, '{0}/upstream.conf'.format(ngxcnf),
'upstream.mustache', data, overwrite=True)
data = dict(phpconf=(
bool(WOAptGet.is_installed(self, 'php7.2-fpm'))),
release=WOVar.wo_version)
WOTemplate.deploy(
self, '{0}/stub_status.conf'.format(ngxcnf),
'stub_status.mustache', data)
data = dict(release=WOVar.wo_version)
WOTemplate.deploy(
self, '{0}/webp.conf'.format(ngxcnf),
'webp.mustache', data, overwrite=False)
WOTemplate.deploy(
self, '{0}/avif.conf'.format(ngxcnf),
'avif.mustache', data, overwrite=False)
WOTemplate.deploy(
self,
'{0}/map-wp-fastcgi-cache.conf'.format(ngxcnf),
'map-wp.mustache', data)
except CommandExecutionError as e:
Log.debug(self, "{0}".format(e))
# Setup Nginx common directory
if not os.path.exists('{0}'.format(ngxcom)):
Log.debug(self, 'Creating directory'
'/etc/nginx/common')
os.makedirs('/etc/nginx/common')
try:
data = dict(release=WOVar.wo_version)
# Common Configuration
WOTemplate.deploy(self,
'{0}/locations-wo.conf'
.format(ngxcom),
'locations.mustache', data)
# traffic advice file
WOTemplate.deploy(self,
'/var/www/html/'
'.well-known/traffic-advice',
'traffic-advice.mustache', data)
WOTemplate.deploy(self,
'{0}/wpsubdir.conf'
.format(ngxcom),
'wpsubdir.mustache', data)
for wo_php in WOVar.wo_php_versions:
data = dict(upstream="{0}".format(wo_php),
release=WOVar.wo_version)
WOConf.nginxcommon(self)
except CommandExecutionError as e:
Log.debug(self, "{0}".format(e))
with open("/etc/nginx/common/release",
"w", encoding='utf-8') as release_file:
release_file.write("v{0}"
.format(WOVar.wo_version))
release_file.close()
# Following files should not be overwrited
data = dict(webroot=ngxroot, release=WOVar.wo_version)
WOTemplate.deploy(self,
'{0}/acl.conf'
.format(ngxcom),
'acl.mustache', data, overwrite=False)
WOTemplate.deploy(self,
'{0}/blockips.conf'
.format(ngxcnf),
'blockips.mustache', data, overwrite=False)
WOTemplate.deploy(self,
'{0}/fastcgi.conf'
.format(ngxcnf),
'fastcgi.mustache', data, overwrite=True)
# 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"
"'$host \"$request\" $status"
" $body_bytes_sent '\n"
"'\"$http_referer\" "
"\"$http_user_agent\"';\n")
if not os.path.exists('/etc/nginx/bots.d'):
WOFileUtils.textwrite(
self, '/etc/nginx/conf.d/variables-hash.conf',
'variables_hash_max_size 4096;\n'
'variables_hash_bucket_size 4096;')
# Nginx-Plus does not have nginx
# package structure like this
# So creating directories
if not os.path.exists('/etc/nginx/sites-available'):
Log.debug(self, 'Creating directory'
'/etc/nginx/sites-available')
os.makedirs('/etc/nginx/sites-available')
if not os.path.exists('/etc/nginx/sites-enabled'):
Log.debug(self, 'Creating directory'
'/etc/nginx/sites-available')
os.makedirs('/etc/nginx/sites-enabled')
# 22222 port settings
if os.path.exists('/etc/nginx/sites-available/22222'):
Log.debug(self, "looking for the current backend port")
for line in open('/etc/nginx/sites-available/22222',
encoding='utf-8'):
if 'listen' in line:
listen_line = line.strip()
break
port = (listen_line).split(' ')
current_backend_port = (port[1]).strip()
else:
current_backend_port = '22222'
if 'current_backend_port' not in locals():
current_backend_port = '22222'
if not os.path.isdir('{0}22222/conf/ols'.format(ngxroot)):
Log.debug(self, "Creating directory "
"{0}22222/conf/ols".format(ngxroot))
os.makedirs('{0}22222/conf/ols'.format(ngxroot))
# Deploy backend vhost
data = dict(webroot=ngxroot,
release=WOVar.wo_version, port=current_backend_port)
release=WOVar.wo_version,
port='22222',
default_php_short=default_php_short)
backend_vhost_dir = '{0}/_backend'.format(ols_vhost)
if not os.path.exists(backend_vhost_dir):
os.makedirs(backend_vhost_dir)
WOTemplate.deploy(
self,
'/etc/nginx/sites-available/22222',
'22222.mustache', data, overwrite=True)
'{0}/vhconf.conf'.format(backend_vhost_dir),
'ols-backend.mustache', data, overwrite=True)
# Setup admin password
passwd = ''.join([random.choice
(string.ascii_letters + string.digits)
for n in range(24)])
if not os.path.isfile('/etc/nginx/htpasswd-wo'):
if not os.path.isfile('{0}/htpasswd-wo'.format(ols_conf)):
try:
WOShellExec.cmd_exec(
self, "printf \"WordOps:"
"$(openssl passwd -apr1 "
"{password} 2> /dev/null)\n\""
"> /etc/nginx/htpasswd-wo "
"> {conf}/htpasswd-wo "
"2>/dev/null"
.format(password=passwd))
.format(password=passwd, conf=ols_conf))
except CommandExecutionError as e:
Log.debug(self, "{0}".format(e))
Log.error(self, "Failed to save HTTP Auth")
if not os.path.islink('/etc/nginx/sites-enabled/22222'):
# Create Symbolic link for 22222
WOFileUtils.create_symlink(
self, ['/etc/nginx/'
'sites-available/'
'22222',
'/etc/nginx/'
'sites-enabled/'
'22222'])
# Create log and cert folder and softlinks
if not os.path.exists('{0}22222/logs'
.format(ngxroot)):
Log.debug(self, "Creating directory "
"{0}22222/logs "
.format(ngxroot))
os.makedirs('{0}22222/logs'
.format(ngxroot))
if not os.path.exists('{0}22222/cert'
.format(ngxroot)):
Log.debug(self, "Creating directory "
"{0}22222/cert"
.format(ngxroot))
os.makedirs('{0}22222/cert'
.format(ngxroot))
if not os.path.isdir('{0}22222/conf/nginx'
.format(ngxroot)):
Log.debug(self, "Creating directory "
"{0}22222/conf/nginx"
.format(ngxroot))
os.makedirs('{0}22222/conf/nginx'
.format(ngxroot))
WOFileUtils.create_symlink(
self,
['/var/log/nginx/'
'22222.access.log',
'{0}22222/'
'logs/access.log'
.format(ngxroot)]
)
WOFileUtils.create_symlink(
self,
['/var/log/nginx/'
'22222.error.log',
'{0}22222/'
'logs/error.log'
.format(ngxroot)]
)
# Generate self-signed cert for backend if missing
if (not os.path.isfile('{0}22222/cert/22222.key'
.format(ngxroot))):
SSL.selfsignedcert(self, proftpd=False, backend=True)
if not os.path.exists('{0}22222/conf/nginx/ssl.conf'
.format(ngxroot)):
with open("/var/www/22222/conf/nginx/"
"ssl.conf", "w") as php_file:
php_file.write("ssl_certificate "
"/var/www/22222/cert/22222.crt;\n"
"ssl_certificate_key "
"/var/www/22222/cert/22222.key;\n"
"ssl_stapling off;\n")
# Deploy OLS admin password via admpass.sh
if os.path.isfile('/usr/local/lsws/admin/misc/admpass.sh'):
try:
WOShellExec.cmd_exec(
self,
'/usr/local/lsws/admin/misc/admpass.sh '
'--password "{0}"'.format(passwd))
except CommandExecutionError as e:
Log.debug(self, "{0}".format(e))
# traffic advice file
data = dict(release=WOVar.wo_version)
WOTemplate.deploy(self,
'/var/www/html/'
'.well-known/traffic-advice',
'traffic-advice.mustache', data)
# Start/Restart OLS
if not WOService.restart_service(self, 'lsws'):
Log.info(self, "Rolling back to previous configuration")
WOGit.rollback(self, ["/usr/local/lsws/conf"])
if not WOService.restart_service(self, 'lsws'):
Log.error(
self, "There is an error in OpenLiteSpeed configuration.\n"
"Use the command '/usr/local/lsws/bin/openlitespeed -t' to identify "
"the cause of this issue", False)
else:
Log.valide(self, "Configuring OpenLiteSpeed")
WOGit.add(self, ["/usr/local/lsws/conf"],
msg="Adding OpenLiteSpeed into Git")
server_ip = WOFqdn.get_server_ip(self)
if server_ip is None:
server_ip = WOVar.wo_fqdn
if set(["nginx"]).issubset(set(apt_packages)):
if set(["openlitespeed"]).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')
else:
self.msg = (self.msg + ["HTTP Auth User "
"Name: WordOps"] +
@@ -405,177 +230,69 @@ def post_pref(self, apt_packages, packages, upgrade=False):
self.msg = (self.msg + [f'WordOps backend is available on https://{server_ip}:22222 '
f'or https://{WOVar.wo_fqdn}:22222'])
data = dict(release=WOVar.wo_version)
WOTemplate.deploy(self, '/opt/cf-update.sh',
'cf-update.mustache',
data, overwrite=True)
WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775)
Log.debug(self, 'Creating Cloudflare.conf')
WOShellExec.cmd_exec(self, '/opt/cf-update.sh')
WOCron.setcron_weekly(self, '/opt/cf-update.sh '
'> /dev/null 2>&1',
comment='Cloudflare IP refresh cronjob '
'added by WordOps')
# Nginx Configation into GIT
if not WOService.restart_service(self, 'nginx'):
try:
hashbucket(self)
WOService.restart_service(self, 'nginx')
except Exception:
Log.warn(
self, "increasing nginx server_names_hash_bucket_size "
"do not fix the issue")
Log.info(self, "Rolling back to previous configuration")
WOGit.rollback(self, ["/etc/nginx"])
if not WOService.restart_service(self, 'nginx'):
Log.error(
self, "There is an error in Nginx configuration.\n"
"Use the command nginx -t to identify "
"the cause of this issue", False)
else:
Log.valide(self, "Configuring Nginx")
WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git")
if not os.path.isdir('/etc/systemd/system/nginx.service.d'):
WOFileUtils.mkdir(self,
'/etc/systemd/system/nginx.service.d')
if not os.path.isdir(
'/etc/systemd/system/nginx.service.d/limits.conf'):
with open(
'/etc/systemd/system/nginx.service.d/limits.conf',
encoding='utf-8', mode='w') as ngx_limit:
ngx_limit.write('[Service]\nLimitNOFILE=500000')
WOShellExec.cmd_exec(self, 'systemctl daemon-reload')
WOService.restart_service(self, 'nginx')
# php conf
# LSPHP configuration
php_list = []
for version in list(WOVar.wo_php_versions.values()):
package_name = 'php' + version + '-fpm'
short_ver = version.replace('.', '')
package_name = 'lsphp{0}'.format(short_ver)
if package_name in apt_packages:
php_list.append([version])
php_list.append([version, short_ver])
for php_version in php_list:
WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git")
Log.wait(self, "Configuring php{0}-fpm".format(php_version[0]))
for php_info in php_list:
php_version = php_info[0]
php_short = php_info[1]
Log.wait(self, "Configuring lsphp{0}".format(php_short))
ngxroot = '/var/www/'
# Create log directories
if not os.path.exists('/var/log/php/{0}/'.format(php_version[0])):
if not os.path.exists('/var/log/php/{0}/'.format(php_version)):
Log.debug(
self, 'Creating directory /var/log/php/{0}/'
.format(php_version[0]))
os.makedirs('/var/log/php/{0}/'.format(php_version[0]))
.format(php_version))
os.makedirs('/var/log/php/{0}/'.format(php_version))
if not os.path.isfile(
'/etc/php/{0}/fpm/php.ini.orig'.format(php_version[0])):
WOFileUtils.copyfile(self,
'/etc/php/{0}/fpm/php.ini'.format(
php_version[0]),
'/etc/php/{0}/fpm/php.ini.orig'
.format(php_version[0]))
# Configure LSPHP php.ini
lsphp_ini = '/usr/local/lsws/lsphp{0}/etc/php/{1}/litespeed/php.ini'.format(
php_short, php_version)
lsphp_ini_orig = lsphp_ini + '.orig'
# Parse etc/php/x.x/fpm/php.ini
config = configparser.ConfigParser()
Log.debug(self, "configuring php file "
"/etc/php/{0}/fpm/php.ini".format(php_version[0]))
config.read('/etc/php/{0}/fpm/php.ini.orig'.format(php_version[0]))
config['PHP']['expose_php'] = 'Off'
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'] = WOVar.wo_timezone
config['opcache']['opcache.enable'] = '1'
config['opcache']['opcache.interned_strings_buffer'] = '8'
config['opcache']['opcache.max_accelerated_files'] = '10000'
config['opcache']['opcache.memory_consumption'] = '256'
config['opcache']['opcache.save_comments'] = '1'
config['opcache']['opcache.revalidate_freq'] = '5'
config['opcache']['opcache.consistency_checks'] = '0'
config['opcache']['opcache.validate_timestamps'] = '1'
with open('/etc/php/{0}/fpm/php.ini'.format(php_version[0]),
encoding='utf-8', mode='w') as configfile:
Log.debug(self, "Writting php configuration into "
"/etc/php/{0}/fpm/php.ini".format(php_version[0]))
config.write(configfile)
if os.path.isfile(lsphp_ini):
if not os.path.isfile(lsphp_ini_orig):
WOFileUtils.copyfile(self, lsphp_ini, lsphp_ini_orig)
# Render php-fpm pool template for phpx.x
data = dict(pid="/run/php/php{0}-fpm.pid".format(php_version[0]),
error_log="/var/log/php{0}-fpm.log".format(
php_version[0]),
include="/etc/php/{0}/fpm/pool.d/*.conf"
.format(php_version[0]))
WOTemplate.deploy(
self, '/etc/php/{0}/fpm/php-fpm.conf'.format(php_version[0]),
'php-fpm.mustache', data)
php_short = php_version[0].replace(".", "")
data = dict(pool='www-php{0}'.format(php_short),
listen='php{0}-fpm.sock'.format(php_short),
user='www-data',
group='www-data', listenuser='root',
listengroup='www-data', openbasedir=True)
WOTemplate.deploy(self, '/etc/php/{0}/fpm/pool.d/www.conf'
.format(php_version[0]),
'php-pool.mustache', data)
data = dict(pool='www-two-php{0}'.format(php_short),
listen='php{0}-two-fpm.sock'.format(php_short),
user='www-data',
group='www-data', listenuser='root',
listengroup='www-data', openbasedir=True)
config = configparser.ConfigParser()
Log.debug(self, "configuring php file {0}".format(lsphp_ini))
config.read(lsphp_ini_orig)
config['PHP']['expose_php'] = 'Off'
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'] = WOVar.wo_timezone
config['opcache']['opcache.enable'] = '1'
config['opcache']['opcache.interned_strings_buffer'] = '8'
config['opcache']['opcache.max_accelerated_files'] = '10000'
config['opcache']['opcache.memory_consumption'] = '256'
config['opcache']['opcache.save_comments'] = '1'
config['opcache']['opcache.revalidate_freq'] = '5'
config['opcache']['opcache.consistency_checks'] = '0'
config['opcache']['opcache.validate_timestamps'] = '1'
with open(lsphp_ini,
encoding='utf-8', mode='w') as configfile:
Log.debug(self, "Writing php configuration into "
"{0}".format(lsphp_ini))
config.write(configfile)
# Deploy extApp config for this PHP version
data = dict(
php_version=php_version,
short_version=php_short,
release=WOVar.wo_version)
WOTemplate.deploy(self,
'/etc/php/{0}/fpm/pool.d/www-two.conf'.format(
php_version[0]),
'php-pool.mustache', data)
# Generate /etc/php/x.x/fpm/pool.d/debug.conf
WOFileUtils.copyfile(self,
"/etc/php/{0}/fpm/pool.d/www.conf".format(
php_version[0]),
"/etc/php/{0}/fpm/pool.d/debug.conf"
.format(php_version[0]))
WOFileUtils.searchreplace(self,
"/etc/php/{0}/fpm/pool.d/"
"debug.conf".format(php_version[0]),
"[www-php{0}]".format(php_short),
"[debug]")
config = configparser.ConfigParser()
config.read(
'/etc/php/{0}/fpm/pool.d/debug.conf'.format(php_version[0]))
config['debug']['listen'] = '127.0.0.1:91{0}'.format(php_short)
config['debug']['rlimit_core'] = 'unlimited'
config['debug']['slowlog'] = '/var/log/php/{0}/slow.log'.format(
php_version[0])
config['debug']['request_slowlog_timeout'] = '10s'
with open('/etc/php/{0}/fpm/pool.d/debug.conf'
.format(php_version[0]),
encoding='utf-8', mode='w') as confifile:
Log.debug(self,
"writting PHP configuration into "
"/etc/php/{0}/fpm/pool.d/debug.conf"
.format(php_version[0]))
config.write(confifile)
with open("/etc/php/{0}/fpm/pool.d/debug.conf"
.format(php_version[0]),
encoding='utf-8', mode='a') as myfile:
myfile.write("php_admin_value[xdebug.profiler_output_dir] "
"= /tmp/ \nphp_admin_value[xdebug.profiler_"
"output_name] = cachegrind.out.%p-%H-%R "
"\nphp_admin_flag[xdebug.profiler_enable"
"_trigger] = on \nphp_admin_flag[xdebug."
"profiler_enable] = off\n")
# Disable xdebug
if not WOShellExec.cmd_exec(self, "grep -q \';zend_extension\'"
" /etc/php/{0}/mods-available/"
"xdebug.ini".format(php_version[0])):
WOFileUtils.searchreplace(self, "/etc/php/{0}/"
"mods-available/"
"xdebug.ini".format(php_version[0]),
"zend_extension",
";zend_extension")
'{0}/lsphp{1}.conf'
.format(WOVar.wo_ols_conf_dir, php_short),
'ols-extapp.mustache', data)
# PHP and Debug pull configuration
if not os.path.exists('{0}22222/htdocs/fpm/status/'
@@ -585,12 +302,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
.format(ngxroot))
os.makedirs('{0}22222/htdocs/fpm/status/'
.format(ngxroot))
open('{0}22222/htdocs/fpm/status/debug{1}'
.format(ngxroot, php_short),
encoding='utf-8', mode='a').close()
open('{0}22222/htdocs/fpm/status/php{1}'
.format(ngxroot, php_short),
encoding='utf-8', mode='a').close()
# Write info.php
if not os.path.exists('{0}22222/htdocs/php/'
@@ -621,31 +332,10 @@ def post_pref(self, apt_packages, packages, upgrade=False):
'www-data',
'www-data', recursive=True)
# enable imagick php extension
WOShellExec.cmd_exec(self, 'phpenmod -v ALL imagick')
# check service restart or rollback configuration
if not WOService.restart_service(self,
'php{0}-fpm'
.format(php_version[0])):
WOGit.rollback(self, ["/etc/php"], msg="Rollback PHP")
else:
Log.valide(
self, "Configuring php{0}-fpm".format(php_version[0]))
WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git")
if os.path.exists('/etc/nginx/conf.d/upstream.conf'):
if not WOFileUtils.grepcheck(
self, '/etc/nginx/conf.d/upstream.conf',
'php{0}'.format(php_short)):
data = dict(php="9000", debug="9001",
php7="9070", debug7="9170",
php8="9080", debug8="9180",
release=WOVar.wo_version)
WOTemplate.deploy(
self, '/etc/nginx/conf.d/upstream.conf',
'upstream.mustache', data, True)
WOConf.nginxcommon(self)
# Restart OLS to pick up new PHP config
WOService.restart_service(self, 'lsws')
Log.valide(
self, "Configuring lsphp{0}".format(php_short))
# create mysql config if it doesn't exist
if "mariadb-server" in apt_packages:
@@ -707,7 +397,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOFileUtils.copyfile(self, "/etc/mysql/my.cnf",
"/etc/mysql/my.cnf.default-pkg")
wo_ram = psutil.virtual_memory().total / (1024 * 1024)
# set InnoDB variable depending on the RAM available
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)
@@ -735,7 +424,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
else:
WOTemplate.deploy(
self, '/etc/mysql/my.cnf', 'my.mustache', data)
# replacing default values
Log.debug(self, "Tuning MySQL configuration")
if os.path.isdir('/etc/systemd/system/mariadb.service.d'):
if not os.path.isfile(
@@ -748,16 +436,9 @@ def post_pref(self, apt_packages, packages, upgrade=False):
'[Service]\nLimitNOFILE=500000')
WOShellExec.cmd_exec(self, 'systemctl daemon-reload')
Log.valide(self, "Tuning MySQL configuration")
# set innodb_buffer_pool_instances depending
# on the amount of RAM
WOService.restart_service(self, 'mariadb')
# 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')
WOCron.setcron_weekly(self, 'mysqlcheck -Aos --auto-repair '
'> /dev/null 2>&1',
comment='MySQL optimization cronjob '
@@ -771,8 +452,8 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOGit.add(self, ["/etc/fail2ban"],
msg="Adding Fail2ban into Git")
Log.wait(self, "Configuring Fail2Ban")
nginxf2b = bool(os.path.exists('/var/log/nginx'))
data = dict(release=WOVar.wo_version, nginx=nginxf2b)
olsf2b = bool(os.path.exists('/usr/local/lsws/bin/openlitespeed'))
data = dict(release=WOVar.wo_version, ols=olsf2b)
WOTemplate.deploy(
self,
'/etc/fail2ban/jail.d/custom.conf',
@@ -820,7 +501,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
WOService.restart_service(self, 'proftpd')
if os.path.isfile('/etc/ufw/ufw.conf'):
# add rule for proftpd with UFW
if WOFileUtils.grepcheck(
self, '/etc/ufw/ufw.conf', 'ENABLED=yes'):
try:
@@ -861,18 +541,15 @@ def post_pref(self, apt_packages, packages, upgrade=False):
Log.failed(self, "Configuring Sendmail")
if "ufw" in apt_packages:
# check if ufw is already enabled
if not WOFileUtils.grep(self,
'/etc/ufw/ufw.conf', 'ENABLED=yes'):
Log.wait(self, "Configuring UFW")
# check if ufw script is already created
if not os.path.isfile("/opt/ufw.sh"):
data = dict()
WOTemplate.deploy(self, '/opt/ufw.sh',
'ufw.mustache',
data, overwrite=False)
WOFileUtils.chmod(self, "/opt/ufw.sh", 0o700)
# setup ufw rules
WOShellExec.cmd_exec(self, "bash /opt/ufw.sh")
Log.valide(self, "Configuring UFW")
else:
@@ -880,31 +557,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
# Redis configuration
if "redis-server" in apt_packages:
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")
if os.path.isfile("/etc/nginx/nginx.conf"):
if 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 '$host \"$request\" "
"$status $body_bytes_sent '\n'\"$http_referer\" "
"\"$http_user_agent\"';\n")
# set redis.conf parameter
# set maxmemory 10% for ram below 512MB and 20% for others
# set maxmemory-policy allkeys-lru
# enable systemd service
WOGit.add(self, ["/etc/redis"],
msg="Adding Redis into Git")
Log.debug(self, "Enabling redis systemd service")
@@ -1157,7 +809,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
wo_grant_host = self.app.config.get('mysql', 'grant-host')
else:
wo_grant_host = 'localhost'
# check if mysql credentials are available
if (WOMysql.mariadb_ping(self)
and wo_grant_host == 'localhost'):
try:
@@ -1284,20 +935,6 @@ def post_pref(self, apt_packages, packages, upgrade=False):
for x in packages):
WOFileUtils.chmod(self, "/usr/bin/pt-query-advisor", 0o775)
# ngxblocker
if any('/usr/local/sbin/install-ngxblocker' == x[1]
for x in packages):
# remove duplicate directives
if os.path.exists('/etc/nginx/conf.d/variables-hash.conf'):
WOFileUtils.rm(self, '/etc/nginx/conf.d/variables-hash.conf')
WOFileUtils.chmod(
self, "/usr/local/sbin/install-ngxblocker", 0o700)
WOShellExec.cmd_exec(self, '/usr/local/sbin/install-ngxblocker -x')
WOFileUtils.chmod(
self, "/usr/local/sbin/update-ngxblocker", 0o700)
if not WOService.restart_service(self, 'nginx'):
Log.error(self, 'ngxblocker install failed')
def pre_stack(self):
"""Inital server configuration and tweak"""
@@ -1309,20 +946,15 @@ def pre_stack(self):
if os.path.exists('/var/lib/wo/version.txt'):
with open('/var/lib/wo/version.txt',
mode='r', encoding='utf-8') as wo_ver:
# check version written in version.txt
wo_check = bool(wo_ver.read().strip() ==
'{0}'.format(WOVar.wo_version))
else:
wo_check = False
if wo_check is False:
# wo sysctl tweaks
# check system type
wo_arch = bool((os.uname()[4]) == 'x86_64')
if os.path.isfile('/proc/1/environ'):
# detect lxc containers
wo_lxc = WOFileUtils.grepcheck(
self, '/proc/1/environ', 'container=lxc')
# detect wsl
wo_wsl = WOFileUtils.grepcheck(
self, '/proc/1/environ', 'wsl')
else:
@@ -1334,12 +966,12 @@ def pre_stack(self):
WOTemplate.deploy(
self, '/etc/sysctl.d/60-wo-tweaks.conf',
'sysctl.mustache', data, True)
# use tcp_bbr congestion algorithm only on new kernels
if (WOVar.wo_platform_codename == 'focal' or
WOVar.wo_platform_codename == 'buster' or
WOVar.wo_platform_codename == 'jammy' or
WOVar.wo_platform_codename == 'bullseye' or
WOVar.wo_platform_codename == 'bookworm'):
WOVar.wo_platform_codename == 'bookworm' or
WOVar.wo_platform_codename == 'trixie'):
try:
WOShellExec.cmd_exec(
self, 'modprobe tcp_bbr')
@@ -1373,7 +1005,6 @@ def pre_stack(self):
Log.debug(self, str(e))
Log.warn(self, "failed to tweak sysctl")
# apply sysctl tweaks
WOShellExec.cmd_exec(
self, 'sysctl -eq -p /etc/sysctl.d/60-wo-tweaks.conf')
@@ -1401,9 +1032,7 @@ def pre_stack(self):
'root soft nofile 500000\n')
# custom motd-news
data = dict()
# check if update-motd.d directory exist
if os.path.isdir('/etc/update-motd.d/'):
# render custom motd template
WOTemplate.deploy(
self, '/etc/update-motd.d/98-wo-update',
'wo-update.mustache', data)