How to Set Up Varnish Cache for Apache or Nginx
Varnish is a high-performance HTTP accelerator that sits in front of your web server and caches responses in memory. It can serve cached pages in microseconds, dramatically reducing the load on your backend and improving response times for visitors to your Breeze-hosted applications.
How Varnish Works
Varnish listens on port 80 (or 443 via a TLS terminator) and forwards uncached requests to your backend web server. When the backend responds, Varnish stores the response in memory and serves it directly for subsequent identical requests, bypassing the backend entirely.
Installing Varnish
sudo apt update
sudo apt install -y varnish
Step 1: Move the Web Server to a Different Port
Since Varnish needs to listen on port 80, move your web server to port 8080.
For Nginx:
sudo nano /etc/nginx/sites-available/default
server {
listen 8080;
server_name yourdomain.com;
# ... rest of config
}
sudo systemctl reload nginx
For Apache:
sudo nano /etc/apache2/ports.conf
Listen 8080
Update your virtual host to use port 8080 and reload Apache.
Step 2: Configure Varnish
Edit the Varnish service configuration to listen on port 80:
sudo nano /etc/default/varnish
DAEMON_OPTS="-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,512m"
On systemd-based systems, also override the service file:
sudo systemctl edit --full varnish
Change the ExecStart line:
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,512m
Step 3: Configure VCL (Varnish Configuration Language)
Edit the default VCL file:
sudo nano /etc/varnish/default.vcl
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 60s;
.between_bytes_timeout = 2s;
}
sub vcl_recv {
# Strip cookies for static files
if (req.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|svg|woff2|webp)$") {
unset req.http.Cookie;
return (hash);
}
# Do not cache POST requests
if (req.method == "POST") {
return (pass);
}
# Do not cache requests with authorization
if (req.http.Authorization) {
return (pass);
}
# Do not cache admin or login pages
if (req.url ~ "^/(admin|login|dashboard)") {
return (pass);
}
# Strip tracking cookies (Google Analytics, etc.)
if (req.http.Cookie) {
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__utm[a-z]+|_ga|_gid|_gat)=[^;]*", "");
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
}
}
sub vcl_backend_response {
# Cache static files for 1 day
if (bereq.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|svg|woff2|webp)$") {
set beresp.ttl = 1d;
unset beresp.http.Set-Cookie;
}
# Default cache TTL for HTML pages
if (beresp.http.Content-Type ~ "text/html") {
set beresp.ttl = 5m;
}
# Grace period - serve stale content while fetching fresh
set beresp.grace = 1h;
}
sub vcl_deliver {
# Add debug header to show cache status
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT (" + obj.hits + ")";
} else {
set resp.http.X-Cache = "MISS";
}
# Remove internal headers
unset resp.http.X-Varnish;
unset resp.http.Via;
}
Step 4: Start Varnish
sudo systemctl daemon-reload
sudo systemctl restart varnish
sudo systemctl enable varnish
Verify Varnish is running:
curl -I http://yourdomain.com
# Look for the X-Cache header
HTTPS with Varnish
Varnish does not handle TLS natively. Use Nginx or HAProxy as a TLS terminator in front of Varnish:
Client → Nginx (443, TLS) → Varnish (80, cache) → Backend (8080)
Configure Nginx as TLS terminator:
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:80;
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;
}
}
Monitoring and Purging
# Live statistics
varnishstat
# View request log
varnishlog
# View access log in NCSA format
varnishncsa
# Purge a specific URL from cache
curl -X PURGE http://yourdomain.com/page-to-purge
# Purge all cached content (add this to VCL first):
# sub vcl_recv { if (req.method == "BAN") { ban("req.http.host == " + req.http.host); return (synth(200, "Banned")); } }
curl -X BAN -H "Host: yourdomain.com" http://127.0.0.1:80/
Performance Tips
- Allocate sufficient memory — set
-s mallocsize based on your working set; more memory means higher hit rates - Use grace mode — serve stale content while fetching fresh data to eliminate cache stampedes
- Strip unnecessary cookies — cookies prevent caching; strip analytics and tracking cookies in VCL
- Monitor hit rate — aim for 90%+ hit rate; use
varnishstatto track cache_hit vs cache_miss - Set appropriate TTLs — balance freshness vs performance; use shorter TTLs for dynamic content and longer for static assets