Speed Up Web with Varnish Cache on VPS

Speed Up Web with Varnish Cache on VPS Nginx

June 2026 · 8 min read

Varnish Cache is an HTTP accelerator that stores entire page content in RAM. When a visitor requests a cached page again, Varnish serves it directly from memory without touching PHP or the database at all. This reduces response time from 200–500ms to 1–5ms. In practice, Varnish can handle significantly more traffic than Nginx alone.

Architecture: Nginx (443) → Varnish (80) → Nginx (8080)

# Nginx handles HTTPS on port 443
# Varnish listens on port 80 (or behind Nginx proxy)
# Backend Nginx/Apache on port 8080

# In this tutorial we'll use:
# Client → Nginx:443 (SSL termination) → Varnish:6081 → Nginx:8080 (backend)

Install Varnish

sudo apt update
sudo apt install varnish -y

# Verify installation
varnishd -V

Change Nginx Backend Port

# Change Nginx to listen on port 8080 instead of 80
sudo nano /etc/nginx/sites-available/yourdomain.com

server {
    listen 8080;  # Change from 80 to 8080
    server_name yourdomain.com;
    # ... rest of your config
}

sudo nginx -t && sudo systemctl reload nginx

Configure Varnish (VCL)

sudo nano /etc/varnish/default.vcl
vcl 4.0;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    # Don't cache requests with cookies (logged-in users)
    if (req.http.Cookie) {
        if (req.http.Cookie !~ "wordpress_logged_in") {
            unset req.http.Cookie;
        }
    }

    # Don't cache admin pages
    if (req.url ~ "^/wp-admin|^/wp-login.php") {
        return(pass);
    }

    # Don't cache POST requests
    if (req.method == "POST") {
        return(pass);
    }
}

sub vcl_backend_response {
    # Cache HTML for 1 hour
    if (beresp.http.Content-Type ~ "text/html") {
        set beresp.ttl = 1h;
        set beresp.grace = 24h;
    }

    # Don't cache if backend says no-store
    if (beresp.http.Cache-Control ~ "no-store|private") {
        set beresp.uncacheable = true;
    }
}

sub vcl_deliver {
    # Add header to show cache hit or miss (for debugging)
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
}

Set Varnish to Listen on Port 6081

sudo nano /etc/varnish/varnish.params

VARNISH_VCL_CONF=/etc/varnish/default.vcl
VARNISH_LISTEN_PORT=6081
VARNISH_STORAGE="malloc,256m"  # Use 256MB of RAM
VARNISH_TTL=120
sudo systemctl restart varnish

Configure Nginx to Forward to Varnish

sudo nano /etc/nginx/sites-available/yourdomain.com

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate ...;
    ssl_certificate_key ...;

    location / {
        proxy_pass http://127.0.0.1:6081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

sudo nginx -t && sudo systemctl reload nginx
Tip: View cache statistics with varnishstat -1 and focus on cache_hit and cache_miss. Hit rate should be 80%+ for typical content websites.

Verify Varnish is Working Correctly

# Check service status
sudo systemctl status varnish

# View hit/miss headers
curl -I https://yourdomain.com | grep X-Cache
# First request: X-Cache: MISS
# Second request: X-Cache: HIT

# View statistics
varnishstat -1 | grep cache_hit

# View real-time logs
varnishlog -i ReqURL,ReqHeader,RespHeader
Tip: Purge cache for a specific page using the PURGE method: curl -X PURGE http://127.0.0.1:6081/path/to/page. Use this in WordPress plugins or deploy scripts to invalidate cache when updating content.

Common Issues & Troubleshooting

Cache hit rate is very low (below 50%)

This is usually caused by cookies preventing Varnish from caching. Check which cookies are being sent:

varnishlog -g request -q "RespHeader:X-Cache eq MISS" -i ReqHeader

WordPress admin pages are slow (through Varnish)

Your VCL must pass admin pages without caching. Check your VCL rules:

if (req.url ~ "^/wp-admin|^/wp-login.php|^/wp-cron.php") {
    return(pass);
}

HTTPS doesn't work through Varnish

Varnish doesn't support SSL directly. You must terminate SSL at Nginx first, then proxy to Varnish over HTTP.

Error "503 Backend fetch failed"

The backend (Nginx on port 8080) is not responding. Check the port:

ss -tlnp | grep 8080
sudo systemctl status nginx

Frequently Asked Questions

How is Varnish different from Nginx FastCGI cache?

Nginx FastCGI cache stores cache on disk, while Varnish stores it in RAM. This makes Varnish 10–100x faster. However, restarting Varnish clears the cache and requires warm-up time.

How much RAM does Varnish need?

It depends on your site size. Typically allocate 25–50% of your VPS RAM for caching. For medium-sized websites, 256–512 MB is usually sufficient. If you run out of RAM, Varnish automatically evicts old pages.

Can I use Varnish with Cloudflare?

Yes. Cloudflare caches at the edge CDN, while Varnish caches at your server. They work well together. Cloudflare misses will reach your origin, and Varnish will serve the response from RAM instead of going to PHP, further reducing origin load.