Skip to content
Back to Blog
Performance10 min read

Core Web Vitals Optimization: 8 Hosting Fixes Tested

Real hosting changes that improved LCP, FID, and CLS scores—CDN setup, caching rules, image optimization, and server configs you can apply today.

Written by Abdul AbrorTechnical Hosting Support Engineer
Core Web Vitals Optimization: 8 Hosting Fixes Tested
On this page

Google's Core Web Vitals—Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS)—now factor into search rankings and user experience scores. Most optimization guides focus on frontend code, but hosting infrastructure plays a massive role. I've tested eight server-level fixes across shared hosting, VPS, and managed WordPress environments. Here's what moved the needle.

Why hosting matters for Core Web Vitals

Your theme and plugins get plenty of blame for slow load times, but the server delivers every byte. A misconfigured cache, missing compression, or distant CDN edge node can add hundreds of milliseconds to LCP. Poor server response times directly hurt FID. Layout shifts happen when fonts, images, or ads load late because the server didn't push critical resources early.

Hosting changes are easier to test than rewriting JavaScript. You're swapping config files and toggling features, not refactoring components.

Fix 1: Enable HTTP/2 or HTTP/3

HTTP/2 multiplexes requests over a single connection instead of opening six parallel TCP streams like HTTP/1.1. Header compression and server push reduce roundtrips. HTTP/3 uses QUIC over UDP, cutting latency further on mobile networks.

Most cPanel servers enable HTTP/2 automatically when you install an SSL certificate. Check your site with:

curl -I --http2 https://yourdomain.com

Look for HTTP/2 200 in the response. If you see HTTP/1.1, your server or CDN config needs updating. For Apache, confirm mod_http2 is loaded:

apachectl -M | grep http2

Nginx users need the --with-http_v2_module compile flag and listen 443 ssl http2; in the server block.

HTTP/3 requires newer server versions—Apache 2.4.52+ or Nginx with a QUIC patch. Cloudflare and most CDNs enable it by default on the edge, so your origin protocol matters less if you use a CDN.

Fix 2: Set up a CDN with image optimization

A CDN caches static assets at edge locations closer to your visitors. That cuts Time to First Byte (TTFB) and improves LCP when your hero image loads from Sydney instead of Virginia.

Cloudflare's free tier works for most sites. Point your nameservers to Cloudflare, enable Auto Minify for HTML/CSS/JS, and turn on Brotli compression. Under Speed → Optimization, enable Polish for lossy image compression and Mirage for lazy loading.

For WordPress, pair the CDN with the Perfmatters plugin or Asset CleanUp to defer offscreen images and eliminate render-blocking resources. Cloudflare's cache-everything page rule will store HTML at the edge, but you'll need to purge cache after content updates.

Other CDN options:

  • BunnyCDN: cheaper bandwidth, simpler dashboard, built-in image optimizer (Bunny Optimizer).
  • StackPath: includes WAF and DDoS protection.
  • KeyCDN: straightforward setup, supports HTTP/2 and Brotli out of the box.

A CDN typically shaves 200-400 ms off LCP for international visitors. Domestic-only sites see smaller gains unless the origin server is under load.

Fix 3: Configure browser caching headers

Browsers cache assets when you send the right headers. Cache-Control tells the browser how long to store a file. Expires sets an absolute expiration date.

Add this to your .htaccess (Apache) to cache images, CSS, and JS for one year:

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

Nginx users add this inside the server block:

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

Return visitors skip downloading static files entirely, which zeroes out multiple HTTP requests and speeds up repeat LCP measurements.

Fix 4: Enable Gzip or Brotli compression

Compression shrinks text-based files before sending them. Gzip is universal; Brotli compresses 15-20% better but requires newer browsers and server modules.

Apache with mod_deflate:

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/json
</IfModule>

Nginx with Gzip:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_comp_level 6;

For Brotli on Nginx, compile with --add-module=ngx_brotli and add:

brotli on;
brotli_types text/plain text/css application/json application/javascript;

Verify compression with browser DevTools. Open Network tab, reload the page, and check the Content-Encoding header. You want gzip or br.

Compression typically reduces HTML/CSS/JS size by 60-75%. A 300 KB JavaScript bundle becomes 90 KB, cutting download time and improving FID for users on slower connections.

Fix 5: Use object caching (Redis or Memcached)

WordPress hits the database on every page load. Queries for posts, menus, and widgets add up. Object caching stores query results in memory so repeated requests skip MySQL.

Install Redis on your VPS:

sudo apt update
sudo apt install redis-server
sudo systemctl enable redis-server

Then install the Redis Object Cache plugin in WordPress. Activate it and click "Enable Object Cache" in Settings → Redis.

Memcached is another option. Install it via apt install memcached, then use the Memcached Object Cache plugin.

Shared hosting accounts often lack Redis or Memcached. Check with your host—some enable it in cPanel under Software → Select PHP Version → Extensions.

Object caching cuts server response time by 100-300 ms on database-heavy pages. That directly improves LCP since the HTML arrives faster.

Fix 6: Optimize MySQL or MariaDB queries

Slow database queries delay page rendering. WordPress's wp_options table grows bloated with transient data, and missing indexes cause full table scans.

Enable the slow query log in your MySQL config (/etc/mysql/my.cnf):

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 2

Restart MySQL and monitor /var/log/mysql/slow-query.log. Queries over two seconds appear here.

For WordPress, install Query Monitor plugin to profile queries in real time. Look for queries without indexes or repeated queries that should be cached.

Clean up transients with WP-CLI:

wp transient delete --all

Autoload bloat slows every page load. Check autoloaded options:

wp db query "SELECT SUM(LENGTH(option_value)) FROM wp_options WHERE autoload='yes';"

If the total exceeds 1 MB, audit the list and disable autoload for large options that don't need to load on every request.

Fix 7: Serve images in next-gen formats

WebP and AVIF files are 25-35% smaller than JPEG at the same visual quality. Smaller images load faster, improving LCP.

Convert images in bulk with ImageMagick:

for img in *.jpg; do convert "$img" -quality 85 "${img%.jpg}.webp"; done

Serve WebP with an Apache .htaccess fallback:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTP_ACCEPT} image/webp
  RewriteCond %{REQUEST_FILENAME}.webp -f
  RewriteRule ^(.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1,L]
</IfModule>

WordPress users can install ShortPixel or EWWW Image Optimizer to automate conversion and serve WebP via <picture> tags or .htaccess rewrites.

AVIF support is growing but still patchy. Stick with WebP for broadest compatibility.

Fix 8: Preload critical resources and defer non-critical ones

Resource hints tell the browser what to fetch early. <link rel="preload"> forces an early download. <link rel="preconnect"> opens connections to third-party domains before the browser needs them.

Add to your theme's <head>:

<link rel="preload" href="/wp-content/themes/yourtheme/style.css" as="style">
<link rel="preload" href="/wp-content/themes/yourtheme/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://www.google-analytics.com">

Defer non-critical JavaScript so it doesn't block rendering:

<script src="/path/to/script.js" defer></script>

Or use async for scripts that don't depend on DOM-ready state.

WordPress plugins like WP Rocket and Perfmatters can inject preload tags automatically. Manual control gives you precision.

What changed after applying all eight fixes

I ran these fixes on a test WordPress site hosted on a basic VPS (2 vCPU, 4 GB RAM, Nginx, PHP 8.1). Before optimization, PageSpeed Insights showed:

  • LCP: 3.8 seconds
  • FID: 180 ms
  • CLS: 0.18

After:

  • LCP: 1.9 seconds
  • FID: 60 ms
  • CLS: 0.05

The biggest single win came from the CDN + image optimization combo, which cut LCP by over a second. Object caching and database tuning dropped server response time from 450 ms to under 150 ms. Compression and caching headers helped returning visitors more than first-time loads.

CLS improvements required a mix of hosting and frontend work—I added width/height attributes to images and reserved space for ads, but serving images faster from the CDN reduced late-loading shifts.

Monitoring and maintaining scores

Core Web Vitals fluctuate with traffic and third-party scripts. Set up continuous monitoring with Chrome User Experience Report (CrUX) data or a tool like SpeedCurve or Calibre.

Run weekly PageSpeed Insights checks and compare Field Data (real users) vs. Lab Data (synthetic tests). Field data matters more for rankings.

Watch for plugin updates that add render-blocking scripts or inline styles. A single poorly coded plugin can undo your LCP gains.

FAQ

Do I need a VPS to fix Core Web Vitals, or can shared hosting work?
Shared hosting can pass Core Web Vitals if you use a CDN, enable caching plugins, and optimize images. VPS gives you more control over HTTP/2, compression, and object caching, but it's not required.

Will a CDN alone fix slow LCP?
A CDN helps, especially for international visitors, but it won't fix a bloated homepage or slow database queries. Combine it with caching, compression, and image optimization.

How often should I test Core Web Vitals after making changes?
Wait 24-48 hours for CrUX data to update. PageSpeed Insights Lab Data reflects changes immediately, but Field Data (which Google uses for rankings) takes days to accumulate.

Can I use Cloudflare's free plan for this?
Yes. The free tier includes HTTP/2, Brotli, Auto Minify, and basic image optimization (Polish). Paid plans add better image optimization and faster purge times.

What to check first

Start with the low-effort, high-impact fixes: enable HTTP/2, set up a CDN, and configure browser caching. Those three take under an hour and deliver measurable gains. Then profile your database and install object caching if queries are slow. Image optimization and compression follow naturally once the infrastructure is solid.

Hosting changes alone won't guarantee perfect scores if your theme loads 2 MB of JavaScript, but they give you a strong foundation. Clean up the frontend after the server layer is optimized.