Series: WordPress Performance on DirectAdmin (Rocky Linux 9)
Phase 1: Foundations — Part 3 of 30
Baseline Metrics for WordPress on DirectAdmin (Rocky Linux 9)
This post is part 3 of the "WordPress Performance on DirectAdmin (Rocky Linux 9)" series (Phase 1: Foundations). Here we focus on establishing repeatable, low-noise baseline metrics before we start tuning PHP-FPM, NGINX/Apache, or MySQL in later phases.
Goals and scope
The objective is to build a simple, reproducible baseline for a DirectAdmin-managed WordPress instance on Rocky Linux 9:
- Confirm the stack (PHP-FPM pools, web server mode, per-domain config paths).
- Measure current performance under light and moderate load.
- Capture system, PHP-FPM, and web server behavior with logs and metrics.
- Document a repeatable test procedure you can re-run after every change.
We’ll assume:
- DirectAdmin on Rocky Linux 9 (EL9), using PHP-FPM (recommended) and Apache or NGINX (or NGINX reverse-proxy to Apache).
- Shell access with
sudo. - At least one WordPress site under a DirectAdmin user (e.g.
user1, domainexample.com).
1. Confirm DirectAdmin stack and paths
1.1 Check web stack mode
In DirectAdmin, confirm which web stack is active:
- DirectAdmin > Extra Features > CustomBuild 2.0 > Edit Options
- Look for:
- webserver (e.g.
apache,nginx_apache, ornginx) - php1_mode (should be
php-fpmfor this series)
- webserver (e.g.
On Rocky Linux 9, confirm services:
sudo systemctl status httpd nginx php-fpm --no-pager
Typical DirectAdmin layouts:
- Apache only:
httpd+php-fpm - NGINX reverse-proxy to Apache:
nginx+httpd+php-fpm - NGINX + PHP-FPM only:
nginx+php-fpm
1.2 PHP-FPM pool locations (DirectAdmin)
DirectAdmin manages per-user PHP-FPM pools. Common EL9 paths:
- Global config:
/etc/php-fpm.conf - Pool configs:
/etc/php-fpm.d/*.conf - DirectAdmin-managed pools (by user):
/usr/local/directadmin/data/users/<user>/php/php-fpm<version>.conf(source templates)
List pools:
grep -R "\[" /etc/php-fpm.d/*.conf
sudo php-fpm -tt
We won’t change pool settings yet; we just need to know where they are for later phases.
1.3 Per-domain web server configs
DirectAdmin generates per-domain configs from templates:
- Apache vhosts:
/etc/httpd/conf/extra/httpd-vhosts.conf(includes per-domain files in/usr/local/directadmin/data/users/<user>/httpd) - NGINX:
/etc/nginx/nginx.confwith includes from/etc/nginx/conf.d/and/usr/local/directadmin/data/users/<user>/nginx.conf - Templates (do not edit lightly):
/usr/local/directadmin/data/templates/
We’ll later modify templates for persistent tuning; for baselining, we only read configs and logs.
2. Install basic tooling on Rocky Linux 9
Install minimal load testing and diagnostic tools. These commands are safe and idempotent.
sudo dnf install -y epel-release
# HTTP load tools (choose at least one)
sudo dnf install -y wrk
# or:
sudo dnf install -y golang-k6
# Network debugging
sudo dnf install -y curl
# System observation
sudo dnf install -y htop iotop strace
# Log viewing helpers
sudo dnf install -y jq
Ensure firewalld allows HTTP/HTTPS:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
3. Prepare WordPress for testing
3.1 Confirm WP-CLI
WP-CLI is the safest way to interact with WordPress from the shell.
cd /var/www/html 2>/dev/null || true
# DirectAdmin often uses:
# /home/<user>/domains/<domain>/public_html
# Example:
cd /home/user1/domains/example.com/public_html
wp core version
If wp is not found, install it (safe):
cd /usr/local/bin
sudo curl -O 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 wp
Then re-run:
cd /home/user1/domains/example.com/public_html
wp core version
3.2 Create a test page
Use a dedicated page for performance checks (no heavy plugins or builders).
cd /home/user1/domains/example.com/public_html
# Create a simple "baseline" page via WP-CLI
wp post create --post_type=page --post_title="Baseline Test" \
--post_status=publish --post_content="Baseline performance test page."
Get the permalink:
wp post list --post_type=page --fields=ID,post_title,post_name,post_status
Assume slug is baseline-test; URL will be something like:
https://example.com/baseline-test/
4. Establish single-request baselines
4.1 Warm up PHP-FPM and caches
First hit the page a few times to warm PHP-FPM, opcode cache, and any page cache plugin.
curl -k -I https://example.com/baseline-test/
curl -k -I https://example.com/baseline-test/
curl -k -I https://example.com/baseline-test/
Use -k only if you have self-signed certificates; otherwise omit it.
4.2 Measure TTFB and response size
Use curl with timing:
curl -k -o /dev/null -s -w \
"dns: %{time_namelookup}s connect: %{time_connect}s ttfb: %{time_starttransfer}s total: %{time_total}s size: %{size_download} bytes
" \
https://example.com/baseline-test/
Record:
- time_starttransfer (TTFB)
- time_total (full load)
- size_download
Do 5 runs and record the median. A reasonable starting goal on a small VPS (1–2 vCPU) for a simple page:
- TTFB: < 250 ms (local network)
- Total: < 400 ms
5. Light load testing (wrk)
Warning: Load tests can temporarily increase CPU and memory usage. Avoid running this on production during peak traffic.
5.1 Basic wrk test
From the server itself (low network latency):
wrk -t2 -c20 -d30s https://example.com/baseline-test/
- -t2: 2 threads
- -c20: 20 concurrent connections
- -d30s: 30 seconds
Record:
- Requests/sec
- Latency distribution (50%, 75%, 90%, 99%)
Good starting expectations for a modest DirectAdmin EL9 VPS (2 vCPU, 4 GB RAM, basic PHP-FPM config):
- Simple cached page: 500–1500 req/s
- Uncached dynamic page: 50–300 req/s
5.2 Optional: k6 script
If you prefer more structured scenarios, create a simple k6 script:
cat > baseline.js << 'EOF'
import http from 'k6/http';
import { check } from 'k6';
export let options = {
vus: 20,
duration: '30s',
};
export default function () {
let res = http.get('https://example.com/baseline-test/');
check(res, {
'status is 200': (r) => r.status === 200,
'ttfb < 300ms': (r) => r.timings.waiting < 300,
});
}
EOF
k6 run baseline.js
Again, run off-peak and record throughput and 95th percentile latency.
6. Observe logs and PHP-FPM behavior
6.1 Tail web server logs
While running wrk or k6, tail logs in another terminal.
Apache logs (DirectAdmin per-domain)
sudo tail -f /var/log/httpd/access_log /var/log/httpd/error_log
Or per-domain logs, often:
sudo tail -f /var/log/httpd/domains/example.com.log \
/var/log/httpd/domains/example.com.error.log
NGINX logs
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
# Per-domain (DirectAdmin):
sudo tail -f /var/log/nginx/domains/example.com.log \
/var/log/nginx/domains/example.com.error.log
Watch for:
- 5xx errors (502/503/504)
- Long request times in access logs (if configured)
- Upstream timeouts (NGINX + PHP-FPM/Apache)
6.2 PHP-FPM logs and status
Check PHP-FPM logs (path may vary by PHP version, e.g. php-fpm80):
sudo journalctl -u php-fpm --since "10 minutes ago" --no-pager
Look for:
server reached pm.max_children setting- Slow script warnings
- Pool-level errors for the DirectAdmin user
List pools and basic settings:
grep -E "^\[|pm\." /etc/php-fpm.d/*.conf
We’ll tune pm.max_children, pm.max_requests, etc., in a later phase; for now, just note current values.
7. System-level metrics during load
Run a light load test while observing system metrics.
7.1 CPU, memory, load
htop
Key points during the 30s test:
- CPU usage > 90%: may be CPU-bound (PHP, MySQL, or NGINX/Apache).
- High load average (much > vCPU count): potential process contention or I/O wait.
- Swap usage increasing: memory pressure; PHP-FPM pool size may be too large.
7.2 Disk I/O
sudo iotop -o
Watch for:
- High write IOPS from MySQL or PHP logs.
- High read IOPS from WordPress files (plugins/themes) or MySQL data.
8. Quick WordPress-level checks
8.1 Check active plugins and theme
From the site directory:
cd /home/user1/domains/example.com/public_html
wp plugin list --status=active
wp theme list
Note any heavy plugins (page builders, security suites, backup plugins running on-page loads). Disable non-essential plugins during baseline tests to isolate platform performance:
# Example: disable a non-critical plugin
wp plugin deactivate some-heavy-plugin
Record which plugins were active during baseline so you can keep tests comparable later.
8.2 Confirm caching behavior
For each test run, check response headers:
curl -k -I https://example.com/baseline-test/
Look for:
- Page cache plugin headers (e.g.
x-litespeed-cache,x-wp-cache,x-cache). - Proxy/cache headers (e.g.
via,x-cacheif behind an external CDN).
Record whether baselines are "cached" or "uncached". You’ll want both in later phases.
9. Build a repeatable baseline checklist
Use this short checklist every time you change DirectAdmin templates, PHP-FPM pools, or NGINX/Apache configs in later phases.
9.1 Pre-test checklist
- Confirm services:
sudo systemctl status nginx httpd php-fpm
- Confirm WordPress is reachable:
curl -k -I https://example.com/baseline-test/
- Confirm domain logs exist:
ls /var/log/httpd/domains/(Apache)ls /var/log/nginx/domains/(NGINX)
- Note plugin and theme state:
wp plugin list --status=activewp theme list
9.2 Baseline test sequence
- Warm up:
curl -k -I https://example.com/baseline-test/(3–5 times)
- Single-request timing:
- Run the
curl -wcommand 5 times and record median TTFB and total.
- Run the
- Light load:
wrk -t2 -c20 -d30s https://example.com/baseline-test/- Record requests/sec and 95th percentile latency.
- Observe logs during the wrk run:
- Web server access/error logs.
- PHP-FPM journal logs.
- Observe system during the wrk run:
htopfor CPU/memory.iotop -ofor disk I/O.
- Document results:
- Include date/time, config versions, plugin list, and any anomalies.
10. Notes on DirectAdmin template safety
DirectAdmin regenerates configs from templates (e.g. in /usr/local/directadmin/data/templates/). Any manual edits in /etc/httpd or /etc/nginx can be overwritten by CustomBuild runs.
For this baseline phase:
- Do not edit template files yet.
- Only inspect existing configs and logs.
- In later phases we’ll use custom templates (e.g.
custom/nginx_server.conf) for persistent tuning.
11. What to keep for future phases
Before moving on to tuning PHP-FPM pools and NGINX/Apache in the next posts, keep the following data:
- Single-request TTFB and total time for
/baseline-test/. - wrk (or k6) throughput and latency metrics.
- PHP-FPM pool settings for the DirectAdmin user (from
/etc/php-fpm.d). - Web server mode (Apache, NGINX, or NGINX+Apache) from DirectAdmin CustomBuild.
- Active plugin list and theme.
- Any 5xx errors or timeouts observed in logs under load.
These baselines are your reference when we later adjust:
- PHP-FPM
pm.*values per DirectAdmin user. - NGINX/Apache timeouts, buffers, and keepalive settings.
- OPcache and MySQL configuration on Rocky Linux 9.
This article offers general technical guidance. Validate all configurations in a safe environment before applying them to production.
Previous: How WordPress Actually Handles a Page Request (And Where Performance Is Lost)
Next: DirectAdmin vs cPanel for WordPress Performance


Leave a Reply