feat: convert WordOps from Nginx to OpenLiteSpeed + LSPHP + LSCache
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:
@@ -1,3 +1,4 @@
|
||||
[Definition]
|
||||
failregex = ^ \[error\] \d+#\d+: .* forbidden .*, client: <HOST>, .*$
|
||||
failregex = ^ \[error\] .* forbidden .*, client: <HOST>, .*$
|
||||
^\S+ \S+ \[.*\] .* 403 .* <HOST> .*$
|
||||
ignoreregex =
|
||||
|
||||
@@ -4,23 +4,17 @@ ignoreip = 127.0.0.1/8 ::1
|
||||
[recidive]
|
||||
enabled = true
|
||||
|
||||
{{#nginx}}[nginx-http-auth]
|
||||
enabled = true
|
||||
logpath = /var/log/nginx/*error*.log
|
||||
|
||||
[nginx-botsearch]
|
||||
enabled = true
|
||||
logpath = /var/log/nginx/*access*.log
|
||||
|
||||
[wo-wordpress]
|
||||
{{#ols}}[wo-wordpress]
|
||||
enabled = true
|
||||
filter = wo-wordpress
|
||||
action = iptables-multiport[name="wo-wordpress", port="http,https"]
|
||||
logpath = /var/log/nginx/*access*.log
|
||||
logpath = /usr/local/lsws/logs/access.log
|
||||
/usr/local/lsws/conf/vhosts/*/logs/ols.access_log
|
||||
maxretry = 5
|
||||
|
||||
[nginx-forbidden]
|
||||
[ols-forbidden]
|
||||
enabled = true
|
||||
filter = nginx-forbidden
|
||||
action = iptables-multiport[name="nginx-forbidden", port="http,https"]
|
||||
logpath = /var/log/nginx/*error*.log{{/nginx}}
|
||||
action = iptables-multiport[name="ols-forbidden", port="http,https"]
|
||||
logpath = /usr/local/lsws/logs/error.log
|
||||
/usr/local/lsws/conf/vhosts/*/logs/ols.error_log{{/ols}}
|
||||
|
||||
9
wo/cli/templates/info_ols.mustache
Normal file
9
wo/cli/templates/info_ols.mustache
Normal file
@@ -0,0 +1,9 @@
|
||||
OpenLiteSpeed ({{version}}):
|
||||
|
||||
server_name {{server_name}}
|
||||
max_connections {{max_connections}}
|
||||
max_ssl_connections {{max_ssl_connections}}
|
||||
keepalive_timeout {{keepalive_timeout}}
|
||||
gzip_compress {{gzip_compress}}
|
||||
brotli_compress {{brotli_compress}}
|
||||
quic_enabled {{quic_enabled}}
|
||||
16
wo/cli/templates/ols-acl.mustache
Normal file
16
wo/cli/templates/ols-acl.mustache
Normal file
@@ -0,0 +1,16 @@
|
||||
# WordOps (wo) Access Control - OpenLiteSpeed
|
||||
# Protect locations using HTTP authentication or IP address
|
||||
realm WordOpsAdmin {
|
||||
userDB {
|
||||
location /usr/local/lsws/conf/htpasswd-wo
|
||||
}
|
||||
}
|
||||
|
||||
context / {
|
||||
realm WordOpsAdmin
|
||||
authName "Restricted Area"
|
||||
required valid-user
|
||||
accessControl {
|
||||
allow 127.0.0.1, ::1
|
||||
}
|
||||
}
|
||||
104
wo/cli/templates/ols-backend.mustache
Normal file
104
wo/cli/templates/ols-backend.mustache
Normal file
@@ -0,0 +1,104 @@
|
||||
# WordOps Admin Backend Virtual Host - WordOps {{release}}
|
||||
# Port {{port}}
|
||||
|
||||
docRoot {{webroot}}22222/htdocs
|
||||
vhDomain _backend
|
||||
enableGzip 1
|
||||
enableBr 1
|
||||
|
||||
errorlog {{webroot}}22222/logs/ols.error_log {
|
||||
useServer 0
|
||||
logLevel ERROR
|
||||
rollingSize 10M
|
||||
}
|
||||
|
||||
accesslog {{webroot}}22222/logs/ols.access_log {
|
||||
useServer 0
|
||||
rollingSize 10M
|
||||
keepDays 30
|
||||
compressArchive 0
|
||||
}
|
||||
|
||||
index {
|
||||
useServer 0
|
||||
indexFiles index.php, index.html, index.htm
|
||||
autoIndex 1
|
||||
}
|
||||
|
||||
# PHP handler
|
||||
scripthandler {
|
||||
add lsapi:lsphp{{default_php_short}} php
|
||||
}
|
||||
|
||||
extprocessor lsphp{{default_php_short}} {
|
||||
type lsapi
|
||||
address uds://tmp/lshttpd/lsphp{{default_php_short}}.sock
|
||||
maxConns 10
|
||||
env PHP_LSAPI_CHILDREN=10
|
||||
env LSAPI_AVOID_FORK=200M
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
pcKeepAliveTimeout 60
|
||||
respBuffer 0
|
||||
autoStart 2
|
||||
path /usr/local/lsws/lsphp{{default_php_short}}/bin/lsphp
|
||||
backlog 100
|
||||
instances 1
|
||||
priority 0
|
||||
memSoftLimit 2047M
|
||||
memHardLimit 2047M
|
||||
procSoftLimit 1400
|
||||
procHardLimit 1500
|
||||
}
|
||||
|
||||
# Rewrite rules
|
||||
rewrite {
|
||||
enable 1
|
||||
autoLoadHtaccess 1
|
||||
rules <<<END_rules
|
||||
RewriteRule ^(.*)$ /index.php?$1 [QSA,L]
|
||||
END_rules
|
||||
}
|
||||
|
||||
# HTTP Auth realm for backend
|
||||
realm WordOpsBackend {
|
||||
userDB {
|
||||
location /usr/local/lsws/conf/htpasswd-wo
|
||||
}
|
||||
}
|
||||
|
||||
# Require auth for the whole backend
|
||||
context / {
|
||||
realm WordOpsBackend
|
||||
authName "Restricted Area"
|
||||
required valid-user
|
||||
allowBrowse 1
|
||||
addDefaultCharset off
|
||||
}
|
||||
|
||||
# Netdata proxy context
|
||||
context /netdata/ {
|
||||
type proxy
|
||||
handler netdata_backend
|
||||
addDefaultCharset off
|
||||
}
|
||||
|
||||
extprocessor netdata_backend {
|
||||
type proxy
|
||||
address 127.0.0.1:19999
|
||||
maxConns 100
|
||||
pcKeepAliveTimeout 60
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
respBuffer 0
|
||||
}
|
||||
|
||||
# SSL Configuration
|
||||
vhssl {
|
||||
keyFile /var/www/22222/cert/22222.key
|
||||
certFile /var/www/22222/cert/22222.crt
|
||||
sslProtocol 24
|
||||
}
|
||||
|
||||
# Include custom configs
|
||||
include {{webroot}}22222/conf/ols/*.conf
|
||||
23
wo/cli/templates/ols-extapp.mustache
Normal file
23
wo/cli/templates/ols-extapp.mustache
Normal file
@@ -0,0 +1,23 @@
|
||||
# LSPHP {{php_version}} External App Configuration - WordOps {{release}}
|
||||
# DO NOT MODIFY, ALL CHANGES WILL BE LOST AFTER AN WordOps (wo) UPDATE
|
||||
|
||||
extprocessor lsphp{{short_version}} {
|
||||
type lsapi
|
||||
address uds://tmp/lshttpd/lsphp{{short_version}}.sock
|
||||
maxConns 10
|
||||
env PHP_LSAPI_CHILDREN=10
|
||||
env LSAPI_AVOID_FORK=200M
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
pcKeepAliveTimeout 60
|
||||
respBuffer 0
|
||||
autoStart 2
|
||||
path /usr/local/lsws/lsphp{{short_version}}/bin/lsphp
|
||||
backlog 100
|
||||
instances 1
|
||||
priority 0
|
||||
memSoftLimit 2047M
|
||||
memHardLimit 2047M
|
||||
procSoftLimit 1400
|
||||
procHardLimit 1500
|
||||
}
|
||||
208
wo/cli/templates/ols-httpd.mustache
Normal file
208
wo/cli/templates/ols-httpd.mustache
Normal file
@@ -0,0 +1,208 @@
|
||||
# OpenLiteSpeed Main Configuration - WordOps {{release}}
|
||||
# DO NOT MODIFY, ALL CHANGES WILL BE LOST AFTER AN WordOps (wo) UPDATE
|
||||
|
||||
serverName {{server_name}}
|
||||
user nobody
|
||||
group nogroup
|
||||
priority 0
|
||||
inMemBufSize 60M
|
||||
swappingDir /tmp/lshttpd/swap
|
||||
autoFix503 1
|
||||
gracefulRestartTimeout 300
|
||||
mime conf/mime.properties
|
||||
showVersionNumber 0
|
||||
adminEmails root@localhost
|
||||
|
||||
errorlog /usr/local/lsws/logs/error.log {
|
||||
logLevel DEBUG
|
||||
debugLevel 0
|
||||
rollingSize 10M
|
||||
enableStderrLog 1
|
||||
}
|
||||
|
||||
accesslog /usr/local/lsws/logs/access.log {
|
||||
rollingSize 10M
|
||||
keepDays 30
|
||||
compressArchive 0
|
||||
}
|
||||
|
||||
indexFiles index.php, index.html, index.htm
|
||||
|
||||
expires {
|
||||
enableExpires 1
|
||||
expiresByType image/*=A604800,text/css=A604800,application/x-javascript=A604800,application/javascript=A604800,font/*=A604800,application/x-font-ttf=A604800
|
||||
}
|
||||
|
||||
tuning {
|
||||
maxConnections 10000
|
||||
maxSSLConnections 10000
|
||||
connTimeout 300
|
||||
maxKeepAliveReq 10000
|
||||
keepAliveTimeout 5
|
||||
sndBufSize 0
|
||||
rcvBufSize 0
|
||||
maxReqURLLen 32768
|
||||
maxReqHeaderSize 65536
|
||||
maxReqBodySize 2047M
|
||||
maxDynRespHeaderSize 32768
|
||||
maxDynRespSize 2047M
|
||||
maxCachedFileSize 4096
|
||||
totalInMemCacheSize 20M
|
||||
maxMMapFileSize 256K
|
||||
totalMMapCacheSize 40M
|
||||
useSendfile 1
|
||||
fileETag 28
|
||||
enableGzipCompress 1
|
||||
enableBrCompress 1
|
||||
enableDynGzipCompress 1
|
||||
gzipCompressLevel 6
|
||||
brStaticCompressLevel 6
|
||||
gzipAutoUpdateStatic 1
|
||||
gzipStaticCompressLevel 6
|
||||
gzipMaxFileSize 10M
|
||||
gzipMinFileSize 300
|
||||
enableQuic 1
|
||||
quicShmDir /dev/shm
|
||||
}
|
||||
|
||||
fileAccessControl {
|
||||
followSymbolLink 1
|
||||
checkSymbolLink 0
|
||||
requiredPermissionMask 000
|
||||
restrictedPermissionMask 000
|
||||
}
|
||||
|
||||
perClientConnLimit {
|
||||
staticReqPerSec 0
|
||||
dynReqPerSec 0
|
||||
outBandwidth 0
|
||||
inBandwidth 0
|
||||
softLimit 10000
|
||||
hardLimit 10000
|
||||
gracePeriod 15
|
||||
banPeriod 300
|
||||
}
|
||||
|
||||
CGIRLimit {
|
||||
maxCGIInstances 20
|
||||
minUID 11
|
||||
minGID 10
|
||||
priority 0
|
||||
CPUSoftLimit 10
|
||||
CPUHardLimit 50
|
||||
memSoftLimit 1460M
|
||||
memHardLimit 1470M
|
||||
procSoftLimit 400
|
||||
procHardLimit 450
|
||||
}
|
||||
|
||||
accessDenyDir {
|
||||
dir /
|
||||
dir /etc/*
|
||||
dir /dev/*
|
||||
dir conf/*
|
||||
dir admin/conf/*
|
||||
}
|
||||
|
||||
scripthandler {
|
||||
add lsapi:lsphp{{default_php_short}} php
|
||||
}
|
||||
|
||||
railsDefaults {
|
||||
maxConns 1
|
||||
env LSAPI_MAX_IDLE=60
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
pcKeepAliveTimeout 60
|
||||
respBuffer 0
|
||||
backlog 50
|
||||
runOnStartUp 3
|
||||
extMaxIdleTime 300
|
||||
priority 3
|
||||
memSoftLimit 2047M
|
||||
memHardLimit 2047M
|
||||
procSoftLimit 500
|
||||
procHardLimit 600
|
||||
}
|
||||
|
||||
wsgiDefaults {
|
||||
maxConns 5
|
||||
env LSAPI_MAX_IDLE=60
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
pcKeepAliveTimeout 60
|
||||
respBuffer 0
|
||||
backlog 50
|
||||
runOnStartUp 3
|
||||
extMaxIdleTime 300
|
||||
priority 3
|
||||
memSoftLimit 2047M
|
||||
memHardLimit 2047M
|
||||
procSoftLimit 500
|
||||
procHardLimit 600
|
||||
}
|
||||
|
||||
nodeDefaults {
|
||||
maxConns 5
|
||||
env LSAPI_MAX_IDLE=60
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
pcKeepAliveTimeout 60
|
||||
respBuffer 0
|
||||
backlog 50
|
||||
runOnStartUp 3
|
||||
extMaxIdleTime 300
|
||||
priority 3
|
||||
memSoftLimit 2047M
|
||||
memHardLimit 2047M
|
||||
procSoftLimit 500
|
||||
procHardLimit 600
|
||||
}
|
||||
|
||||
module cache {
|
||||
ls_enabled 1
|
||||
checkPrivateCache 1
|
||||
checkPublicCache 1
|
||||
maxCacheObjSize 10000000
|
||||
maxStaleAge 200
|
||||
qsCache 1
|
||||
reqCookieCache 1
|
||||
respCookieCache 1
|
||||
ignoreReqCacheCtrl 1
|
||||
ignoreRespCacheCtrl 0
|
||||
enableCache 0
|
||||
expireInSeconds 3600
|
||||
enablePrivateCache 0
|
||||
privateExpireInSeconds 3600
|
||||
}
|
||||
|
||||
# Listener for HTTP on port 80
|
||||
listener Default {
|
||||
address *:80
|
||||
secure 0
|
||||
}
|
||||
|
||||
# Listener for HTTPS on port 443
|
||||
listener Secure {
|
||||
address *:443
|
||||
secure 1
|
||||
keyFile /usr/local/lsws/conf/example.key
|
||||
certFile /usr/local/lsws/conf/example.crt
|
||||
sslProtocol 24
|
||||
enableQuic 1
|
||||
}
|
||||
|
||||
# Listener for backend on port 22222
|
||||
listener Backend {
|
||||
address *:{{backend_port}}
|
||||
secure 1
|
||||
keyFile /var/www/22222/cert/22222.key
|
||||
certFile /var/www/22222/cert/22222.crt
|
||||
sslProtocol 24
|
||||
}
|
||||
|
||||
# Include external app definitions
|
||||
include /usr/local/lsws/conf/lsphp*.conf
|
||||
|
||||
# Include virtual host mappings
|
||||
include /usr/local/lsws/conf/vhosts/*/vhconf.conf
|
||||
53
wo/cli/templates/ols-security.htaccess.mustache
Normal file
53
wo/cli/templates/ols-security.htaccess.mustache
Normal file
@@ -0,0 +1,53 @@
|
||||
# General Security .htaccess Rules - WordOps {{release}}
|
||||
# DO NOT MODIFY, ALL CHANGES WILL BE LOST AFTER AN WordOps (wo) UPDATE
|
||||
|
||||
# Deny access to hidden files (except .well-known)
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteRule "(^|/)\.(?!well-known\/)" - [F]
|
||||
</IfModule>
|
||||
|
||||
# Deny access to backup, log, and config files
|
||||
<FilesMatch "\.(old|orig|original|php#|php~|php_bak|save|swo|aspx?|tpl|sh|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rdf|gz|zip|bz2|7z|pem|asc|conf|dump)$">
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Deny access to readme, license, and similar files
|
||||
<FilesMatch "(readme|license|example|README|LEGALNOTICE|INSTALLATION|CHANGELOG)\.(txt|html|md)$">
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Cache static files
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresByType image/jpeg "access plus 1 year"
|
||||
ExpiresByType image/gif "access plus 1 year"
|
||||
ExpiresByType image/png "access plus 1 year"
|
||||
ExpiresByType image/webp "access plus 1 year"
|
||||
ExpiresByType image/svg+xml "access plus 1 year"
|
||||
ExpiresByType image/x-icon "access plus 1 year"
|
||||
ExpiresByType text/css "access plus 1 year"
|
||||
ExpiresByType application/javascript "access plus 1 year"
|
||||
ExpiresByType application/x-javascript "access plus 1 year"
|
||||
ExpiresByType font/ttf "access plus 1 year"
|
||||
ExpiresByType font/otf "access plus 1 year"
|
||||
ExpiresByType font/woff "access plus 1 year"
|
||||
ExpiresByType font/woff2 "access plus 1 year"
|
||||
</IfModule>
|
||||
|
||||
# CORS headers for static assets
|
||||
<IfModule mod_headers.c>
|
||||
<FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font\.css|css|js|gif|png|jpe?g|svg|svgz|ico|webp)$">
|
||||
Header set Access-Control-Allow-Origin "*"
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
|
||||
# Security headers
|
||||
<IfModule mod_headers.c>
|
||||
Header set X-Frame-Options "SAMEORIGIN"
|
||||
Header set X-Content-Type-Options "nosniff"
|
||||
Header set Referrer-Policy "strict-origin-when-cross-origin"
|
||||
Header set X-Powered-By "WordOps"
|
||||
</IfModule>
|
||||
10
wo/cli/templates/ols-ssl.mustache
Normal file
10
wo/cli/templates/ols-ssl.mustache
Normal file
@@ -0,0 +1,10 @@
|
||||
# OpenLiteSpeed SSL Configuration - WordOps
|
||||
# Domain: {{domain}}
|
||||
|
||||
vhssl {
|
||||
keyFile {{ssl_live_path}}/{{domain}}/key.pem
|
||||
certFile {{ssl_live_path}}/{{domain}}/fullchain.pem
|
||||
certChain 1
|
||||
sslProtocol 24
|
||||
enableQuic 1
|
||||
}
|
||||
17
wo/cli/templates/ols-vhost-mapping.mustache
Normal file
17
wo/cli/templates/ols-vhost-mapping.mustache
Normal file
@@ -0,0 +1,17 @@
|
||||
# Virtual Host Mapping for {{site_name}} - WordOps {{release}}
|
||||
virtualhost {{site_name}} {
|
||||
vhRoot {{webroot}}
|
||||
configFile {{vhost_conf_path}}
|
||||
allowSymbolLink 1
|
||||
enableScript 1
|
||||
restrained 0
|
||||
}
|
||||
|
||||
# Listener mappings
|
||||
listener Default {
|
||||
map {{site_name}} {{site_name}}{{#www_alias}}, www.{{site_name}}{{/www_alias}}
|
||||
}
|
||||
|
||||
listener Secure {
|
||||
map {{site_name}} {{site_name}}{{#www_alias}}, www.{{site_name}}{{/www_alias}}
|
||||
}
|
||||
122
wo/cli/templates/ols-vhost.mustache
Normal file
122
wo/cli/templates/ols-vhost.mustache
Normal file
@@ -0,0 +1,122 @@
|
||||
# OpenLiteSpeed Virtual Host Configuration - WordOps {{release}}
|
||||
# Domain: {{site_name}}
|
||||
|
||||
docRoot {{webroot}}/htdocs
|
||||
vhDomain {{site_name}}
|
||||
vhAliases www.{{site_name}}
|
||||
enableGzip 1
|
||||
enableBr 1
|
||||
|
||||
errorlog {{webroot}}/logs/ols.error_log {
|
||||
useServer 0
|
||||
logLevel ERROR
|
||||
rollingSize 10M
|
||||
}
|
||||
|
||||
accesslog {{webroot}}/logs/ols.access_log {
|
||||
useServer 0
|
||||
rollingSize 10M
|
||||
keepDays 30
|
||||
compressArchive 0
|
||||
}
|
||||
|
||||
index {
|
||||
useServer 0
|
||||
indexFiles {{^static}}index.php, {{/static}}index.html, index.htm
|
||||
autoIndex 0
|
||||
}
|
||||
|
||||
{{^static}}
|
||||
# PHP handler via LSAPI
|
||||
scripthandler {
|
||||
add lsapi:lsphp{{php_short}} php
|
||||
}
|
||||
{{/static}}
|
||||
|
||||
# External app - LSPHP
|
||||
extprocessor lsphp{{php_short}} {
|
||||
type lsapi
|
||||
address uds://tmp/lshttpd/lsphp{{php_short}}.sock
|
||||
maxConns 10
|
||||
env PHP_LSAPI_CHILDREN=10
|
||||
env LSAPI_AVOID_FORK=200M
|
||||
initTimeout 60
|
||||
retryTimeout 0
|
||||
pcKeepAliveTimeout 60
|
||||
respBuffer 0
|
||||
autoStart 2
|
||||
path /usr/local/lsws/lsphp{{php_short}}/bin/lsphp
|
||||
backlog 100
|
||||
instances 1
|
||||
priority 0
|
||||
memSoftLimit 2047M
|
||||
memHardLimit 2047M
|
||||
procSoftLimit 1400
|
||||
procHardLimit 1500
|
||||
}
|
||||
|
||||
# LSCache module configuration
|
||||
module cache {
|
||||
ls_enabled 1
|
||||
checkPrivateCache 1
|
||||
checkPublicCache 1
|
||||
maxCacheObjSize 10000000
|
||||
maxStaleAge 200
|
||||
qsCache 1
|
||||
reqCookieCache 1
|
||||
respCookieCache 1
|
||||
ignoreReqCacheCtrl 1
|
||||
ignoreRespCacheCtrl 0
|
||||
{{#wp}}
|
||||
enableCache 1
|
||||
{{/wp}}
|
||||
{{^wp}}
|
||||
enableCache 0
|
||||
{{/wp}}
|
||||
expireInSeconds 3600
|
||||
enablePrivateCache 0
|
||||
privateExpireInSeconds 3600
|
||||
}
|
||||
|
||||
# Rewrite rules
|
||||
rewrite {
|
||||
enable 1
|
||||
autoLoadHtaccess 1
|
||||
}
|
||||
|
||||
# Security context for wp-admin
|
||||
context /wp-admin/ {
|
||||
location {{webroot}}/htdocs/wp-admin/
|
||||
allowBrowse 1
|
||||
{{^static}}
|
||||
addDefaultCharset off
|
||||
phpIniOverride {
|
||||
}
|
||||
{{/static}}
|
||||
}
|
||||
|
||||
# Security - deny hidden files
|
||||
context exp:/(\.(?!well-known)) {
|
||||
allowBrowse 0
|
||||
}
|
||||
|
||||
# Let's Encrypt validation
|
||||
context /.well-known/acme-challenge/ {
|
||||
location /var/www/html/.well-known/acme-challenge/
|
||||
allowBrowse 1
|
||||
addDefaultCharset off
|
||||
}
|
||||
|
||||
# Include per-site custom configurations
|
||||
include {{webroot}}/conf/ols/*.conf
|
||||
|
||||
{{#ssl}}
|
||||
# SSL Configuration
|
||||
vhssl {
|
||||
keyFile {{ssl_live_path}}/{{site_name}}/key.pem
|
||||
certFile {{ssl_live_path}}/{{site_name}}/fullchain.pem
|
||||
certChain 1
|
||||
sslProtocol 24
|
||||
enableQuic 1
|
||||
}
|
||||
{{/ssl}}
|
||||
49
wo/cli/templates/ols-wpcommon.htaccess.mustache
Normal file
49
wo/cli/templates/ols-wpcommon.htaccess.mustache
Normal file
@@ -0,0 +1,49 @@
|
||||
# WordPress Common Security Rules - WordOps {{release}}
|
||||
# DO NOT MODIFY, ALL CHANGES WILL BE LOST AFTER AN WordOps (wo) UPDATE
|
||||
# This file is auto-generated and placed in the site's htdocs/.htaccess
|
||||
|
||||
# Limit access to wp-login.php to prevent brute force attacks
|
||||
<Files wp-login.php>
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_METHOD} POST
|
||||
RewriteCond %{HTTP_REFERER} !^https?://(.*)?{{site_name}} [NC]
|
||||
RewriteRule .* - [F]
|
||||
</IfModule>
|
||||
</Files>
|
||||
|
||||
# Block xmlrpc.php except Jetpack IPs
|
||||
<Files xmlrpc.php>
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
Allow from 122.248.245.244
|
||||
Allow from 54.217.201.243
|
||||
Allow from 54.232.116.4
|
||||
Allow from 192.0.80.0/20
|
||||
Allow from 192.0.96.0/20
|
||||
Allow from 192.0.112.0/20
|
||||
Allow from 195.234.108.0/22
|
||||
</Files>
|
||||
|
||||
# Block wp-config.txt
|
||||
<Files wp-config.txt>
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</Files>
|
||||
|
||||
# Deny access to PHP files in uploads directory
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteRule ^wp-content/uploads/.*\.php$ - [F]
|
||||
RewriteRule ^wp-content/uploads/edd/.*\.zip$ / [R=301,L]
|
||||
</IfModule>
|
||||
|
||||
# Mitigate DoS attack with WordPress script concatenation
|
||||
<Files "load-scripts.php">
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</Files>
|
||||
<Files "load-styles.php">
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
</Files>
|
||||
227
wo/cli/templates/wp-fort-knox.php
Normal file
227
wo/cli/templates/wp-fort-knox.php
Normal file
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Plugin Name: WP Fort Knox
|
||||
* Description: Enhanced WordPress security plugin that disables file modifications and plugin management from wp-admin while preserving WP-CLI functionality.
|
||||
* Version: 2.0.0
|
||||
* Author: WEFIXIT
|
||||
* Network: true
|
||||
*
|
||||
* Security Features:
|
||||
* - Defines DISALLOW_FILE_MODS constant to block file changes from wp-admin
|
||||
* - Filters plugin installation, upload, update, and deletion capabilities at runtime (non-destructive)
|
||||
* - Blocks creation of administrator users through wp-admin interface
|
||||
* - Prevents role elevation to administrator outside of WP-CLI
|
||||
* - Hides administrator role from user role dropdown in wp-admin
|
||||
* - Displays admin notices to inform users about restrictions
|
||||
* - Preserves WP-CLI functionality for all operations
|
||||
* - Can be disabled temporarily via constant or filter
|
||||
*
|
||||
* This is a Must-Use plugin - place directly in /wp-content/mu-plugins/
|
||||
*
|
||||
* Temporary Disable:
|
||||
* Add to wp-config.php: define('WP_FORT_KNOX_DISABLED', true);
|
||||
* Or use filter: add_filter('wp_fort_knox_disabled', '__return_true');
|
||||
*
|
||||
* WP-CLI Commands for Administrative Tasks:
|
||||
*
|
||||
* User Management:
|
||||
* wp user create admin admin@example.com --role=administrator --user_pass=secure_password
|
||||
* wp user set-role username administrator
|
||||
* wp user list --fields=ID,user_login,roles
|
||||
*
|
||||
* Plugin Management:
|
||||
* wp plugin install plugin-name --activate
|
||||
* wp plugin update plugin-name
|
||||
* wp plugin update --all
|
||||
* wp plugin list
|
||||
* wp plugin deactivate plugin-name
|
||||
* wp plugin delete plugin-name
|
||||
*
|
||||
* Theme Management:
|
||||
* wp theme install theme-name --activate
|
||||
* wp theme update theme-name
|
||||
* wp theme update --all
|
||||
* wp theme list
|
||||
*
|
||||
* Core Updates:
|
||||
* wp core update
|
||||
* wp core update --version=6.4.1
|
||||
* wp core check-update
|
||||
*
|
||||
* @package WPFortKnox
|
||||
* @since 1.0.0
|
||||
* @version 2.0.0
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WP_Fort_Knox {
|
||||
|
||||
private $managed_capabilities = [
|
||||
'install_plugins',
|
||||
'upload_plugins',
|
||||
'update_plugins',
|
||||
'delete_plugins'
|
||||
];
|
||||
|
||||
public function __construct() {
|
||||
// Check if disabled
|
||||
if ( $this->is_disabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply security measures
|
||||
$this->apply_security();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin should be disabled
|
||||
*/
|
||||
private function is_disabled() {
|
||||
// Always allow WP-CLI
|
||||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for disable constant
|
||||
if ( defined( 'WP_FORT_KNOX_DISABLED' ) && WP_FORT_KNOX_DISABLED ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow filter for programmatic control
|
||||
if ( apply_filters( 'wp_fort_knox_disabled', false ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply all security measures
|
||||
*/
|
||||
private function apply_security() {
|
||||
// Block file modifications
|
||||
if ( ! defined( 'DISALLOW_FILE_MODS' ) ) {
|
||||
define( 'DISALLOW_FILE_MODS', true );
|
||||
}
|
||||
|
||||
// Remove plugin capabilities at runtime (non-destructive)
|
||||
add_filter( 'user_has_cap', [ $this, 'filter_capabilities' ], 999, 4 );
|
||||
|
||||
// Hide administrator role from user creation/edit screens
|
||||
add_filter( 'editable_roles', [ $this, 'hide_administrator_role' ] );
|
||||
|
||||
// Block admin user creation via wp-admin
|
||||
add_filter( 'pre_insert_user_data', [ $this, 'block_admin_creation' ], 10, 3 );
|
||||
|
||||
// Prevent role elevation to administrator
|
||||
add_action( 'set_user_role', [ $this, 'prevent_admin_elevation' ], 10, 3 );
|
||||
|
||||
// Show notice on plugins page
|
||||
add_action( 'admin_notices', [ $this, 'show_admin_notice' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter user capabilities at runtime
|
||||
*/
|
||||
public function filter_capabilities( $allcaps, $caps, $args, $user ) {
|
||||
// Only filter for non-CLI requests
|
||||
foreach ( $this->managed_capabilities as $cap ) {
|
||||
if ( isset( $allcaps[ $cap ] ) ) {
|
||||
$allcaps[ $cap ] = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $allcaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide administrator role from dropdowns
|
||||
*/
|
||||
public function hide_administrator_role( $roles ) {
|
||||
unset( $roles['administrator'] );
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block admin user creation
|
||||
*/
|
||||
public function block_admin_creation( $data, $update, $user_id ) {
|
||||
// Allow updates to existing users
|
||||
if ( $update ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Block new admin creation
|
||||
if ( isset( $data['role'] ) && $data['role'] === 'administrator' ) {
|
||||
wp_die(
|
||||
'Administrator account creation is disabled. Use WP-CLI: wp user create username email@example.com --role=administrator',
|
||||
'Security Policy',
|
||||
[ 'back_link' => true ]
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent elevation to administrator role
|
||||
*/
|
||||
public function prevent_admin_elevation( $user_id, $role, $old_roles ) {
|
||||
// If trying to add administrator role
|
||||
if ( $role === 'administrator' && ! in_array( 'administrator', $old_roles ) ) {
|
||||
// Revert the change
|
||||
$user = get_userdata( $user_id );
|
||||
if ( $user ) {
|
||||
$user->remove_role( 'administrator' );
|
||||
$user->add_role( $old_roles[0] ?? 'subscriber' );
|
||||
|
||||
// Log the attempt
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( sprintf(
|
||||
'[WP Fort Knox] Blocked administrator elevation for user %s (ID: %d)',
|
||||
$user->user_login,
|
||||
$user_id
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show admin notice on relevant pages
|
||||
*/
|
||||
public function show_admin_notice() {
|
||||
// Only show to users who would normally have capability
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
// Show on plugins page
|
||||
if ( $screen && $screen->id === 'plugins' ) {
|
||||
?>
|
||||
<div class="notice notice-info">
|
||||
<p><strong>WP Fort Knox:</strong> Plugin management is disabled in wp-admin. Use WP-CLI for all plugin operations. To disable temporarily, contact support.</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Show on users page when trying to add new
|
||||
if ( $screen && $screen->id === 'user' && $screen->action === 'add' ) {
|
||||
?>
|
||||
<div class="notice notice-warning">
|
||||
<p><strong>WP Fort Knox:</strong> Administrator role creation is disabled. Use WP-CLI for all user operations. To disable temporarily, contact support.</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize - no activation hooks needed for mu-plugins
|
||||
new WP_Fort_Knox();
|
||||
Reference in New Issue
Block a user