Quick Summary
Many website owners try to improve Core Web Vitals by compressing images, removing JavaScript or changing the site’s theme. Sometimes this helps, but poor scores are often caused much earlier in the request lifecycle. Slow page generation, overloaded PHP, inefficient database queries, missing Redis Object Cache, disabled compression or incorrect cache headers can all delay the first HTML response before the browser even starts loading front-end assets.
Before making changes, identify where the delay occurs. If Google PageSpeed Insights reports a high Initial Server Response Time and Chrome DevTools shows most of the request spent in the Waiting (TTFB) phase, focus first on server response time, PHP-FPM, database performance, Redis, HTTP cache headers, HTTP/2 or HTTP/3, and SSL configuration. Front-end optimisation becomes far more effective only after the server delivers HTML quickly.
At Era.Host, this diagnostic approach regularly identifies the real bottleneck within minutes, avoiding hours spent optimising images, CSS or JavaScript when the server itself is responsible for poor Core Web Vitals.
How to Measure TTFB and Determine Whether the Server Is the Problem
If Google PageSpeed Insights reports a high Initial Server Response Time or poor LCP, start by identifying where the delay occurs rather than optimising images or changing the site’s theme. If the browser spends most of its time waiting for the first byte of HTML, the bottleneck is usually the server or the application, not the front end.
Begin with Google PageSpeed Insights, then open the same page in Chrome DevTools. In the Network tab, disable browser caching, reload the page, select the initial HTML request and inspect the Waiting (TTFB) value in the Timing tab. If most of the request time is spent there, continue with server-side diagnostics.
Measure TTFB directly with curl:
curl -o /dev/null -s -w \
"DNS: %{time_namelookup}\n\
Connect: %{time_connect}\n\
TLS: %{time_appconnect}\n\
TTFB: %{time_starttransfer}\n\
Total: %{time_total}\n" \
https://example.com/
Review each stage separately. time_namelookup measures DNS resolution, time_connect the TCP connection, time_appconnect the TLS handshake and time_starttransfer the actual TTFB. If DNS, TCP and TLS complete quickly but time_starttransfer is high, the delay occurs while the server generates the page.
Test more than the homepage. Measure categories, product pages, login pages and other dynamic content several times and at different times of day. If only dynamic pages show high TTFB or results fluctuate significantly, the cause is often PHP-FPM saturation, database load or scheduled background tasks.
While testing, review the Nginx and PHP-FPM logs for errors such as upstream timed out, PHP slow log entries or warnings that PHP-FPM workers are exhausted. These indicate that HTML generation, rather than front-end resources, is responsible for the delay.
Once Chrome DevTools and curl both show consistently high time_starttransfer while static assets load normally, focus on PHP execution, database performance, Redis Object Cache, server-side caching and PHP-FPM configuration before optimising images, CSS or JavaScript.
How to Distinguish Network Latency from Slow Page Generation
A slow website is not always caused by PHP or the database. Delays may occur before the server starts generating HTML because of slow DNS resolution, TCP connection setup, TLS negotiation or network routing. Before optimising the application, identify where the time is actually being spent.
Measure the request with curl:
curl -o /dev/null -s -w \
"DNS: %{time_namelookup}\n\
Connect: %{time_connect}\n\
TLS: %{time_appconnect}\n\
TTFB: %{time_starttransfer}\n\
Total: %{time_total}\n" \
https://example.com/
If time_namelookup or time_appconnect is unusually high, investigate DNS or TLS configuration. If those stages complete quickly but time_starttransfer dominates the request, the delay is occurring while the server generates the page.
Next, compare static and dynamic content:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}\n" https://example.com/style.css
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}\n" https://example.com/images/logo.webp
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}\n" https://example.com/
If CSS and images respond quickly while HTML has a much higher TTFB, the network is not the bottleneck. Focus on PHP, database performance, Redis Object Cache, PHP-FPM or application logic. If all resources respond slowly, continue with network diagnostics:
traceroute example.com
or
mtr example.com
Look for packet loss, unstable routing or high latency, and repeat the tests from different locations. At the same time, compare the request breakdown in Chrome DevTools. If both DevTools and curl show that most of the delay occurs during Waiting (TTFB), investigate server-side processing. If every resource is slow regardless of content type, resolve network, TLS or infrastructure issues before optimising the application.
How to Improve LCP with Gzip or Brotli Compression
A poor LCP score is not always caused by large images or JavaScript. If HTML, CSS and JavaScript are transferred without compression, the browser spends longer downloading the resources required to render the first screen, especially on slower networks.
Start by checking that compression is enabled. On Nginx, verify that gzip or brotli is configured. On Apache, confirm that mod_deflate or mod_brotli is enabled. Apply compression to HTML, CSS, JavaScript, SVG, XML and JSON, but exclude already compressed formats such as JPEG, PNG, WebP, AVIF, ZIP and MP4, as recompressing them only wastes CPU resources.
After updating the configuration, validate and reload the web server.
For Nginx:
nginx -t
systemctl restart nginx
For Apache:
apachectl configtest
systemctl restart apache2
Then verify that compression is actually being used. Open Chrome DevTools, disable browser caching, reload the page and inspect the Content-Encoding response header. Text-based resources should return gzip or br. Compare the Transferred and Resource Size values in the Network tab. Compressed resources should transfer significantly less data than their original size.
Finally, repeat the PageSpeed and DevTools tests. If HTML, CSS and JavaScript download faster and LCP improves without changing images or the site’s theme, the bottleneck was data transfer rather than PHP execution or browser rendering.
The configuration is complete when text resources are served with Content-Encoding: gzip or br, already compressed files are excluded, transferred sizes are reduced, and PageSpeed together with DevTools confirms faster loading of the resources that affect LCP.
How to Configure Cache-Control and Expires for Static Assets
If Google PageSpeed recommends Serve static assets with an efficient cache policy, the problem is often missing or incorrect Cache-Control and Expires headers rather than the CMS itself. Without them, browsers repeatedly download unchanged CSS, JavaScript, images and fonts instead of using cached copies.
Start by checking the response headers in Chrome DevTools. Open the Network tab, reload the page and inspect a CSS file, JavaScript file or image. If Cache-Control or Expires is missing, or max-age=0 or no-cache is returned, the browser must request the resource again on every visit.
Configure browser caching on the web server. For Nginx, add cache rules for static file types. For Apache, configure mod_expires and mod_headers. If the site uses .htaccess, verify that the directives are applied correctly. Versioned files such as style.8f4c21.css or app.2d71.js can safely use long cache lifetimes because updated filenames automatically invalidate older cached copies.
After updating the configuration, validate and restart the web server.
For Nginx:
nginx -t
systemctl restart nginx
For Apache:
apachectl configtest
systemctl restart apache2
Verify the result in DevTools by loading the page twice. On the second request, static assets should be served from disk cache or memory cache. You can also confirm the response headers with:
curl -I https://example.com/css/style.css
The response should include appropriate Cache-Control and, where applicable, Expires headers.
The configuration is complete when repeat visits load static assets from the browser cache, the expected caching headers are returned consistently, and Google PageSpeed no longer reports inefficient browser caching. This reduces bandwidth usage, speeds up repeat visits and lowers unnecessary requests to the server.
How to Enable Redis Object Cache for WordPress and Other CMS Platforms
If Google PageSpeed reports a high Initial Server Response Time, the WordPress dashboard feels slow or TTFB remains high despite low traffic, the bottleneck is often the database rather than the server. Without object caching, WordPress, WooCommerce, OpenCart, Drupal and other CMS platforms repeatedly execute the same SQL queries for menus, settings, products and other frequently requested data.
Start by confirming that Redis is installed and running:
systemctl status redis
If Redis is unavailable, install it, enable automatic startup and verify that the service starts correctly after a reboot.
Next, configure the application to use Redis. In WordPress, install and enable the Redis Object Cache plugin. In Laravel, configure Redis in the .env file, clear the configuration cache and restart the application. Other CMS platforms should be configured to use Redis instead of file-based caching where supported.
After configuration, verify that the application is actually using Redis.
redis-cli ping
The expected response is:
PONG
Then check cache activity:
redis-cli info stats
The keyspace_hits counter should increase during normal browsing. If it does not, the application is probably still querying MySQL directly.
For WordPress, compare the same page before and after enabling Redis using Query Monitor. The number of SQL queries and page generation time should decrease. Repeat the TTFB test in Chrome DevTools or with curl, and review the MySQL or MariaDB slow query log. A correctly configured Redis Object Cache typically reduces repeated database queries and produces more consistent server response times.
The configuration is complete when Redis is running, redis-cli ping returns PONG, keyspace_hits increases during normal use, SQL queries decrease and TTFB becomes shorter and more stable. At that point, Redis is actively reducing database load instead of simply running as another background service.
How to Check PHP-FPM and the Database When INP or TTFB Remain High
If Redis, compression and browser caching are already configured but Google PageSpeed still reports a high TTFB or poor INP score, the bottleneck is usually PHP-FPM or the database. Long-running PHP processes, exhausted worker pools and slow SQL queries often delay page generation even when overall server load appears low.
Start by checking that PHP-FPM is running correctly:
systemctl status php-fpm
On Ubuntu, the service name may include the PHP version:
systemctl status php8.3-fpm
If the service is unstable, resolve that first. Then inspect recent log entries:
journalctl -u php-fpm -n 100
Pay particular attention to messages such as server reached pm.max_children, upstream timed out, Allowed memory size exhausted or repeated child exited entries. These usually indicate exhausted PHP workers, timeouts, insufficient memory or unstable PHP processes.
Next, enable the PHP-FPM slowlog if necessary, reproduce the slow operation and identify scripts that consistently appear in the log. Repeated entries usually point to inefficient application code or problematic plugins rather than the server itself.
Continue with the database by reviewing the MySQL or MariaDB slow query log. Long-running SELECT, JOIN, filesort or UPDATE queries often become the main source of high TTFB. Redis reduces repeated queries but cannot compensate for inefficient SQL that still has to be executed.
Monitor the server while reproducing the problem:
top
or
htop
Monitor disk performance:
iostat -x 1
Check memory and process activity:
vmstat 1
If CPU usage remains low but iowait is high, the server is waiting for storage. Growing swap usage indicates insufficient RAM, while one or more long-running PHP processes usually point to slow code or expensive database queries.
Finally, inspect the web server log:
tail -100 /var/log/nginx/error.log
Repeated upstream timed out or PHP-FPM connection errors confirm that Nginx is waiting too long for the application to respond.
The investigation is complete once the slow logs consistently identify the same scripts or SQL queries, pm.max_children is no longer exhausted, swap remains unused, iowait stays low and repeated timeout errors disappear. Only then should you decide whether the solution is application optimisation, database tuning, PHP-FPM adjustments or additional server resources.
How to Enable HTTP/2 and Verify the TLS Handshake
A website may use HTTPS but still deliver resources inefficiently. Before looking for application-level problems, verify that HTTP/2 is enabled and the TLS handshake is not adding unnecessary delay.
For Nginx, confirm that the HTTPS listener includes http2:
listen 443 ssl http2;
For Apache, make sure mod_http2 is enabled and the configuration includes:
Protocols h2 http/1.1
After making changes, validate and restart the web server.
For Nginx:
nginx -t
systemctl restart nginx
For Apache:
apachectl configtest
systemctl restart apache2
Verify HTTP/2 from the command line:
curl -I --http2 https://example.com
Then check the browser. In Chrome DevTools, open the Network tab, enable the Protocol column and reload the page. HTML, CSS, JavaScript, fonts and images should show h2. If they still show http/1.1, the browser is not using HTTP/2 despite the server configuration.
Also inspect the TLS certificate in the browser and confirm that it is valid, trusted and has a complete certificate chain. An incomplete chain or incorrect TLS configuration can slow connection setup or cause validation failures.
Measure TLS timing with curl:
curl -o /dev/null -s -w \
"TLS: %{time_appconnect}\n\
TTFB: %{time_starttransfer}\n" \
https://example.com/
If time_appconnect is unusually high while other stages are normal, review the TLS configuration, certificate chain, OpenSSL version, cipher suites and web server settings.
The configuration is complete when Nginx or Apache validates without errors, curl –http2 confirms HTTP/2, Chrome DevTools shows h2, the certificate is trusted and the TLS handshake completes quickly.
How to Choose a Hosting Package for Better Core Web Vitals
After measuring TTFB, tuning PHP-FPM, enabling Redis, configuring HTTP/2 or HTTP/3, and setting up compression and browser caching, it often becomes clear that further optimisation depends on the hosting platform itself. If the infrastructure does not support current PHP versions, Redis, fast NVMe storage or flexible PHP-FPM configuration, maintaining good Core Web Vitals becomes increasingly difficult regardless of how well the application is optimised.
Before choosing a hosting package, identify the platform’s actual limitations. If PageSpeed consistently reports a high TTFB, PHP-FPM reaches its limits, the database becomes the main source of latency or Redis is unavailable, upgrading disk space alone is unlikely to improve performance.
Look beyond CPU cores and RAM. Check whether the hosting platform supports modern PHP releases, Redis Object Cache, HTTP/2 and HTTP/3, NVMe storage, current MySQL or MariaDB versions, automatic backups, server log access and resource upgrades without requiring migration. These capabilities have a much greater impact on Core Web Vitals than storage capacity alone.
At Era.Host, the hosting environment is built around these requirements, combining modern PHP versions, Redis support, NVMe storage, HTTP/2 and HTTP/3, flexible resource upgrades and full access to diagnostic tools, making it easier to identify and resolve server-side performance bottlenecks before they affect Core Web Vitals.
A well-chosen hosting package is not the one with the largest specifications, but the one that consistently delivers fast HTML generation, stable TTFB and straightforward scalability as the project grows.