Varnish Cache Setup: Cache WordPress and Magento at Server Level
Varnish cache setup puts Varnish on port 80 and your web server on 8080, then points default.vcl at that backend. Add an X-Cache header, reload both services, and curl the same URL twice: the second response reads HIT. HTTPS stays on a proxy in front of Varnish.
A server administrator's walkthrough: ports, VCL basics, TLS termination, HIT verification, purging and ESI — and when Varnish is the wrong tool.
knowledge
- Read time
- 4 min
- Sections
- 8
- Updated
- 14 Nov 2026
- Written by
- WebJi® team
Last editorial update: 15 November 2026.
What does Varnish do, and when does it actually help?
Varnish is an HTTP reverse proxy that stores rendered pages in memory and answers repeat requests without touching PHP or MySQL — the first request is a MISS that fills the cache, the next is a HIT served from RAM. It pays off on a VPS or dedicated server running several sites, or on a Magento 2 store, which ships its own Varnish integration as the recommended production cache.
On a single WordPress site on shared hosting it is usually the wrong tool: you do not control the ports or the VCL there, and a page-cache plugin delivers most of the gain. Varnish adds a moving part you must purge, monitor and keep out of the login and cart flow — take it on when the origin, not the network, is the constraint. The PHP half of the speed story is in the OPcache setup guide.
How do you install Varnish and move the web server to port 8080?
Varnish takes port 80 and Apache or Nginx moves to 8080, so every request passes through the cache before PHP runs — on Ubuntu or Debian that is one package install, two file edits and two restarts.
- Install and stop the service:
sudo apt update && sudo apt install varnish, thensudo systemctl stop varnish. - Open
/lib/systemd/system/varnish.serviceand set the listen address on the ExecStart line to-a :80. - On the same line set the cache size, for example
-s malloc,1G, raised to 2G on a busy server. - Move the origin web server to 8080:
Listen 8080in/etc/apache2/ports.confand each virtual host, orlisten 8080;in each Nginx server block. - Run
sudo systemctl daemon-reload, then restart both:sudo systemctl restart apache2 varnish(ornginx varnish).
Installing from the official Varnish package repository gives a newer build than the distribution's default; if you skip that step, check the installed version with varnishd -V before tuning anything.
What goes into default.vcl?
VCL — the Varnish Configuration Language — is the file that names the server Varnish fetches from (the backend) and the rules for what it keeps; default.vcl holds it, and every setup edits the backend block first.
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_backend_response {
# keep objects for five minutes when the app sends nothing
if (beresp.ttl <= 0s) {
set beresp.ttl = 300s;
}
}
sub vcl_deliver {
# make HIT/MISS visible in the response
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}
Three subroutines cover most needs: vcl_recv decides what to look up, vcl_backend_response sets TTLs and ESI, and vcl_deliver shapes headers. Varnish keeps an object 120 seconds by default; a five-minute TTL suits a brochure or blog, while a shop should let the application send its own Cache-Control — Varnish honours a shorter max-age from the backend, so the two do not fight. One trap: Varnish resolves the backend hostname once, when the VCL compiles, so after a DNS change you reload the VCL rather than wait.
How does HTTPS work if Varnish speaks plain HTTP?
Varnish Cache does not terminate TLS, so the certificate stays on Nginx, HAProxy or a load balancer in front, and Varnish listens behind it on port 80 — the browser still sees https and a valid lock. The usual layout is Nginx on 443 for TLS, Varnish on 80, and the origin on 8080.
Redirect http to https at the front proxy, not inside Varnish; otherwise a cached page can be served over plain http after the switch. For the certificate itself, the SSL troubleshooting guide covers the chain and mixed-content checks this layout occasionally surfaces.
How do you verify Varnish owns port 80 and is actually caching?
After the restart, varnishd should own port 80, the origin should own 8080, and the homepage should load with no 503 — then curl the same URL twice and read the X-Cache header you added in vcl_deliver.
sudo ss -ltnp | grep :80— varnishd is the process listed.sudo ss -ltnp | grep :8080— Apache or Nginx is the process listed.systemctl status varnish— active (running), not restarting in a loop.curl -I https://your-site/twice — the second response readsX-Cache: HIT.
A 503 here usually means the backend port in default.vcl and the port the web server listens on are different numbers — fix the pair rather than disabling Varnish. varnishlog -g request shows the lookup and hit lines for one request; and if the response carries a Set-Cookie header, Varnish will not cache it, which is why login and cart pages stay dynamic by design.
How do you purge the cache after publishing?
Purge the URLs that changed — never restart the service, because a restart empties the whole cache and sends the next round of requests straight back to PHP. Two routes work: a controlled PURGE request allowed only from localhost and your own IP through an ACL in VCL, or varnishadm ban for a pattern such as one URL prefix.
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip != "127.0.0.1" && client.ip != "203.0.113.10") {
return (synth(405, "Not allowed"));
}
return (purge);
}
}
Keep the PURGE method closed to the public internet, and wire it to your publish hook so an editor never has to know it exists. On WordPress, the cache-clearing flow is compared with plugin alternatives in the WordPress cache guide.
When is ESI worth the extra complexity?
Edge Side Includes let one cached page carry small dynamic fragments — a cart counter, a personalised greeting — fetched and stitched separately, so the page stays a HIT while the fragment stays live. Enable it in vcl_backend_response with set beresp.do_esi = true; and mark the fragment page uncacheable, then include it from the template with <esi:include src="/cart-count/"/>.
It is worth it when one fragment changes per visitor on an otherwise identical page; it is overkill when two versions of a page (logged-in and logged-out) would do the job with less machinery. Every ESI include is another request Varnish must assemble, so measure before adopting it sitewide.
Frequently asked questions
What is a VCL file, and do I have to edit it?
VCL is the Varnish Configuration Language, and default.vcl holds the backend address and the cache rules. Every setup edits the backend block; the request and response rules in vcl_recv and vcl_backend_response are optional until you need purging, TTL overrides or custom headers.
Does Varnish work with HTTPS websites?
Not directly. Varnish Cache does not terminate TLS, so Nginx, HAProxy or a load balancer handles the certificate in front and forwards plain HTTP to Varnish on port 80. The visitor still sees a valid https connection with the lock.
Why does Varnish return 503 after the setup?
Almost always a port mismatch: default.vcl points at one port while the origin web server listens on another. Check ss -ltnp for both :80 and :8080, align the backend port with the web server's Listen directive, and reload — do not disable Varnish to work around it.
Is Varnish worth it on shared hosting?
Rarely, because you do not control the ports or the VCL on shared plans. A page-cache plugin gives most of the benefit there. Varnish fits a VPS or dedicated server with several sites, or a Magento 2 store that ships its own Varnish configuration.
How is this different from Redis object caching?
Varnish caches whole rendered pages before PHP runs; Redis caches database objects and query results inside PHP. They solve different bottlenecks and stack well together — the Redis side is covered in the WordPress object cache guide.
Last editorial update: 15 November 2026.
Ready to get started with WebJi®?
Join 12,000+ businesses across India and overseas. INR pricing, 18% GST shown before payment and 24/7 email support in Hindi and English — average first reply under 60 minutes.