Series: WordPress Performance on DirectAdmin (Rocky Linux 9)
Phase 1: Foundations — Part 1 of 30
Overview and Goals
This article is part of the “WordPress Performance on DirectAdmin (Rocky Linux 9)” series (phase 1: foundations). The goal is to get a clean, measurable baseline and apply safe, DirectAdmin-aware performance tuning you can build on in later phases.
Scope and assumptions:
- Rocky Linux 9 (EL9), DirectAdmin-managed hosting
- PHP-FPM (per-user or per-domain) via DirectAdmin
- Apache with or without NGINX reverse proxy (DirectAdmin defaults)
- Shell and WP-CLI access
1. Establish a Baseline
1.1 Identify stack and DirectAdmin configuration
First confirm how DirectAdmin is serving WordPress for the target domain.
sudo /usr/local/directadmin/custombuild/build options | egrep "(webserver|php|nginx)"
Check per-domain web stack in DirectAdmin:
- DirectAdmin > User Level > Domain Setup > domain.tld
- Note if NGINX is enabled as a reverse proxy or if it is Apache-only.
Confirm PHP-FPM mode:
sudo /usr/local/directadmin/custombuild/build php n
Look for php1_mode=php-fpm and whether you are using per-user or per-domain pools (common on newer DirectAdmin installs).
1.2 Install baseline tooling
Install CLI tools for measurement and debugging:
sudo dnf install -y epel-release
sudo dnf install -y htop iotop curl wget git ncdu
sudo dnf install -y wrk
Optional (for more advanced load testing):
sudo dnf install -y nodejs
sudo npm install -g k6
Install WP-CLI globally (if not already):
cd /usr/local/src
sudo curl -o wp-cli.phar https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
sudo php wp-cli.phar --info
sudo chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
Test from a WordPress docroot (replace with your path):
cd /home/USER/domains/example.com/public_html
wp core version
1.3 Capture baseline performance
Use a single page as your reference, typically the homepage or a heavy landing page.
URL="https://example.com/"
wrk -t4 -c40 -d30s "$URL"
Record:
- Requests/sec
- Latency distribution
- CPU load (
htop) and memory usage during the test
Also log a simple single-request timing:
curl -o /dev/null -s -w "DNS: %{time_namelookup}\nConnect: %{time_connect}\nTTFB: %{time_starttransfer}\nTotal: %{time_total}\n" "$URL"
2. PHP-FPM Pool Tuning (DirectAdmin-Specific)
PHP-FPM is usually the first bottleneck on small to medium DirectAdmin servers. DirectAdmin manages pool configs under /usr/local/phpXY/lib/php-fpm.conf and per-user/per-domain pool files under /usr/local/phpXY/etc/php-fpm.d/ (exact path may vary slightly by version).
2.1 Locate the relevant pool
For a given domain, identify the pool file. Common patterns:
- Per-user:
/usr/local/php81/etc/php-fpm.d/USER.conf - Per-domain (newer DirectAdmin templates):
/usr/local/php81/etc/php-fpm.d/USER-domain.tld.conf
sudo ls /usr/local/php*/etc/php-fpm.d/ | grep -i user_or_domain
Warning: Editing pool files incorrectly can break PHP for that user/domain. Apply changes incrementally and be ready to revert.
2.2 Choose sane starting values
For a typical 2–4 vCPU, 4–8 GB RAM Rocky 9 server hosting a few WordPress sites, a good starting point per busy pool:
- pm:
ondemand(for low concurrency) ordynamic(for steady traffic) - pm.max_children: 10–20 (per busy site)
- pm.start_servers: 2–4
- pm.min_spare_servers: 2
- pm.max_spare_servers: 6
- pm.process_idle_timeout: 10–20s
Estimate memory usage per PHP process:
ps -o rss,cmd -C php-fpm | head
RSS (KB) × pm.max_children should stay well below available RAM.
2.3 Edit pool config
Open the pool file for the relevant PHP version:
sudo nano /usr/local/php81/etc/php-fpm.d/USER.conf
Example tuned block:
[USER]
user = USER
group = USER
listen = /usr/local/php81/sockets/USER.sock
listen.owner = USER
listen.group = USER
listen.mode = 0660
pm = dynamic
pm.max_children = 15
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 6
pm.max_requests = 500
pm.process_idle_timeout = 15s
Restart PHP-FPM for that version:
sudo systemctl restart php-fpm81.service
Downtime note: Restarting PHP-FPM briefly interrupts PHP responses (usually <1s). During traffic peaks, coordinate restarts during low-traffic windows.
2.4 Persisting changes via DirectAdmin templates
DirectAdmin can overwrite pool configs during updates. To keep tuning persistent, adjust the PHP-FPM templates:
- Template directory (example):
/usr/local/directadmin/data/templates/custom/ - Copy default templates:
php-fpm.conf,php-fpm_pool.conf
sudo mkdir -p /usr/local/directadmin/data/templates/custom
cd /usr/local/directadmin/data/templates
sudo cp php-fpm* /usr/local/directadmin/data/templates/custom/
Edit the custom/php-fpm_pool.conf and set your preferred pm.* values, using DirectAdmin placeholders (e.g. |MAX_CHILDREN|) if you want per-user overrides later.
Rebuild configs:
sudo /usr/local/directadmin/custombuild/build php_fpm
3. Web Server and DirectAdmin Templates
3.1 Apache MPM tuning
On Rocky 9, Apache config is typically under /etc/httpd/conf/httpd.conf and /etc/httpd/conf.modules.d/. DirectAdmin often uses event MPM by default.
Check MPM:
sudo httpd -M | egrep "(mpm_event|mpm_prefork|mpm_worker)"
For PHP-FPM, event or worker is preferred over prefork. If you must change MPM, do it via DirectAdmin custombuild:
sudo /usr/local/directadmin/custombuild/build set apache_mpm event
sudo /usr/local/directadmin/custombuild/build apache
sudo systemctl restart httpd
Downtime note: Rebuilding Apache and restarting httpd will cause brief downtime; schedule appropriately.
3.2 KeepAlive and basic Apache tuning
In /etc/httpd/conf/httpd.conf (or DA-managed includes), tune:
sudo nano /etc/httpd/conf/httpd.conf
Suggested starting values:
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 2
<IfModule mpm_event_module>
ServerLimit 16
StartServers 4
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 5000
</IfModule>
Reload:
sudo systemctl reload httpd
3.3 NGINX reverse proxy (if enabled)
When DirectAdmin uses NGINX as a reverse proxy, configs are under /etc/nginx/ and DirectAdmin templates under /usr/local/directadmin/data/templates/.
Check NGINX status:
sudo systemctl status nginx
Basic NGINX tuning in /etc/nginx/nginx.conf:
worker_processes auto;
worker_connections 4096;
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
types_hash_max_size 2048;
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}
Test and reload:
sudo nginx -t
sudo systemctl reload nginx
4. WordPress-Level Performance
4.1 Disable slow or unused plugins/themes
From the WordPress docroot:
cd /home/USER/domains/example.com/public_html
wp plugin status
Deactivate obvious unused plugins:
wp plugin deactivate plugin-slug-1 plugin-slug-2
Switch away from heavy multipurpose themes where possible; at minimum, disable unused bundled plugins.
4.2 Enable page caching
On DirectAdmin, filesystem-based full-page caching is usually the simplest and most robust approach.
Install a caching plugin (example: Cache Enabler, WP Super Cache, or similar). Once installed, verify cache status via headers:
curl -I https://example.com/ | egrep -i "(cache|x-cache)"
Then compare performance with wrk before/after enabling cache.
4.3 Object caching (optional at this phase)
On Rocky 9, Redis is a good option if you have multiple WordPress sites or heavy authenticated traffic.
sudo dnf install -y redis
sudo systemctl enable --now redis
Secure Redis (bind to localhost):
sudo sed -i 's/^bind .*/bind 127.0.0.1/' /etc/redis/redis.conf
sudo systemctl restart redis
Install a Redis object cache plugin, then:
cd /home/USER/domains/example.com/public_html
wp redis enable
Monitor Redis memory usage with redis-cli info memory and adjust maxmemory in /etc/redis/redis.conf if needed.
5. Logging, Monitoring, and Testing Changes
5.1 Tail logs during tests
For Apache:
sudo tail -f /var/log/httpd/access_log /var/log/httpd/error_log
For NGINX (if used):
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
For PHP-FPM 8.1 (example):
sudo tail -f /var/log/php-fpm/81-php-fpm.log
Watch for:
server reached pm.max_children(increasepm.max_childrenor optimize PHP)- 502/504 errors (proxy timeouts, PHP-FPM overload)
- Slow script warnings
5.2 Repeat performance tests
After each tuning step, rerun your baseline tests:
wrk -t4 -c40 -d30s "$URL"
Use curl to compare TTFB and total time:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}\nTotal: %{time_total}\n" "$URL"
Optional k6 script (save as load.js):
import http from 'k6/http';
import { sleep } from 'k6';
export let options = {
vus: 20,
duration: '1m',
};
export default function () {
http.get('https://example.com/');
sleep(1);
}
Run:
k6 run load.js
6. Per-Domain Tuning Workflow Checklist
Use this checklist per WordPress domain on DirectAdmin:
- Identify PHP version and pool file for the domain.
- Measure baseline with
wrkandcurl. - Estimate PHP-FPM memory usage and set
pm.*values safely. - Restart PHP-FPM and confirm no errors in logs.
- Review Apache/NGINX configs; apply basic keepalive and worker tuning.
- Ensure full-page cache is enabled and working (check headers).
- Optionally enable Redis object cache for dynamic-heavy workloads.
- Retest performance and compare metrics to baseline.
- Persist changes via DirectAdmin custom templates where applicable.
7. Firewalld and Network Considerations
On Rocky 9, ensure only necessary ports are exposed. This does not directly speed up WordPress, but reduces attack surface and noisy traffic.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Keep Redis bound to 127.0.0.1 as shown earlier; do not open Redis ports externally.
8. Summary and Next Steps
In this phase we focused on foundational performance tuning for WordPress on DirectAdmin with Rocky Linux 9:
- Establishing a measurable performance baseline using
wrk,curl, and WP-CLI - DirectAdmin-aware PHP-FPM pool tuning and template persistence
- Basic Apache/NGINX configuration tuning aligned with PHP-FPM
- Enabling and verifying WordPress page and object caching
- Systematic testing and log-based validation of each change
Later phases in this series will go deeper into opcode caching, database tuning (MariaDB/MySQL), advanced caching strategies, and automation of these configurations across multiple DirectAdmin servers.
This article offers general technical guidance. Validate all configurations in a safe environment before applying them to production.
Next: How WordPress Actually Handles a Page Request (And Where Performance Is Lost)


Leave a Reply