Skip to content
Back to Blog
Performance11 min read

Improve Core Web Vitals: 7 Server-Side Fixes [2026]

Backend changes—CDN routing, compression layers, query optimization, and hosting stack tuning—that move LCP, CLS, and INP into the green without touching a line of front-end code.

Written by Abdul AbrorTechnical Hosting Support Engineer
Improve Core Web Vitals: 7 Server-Side Fixes [2026]
On this page

Google's Core Web Vitals remain a ranking signal, and most advice points to minifying JavaScript or lazy-loading images. That's front-end territory. What gets less attention is the server layer—where response times start, where bytes get compressed, and where a slow database query can wreck your Largest Contentful Paint score before the browser ever renders a pixel. I've watched support tickets where a site owner chased Lighthouse suggestions for weeks, only to discover that switching from shared hosting to a VPS with proper opcode caching fixed everything overnight.

This guide walks through seven backend levers you control from your hosting dashboard, server config files, or CDN panel. No React bundles. No image formats. Just infrastructure changes that directly improve LCP, Cumulative Layout Shift, and Interaction to Next Paint.

Why the server matters for Core Web Vitals

LCP measures how long it takes for the largest visible element to render. If your HTML sits in a queue behind fifty other requests on a shared IP, the browser waits. Same story for Time to First Byte—TTFB feeds directly into LCP, and TTFB lives entirely on the server side.

CLS tracks layout shifts. A late-loading web font from a slow origin can cause text to reflow. INP measures input responsiveness, and if your backend takes two seconds to process a form submission or AJAX call, the user sees a frozen interface.

The front end can't compensate for a 1.8-second TTFB or a database query that scans twenty thousand rows. Fix the origin first.

1. Enable Brotli compression at the web server

Gzip is the default, but Brotli compresses HTML, CSS, and JavaScript roughly 15-20 percent smaller at comparable speed. Most modern browsers support it, and Apache or Nginx can serve Brotli with a few lines of config.

For Nginx, install the Brotli module if it's not compiled in, then add to your server block:

brotli on;
brotli_types text/css text/javascript application/javascript application/json image/svg+xml;
brotli_comp_level 6;

Reload Nginx. Check response headers with curl -I -H "Accept-Encoding: br" https://yoursite.com and look for content-encoding: br.

For Apache, enable mod_brotli and add to your VirtualHost or .htaccess:

<IfModule mod_brotli.c>
  AddOutputFilterByType BROTLI_COMPRESS text/html text/css text/javascript application/javascript
  BrotliCompressionQuality 6
</IfModule>

Brotli's delta shows up most in repeat visits where the browser already cached images. The HTML and inline CSS shrink, TTFB drops, and LCP improves by a few hundred milliseconds. Not dramatic, but cumulative with the other fixes here.

2. Move static assets to a CDN with proper cache headers

Core Web Vitals care about speed to glass. A CDN edge node three milliseconds away beats your origin server two hundred milliseconds away every time.

Most hosting control panels—cPanel, Plesk, or a provider dashboard—let you plug in Cloudflare, BunnyCDN, or KeyCDN in minutes. The key is making sure your origin sends correct Cache-Control headers so the CDN actually caches.

In your web server config, set long expiry for static assets:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

Then purge the CDN cache once. Subsequent requests for /style.css or /hero.jpg never hit your origin. The CDN serves from RAM at the edge, and LCP for image-heavy pages drops visibly.

One mistake I see often: leaving Cache-Control: no-cache on CSS because a developer wanted live updates during a redesign six months ago. The CDN respects that header and proxies every request back to origin. Check your response headers in browser DevTools and confirm you see cf-cache-status: HIT or equivalent.

3. Tune your database queries and add indexes

WordPress, Joomla, and most CMS platforms generate pages by running database queries. A missing index means the database scans the entire table, and a five-thousand-row posts table turns a 20 ms query into 600 ms.

Log slow queries in MySQL or MariaDB:

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.5

Restart MySQL, then tail the log while you load your homepage:

tail -f /var/log/mysql/slow.log

Look for queries with Rows_examined in the thousands. Run EXPLAIN on the query and check for type: ALL (table scan). Add an index:

ALTER TABLE wp_posts ADD INDEX idx_post_status_date (post_status, post_date);

For WordPress specifically, plugins like Query Monitor show you every query and its duration. I've seen homepage generation time drop from 1.2 seconds to 180 ms after indexing wp_postmeta on meta_key.

Database optimization doesn't feel like a Core Web Vitals fix because it's invisible to Lighthouse. But it directly cuts server processing time, which lowers TTFB, which improves LCP.

4. Enable opcode caching with OPcache

PHP reads your script files, parses them into opcodes, then executes. Without OPcache, that parse step happens on every request. With OPcache, PHP stores the compiled opcodes in memory.

Most cPanel servers and modern VPS images ship with OPcache installed but not tuned. Check php -i | grep opcache or look in phpinfo() for opcache.enable.

Edit your php.ini (often /etc/php/8.x/fpm/php.ini or /usr/local/lib/php.ini):

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60

Restart PHP-FPM:

systemctl restart php8.1-fpm

First request after restart is still slow (cache warm-up). Second request is fast. The difference is 50-200 ms of CPU time per request, and on a busy site that compounds. LCP benefits because the server spends less time generating the HTML, so TTFB drops.

If you're on shared hosting, check your provider's control panel for a PHP settings section. Many offer a toggle for OPcache or a preset PHP version that includes it.

What about object caching?

WordPress and similar platforms can store database query results in Redis or Memcached. That skips the database entirely for repeat requests.

Install Redis, then drop in an object cache plugin (for WordPress, the official Redis Object Cache plugin works). No code changes. The CMS checks Redis first; if the data is cached, it skips MySQL.

Set a reasonable TTL—600 seconds for something like a post list, 3600 for rarely changing settings. The impact on TTFB is immediate, especially on pages that run ten or twenty queries.

Redis also helps with logged-in users. A guest visiting your homepage might see a fully cached page, but a logged-in user triggers dynamic queries. Object caching helps both.

5. Switch to HTTP/2 or HTTP/3 if you haven't

HTTP/1.1 opens one request per connection, so browsers open six connections and pipeline requests. HTTP/2 multiplexes dozens of requests over a single connection, and HTTP/3 does the same over QUIC (UDP).

Both reduce connection overhead and latency. For a page that loads twenty CSS, JS, and image files, HTTP/2 shaves 100-300 ms off total load time compared to HTTP/1.1.

Nginx and Apache support HTTP/2 out of the box if you have an SSL certificate:

listen 443 ssl http2;

Restart the web server. Check in Chrome DevTools Network tab—protocol column should show h2. Cloudflare and most CDNs enable HTTP/2 automatically, so if you're behind a CDN, you're probably already using it.

HTTP/3 is newer and requires a rebuild of Nginx or a CDN that supports it (Cloudflare does). The improvement over HTTP/2 is smaller—maybe 50-100 ms in high-latency networks—but it's nearly zero effort if your CDN offers a toggle.

6. Use a dedicated or VPS hosting plan with enough CPU and RAM

Shared hosting crams two hundred accounts onto one server. When your neighbor's site gets a traffic spike, your site waits for CPU time. The kernel scheduler is fair, but fairness means your PHP process queues behind everyone else's.

I've seen identical WordPress installs run with 400 ms TTFB on shared hosting and 80 ms TTFB on a 2 GB VPS. The difference is CPU contention and memory swapping.

A VPS gives you dedicated CPU cores and RAM. Look for at least 2 GB of RAM and two vCPUs if you run a CMS with active plugins. Cheaper options exist—Hetzner, Vultr, and DigitalOcean all offer VPS plans under ten dollars a month—but the performance gap between shared and VPS is the single biggest lever for TTFB.

Managed WordPress hosts (Kinsta, WP Engine, Flywheel) sit somewhere in between. They use container isolation on shared hardware, so you don't get noisy neighbor problems, and they preconfigure Nginx, Redis, and CDN. If managing a VPS sounds like too much, managed hosting is a solid middle path.

7. Optimize your TLS handshake and certificate chain

Every HTTPS connection starts with a TLS handshake. The client and server exchange keys, verify the certificate, and establish encryption. A misconfigured certificate chain adds an extra round trip.

Make sure your web server sends the full certificate chain (your cert plus intermediates) in one response. Browsers shouldn't have to fetch intermediate certs separately.

For Nginx, concatenate your cert and intermediate into one file:

cat yoursite.crt intermediate.crt > fullchain.pem

Then point your config to the combined file:

ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/yoursite.key;

Also enable session resumption so repeat visitors skip the full handshake:

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

Test your setup with openssl s_client -connect yoursite.com:443 -servername yoursite.com. Look for the chain in the output. If it says "verify return code: 0 (ok)" you're set.

TLS 1.3 is faster than 1.2 because it reduces round trips. Most modern Nginx builds support it; add ssl_protocols TLSv1.2 TLSv1.3; and you're done. The handshake drops from two round trips to one, saving roughly 50-100 ms per new connection.

Measure before and after with real data

Lighthouse and PageSpeed Insights run synthetic tests from a data center. Useful, but not representative of your actual visitors. Use Chrome User Experience Report (CrUX) data in Search Console to see real 75th percentile scores from the field.

After you apply these fixes, wait a week for CrUX to collect new data, then check Search Console under Core Web Vitals. The report shows LCP, CLS, and INP buckets (Good, Needs Improvement, Poor) for mobile and desktop. You want most URLs in Good.

For internal monitoring, set up Server-Timing headers to track TTFB and database time:

add_header Server-Timing "db;dur=$upstream_response_time";

Then parse those headers in your analytics or RUM tool.

Does TTFB directly affect my ranking?

No. Google's ranking algorithm considers Core Web Vitals (LCP, CLS, INP), and TTFB feeds into LCP but isn't a standalone metric. That said, a 2-second TTFB almost always means a bad LCP, so fixing TTFB indirectly helps your ranking.

Should I use a CDN even if my audience is in one country?

Yes. A CDN edge node in the same country is still faster than your origin server because of routing and peering. Cloudflare and BunnyCDN both have local PoPs in most regions. The latency drop is measurable even over short distances.

How much RAM does Redis need for object caching?

For a small to medium WordPress site, 128 MB is plenty. A large site with thousands of posts might need 512 MB. Redis stores only the cache keys and serialized data, not full page HTML, so memory usage stays low. Monitor with redis-cli INFO memory.

Can I use Brotli and Gzip at the same time?

Yes. Configure your web server to support both; it will send Brotli to browsers that accept it and Gzip to older clients. The Accept-Encoding request header tells the server which one to use. No conflict.

What to check first

Start with TTFB because it's the foundation. Run a quick test with curl -w "@curl-format.txt" -o /dev/null -s https://yoursite.com (where curl-format.txt contains time_total: %{time_total}\n). If TTFB is over 600 ms, look at your hosting plan, database queries, and opcode caching. Those three fixes usually cut TTFB in half.

Once TTFB is under 300 ms, layer in Brotli, CDN, and HTTP/2. Each one shaves another 50-200 ms. Measure with real CrUX data, not just Lighthouse, because your actual users experience variable latency, device speed, and network conditions.

Core Web Vitals aren't purely a front-end problem. The server does half the work.