Skip to main content

Performance Tuning

OpenLiteSpeed is fast by default. These settings push it further — from baseline to production-optimized.


Performance Baseline — Before You Tune

# Establish baseline response time
curl -w "TTFB: %{time_starttransfer}s | Total: %{time_total}s\n" \
-o /dev/null -s https://example.com/

# Check cache headers on a request
curl -I https://example.com/ | grep -iE "cache-control|etag|last-modified|x-cache"

# Check compression
curl -H "Accept-Encoding: gzip,br" -I https://example.com/ | grep -i "content-encoding"

# Check HTTP version
curl -I --http2 https://example.com/ 2>&1 | grep "HTTP/"

# Count requests per second (ab benchmark)
ab -n 1000 -c 10 https://example.com/ | grep "Requests per second"

HTTP/2 and HTTP/3 / QUIC

Enable HTTP/2 (httpd_config.conf — HTTPS listener)

listener HTTPS {
address *:443
secure 1
...
# Enable HTTP/2 via ALPN
alpn h2,http/1.1
}

Enable HTTP/3 / QUIC

listener HTTPS {
address *:443
secure 1
...
alpn h3,h2,http/1.1

# QUIC uses UDP — ensure UDP 443 is open in firewall
quic 1
quicShmDir /dev/shm
}
# Check firewall allows UDP 443 for QUIC
sudo ufw allow 443/udp

# Verify HTTP/2 is negotiated
curl -I --http2 https://example.com/ | head -1
# Expected: HTTP/2 200

# Verify HTTP/3 (needs curl with h3 support)
curl -I --http3 https://example.com/ | head -1

Compression

vhconf.conf — compression settings
# Enable gzip (broad compatibility)
enableGzip 1

# Enable Brotli (better ratio, modern browsers)
enableBr 1

# In httpd_config.conf — compression config block
compress {
# Minimum file size to compress
compressMinSize 1024

# Compress these MIME types
compressibleTypes text/html, text/css, text/javascript,
application/javascript, application/json,
application/xml, text/xml, image/svg+xml,
text/plain, application/xhtml+xml

# Cache compressed output
enableCache 1
}

Verify Compression

# Test gzip
curl -H "Accept-Encoding: gzip" -I https://example.com/ | grep "content-encoding"

# Test Brotli
curl -H "Accept-Encoding: br" -I https://example.com/ | grep "content-encoding"

# Check actual compressed size vs. uncompressed
curl -H "Accept-Encoding: gzip" -s https://example.com/ | wc -c
curl -s https://example.com/ | wc -c

LiteSpeed Cache (LSCache)

LSCache is OLS's built-in full-page cache. It works with the LSCache plugins for WordPress, Joomla, etc.

vhconf.conf — enable LSCache
# Enable the cache engine for this vhost
lsCache {
lscacheOn 1
privateCacheTimeout 60
publicCacheTimeout 86400
dynamicCacheTimeout 0
}
# Check LSCache is responding
curl -I https://example.com/ | grep -i "x-litespeed-cache"
# Expected header: X-LiteSpeed-Cache: hit

# Purge LSCache for a domain (if LSCache plugin installed)
# Usually done via WP admin or curl with purge request
curl -X PURGE https://example.com/

Cache Headers from .htaccess

.htaccess — browser caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
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 text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-font-woff "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
ExpiresDefault "access plus 1 week"
</IfModule>

# Cache-Control headers
<FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico|webp|svg|woff|woff2)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>

Connection Optimization (httpd_config.conf)

# ============================================================
# KEEP-ALIVE
# ============================================================
tuning {
maxKeepAliveReq 1000 # max requests per keep-alive
keepAliveTimeout 5 # seconds to wait for next request
sndBufSize 0 # 0 = OS default (auto)
rcvBufSize 0 # 0 = OS default (auto)
maxReqURLLen 32768 # max URL length
maxReqHeaderSize 65536 # max header size
maxReqBodySize 2G # max upload body
maxDynRespHeaderSize 32768
maxDynRespSize 2G
}

# ============================================================
# CONNECTION LIMITS
# ============================================================
connLimit {
maxConnections 20000 # total server-wide
maxSSLConnections 20000
connHardLimit 10000 # per IP hard limit
connSoftLimit 2000 # per IP soft limit (then throttle)
gracePeriod 15 # seconds before hard limit kicks in
banPeriod 300 # seconds to ban after hard limit
}

Static File Optimization

httpd_config.conf
# File descriptor cache (reduces open() syscalls)
fileCacheStat {
maxCacheEntries 4096
maxCacheFileSize 1M
maxSmallFileSize 4K
smallFileDefaultAge 10
largeFileDefaultAge 30
fileStatRefreshInterval 60
}
vhconf.conf — static file context
# Serve uploads directly as static
context /wp-content/uploads {
location /var/www/example.com/public/wp-content/uploads
allowBrowse 0
accessControl {
allow *
}
}

Reverse Proxy Caching (for Node.js / backend)

vhconf.conf — cache proxy responses
extprocessor node_app {
type proxy
address 127.0.0.1:3000
maxConns 100
persistConn 1
pcKeepAliveTimeout 60
}

context / {
type proxy
handler node_app
addDefaultCharset 0
}

Quick Wins Checklist

OptimizationImpactHow
Enable BrotliMediumenableBr 1 in vhconf
Enable HTTP/2Highalpn h2,http/1.1 in listener
Enable OPcacheVery Highphp.ini opcache.enable=1
Enable LSCacheVery HighlscacheOn 1 in vhconf
Set browser cache headersHigh.htaccess Expires rules
Tune PHP worker countMediumPHP_LSAPI_CHILDREN in extprocessor
Enable LSAPI_AVOID_FORKMediumAdd to extprocessor env
Disable unused PHP extensionsLowRemove from php.ini / conf.d
Enable file stat cacheMediumfileCacheStat block

Benchmarking

# ab (Apache Bench) — simple concurrency test
ab -n 5000 -c 50 https://example.com/

# wrk — modern HTTP benchmarking
wrk -t4 -c100 -d30s https://example.com/

# siege — stress test with multiple URLs
siege -c 25 -r 100 https://example.com/

# hey — simple Go-based load tester
hey -n 10000 -c 100 https://example.com/

# Check memory and CPU during load test
watch -n1 'ps aux | grep lshttpd | grep -v grep | head -5'
watch -n1 'free -m'