Docs / Performance Optimization / How to Set Up Varnish Cache for Apache or Nginx

How to Set Up Varnish Cache for Apache or Nginx

By Admin · Mar 2, 2026 · Updated Apr 23, 2026 · 28 views · 4 min read

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 malloc size 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 varnishstat to track cache_hit vs cache_miss
  • Set appropriate TTLs — balance freshness vs performance; use shorter TTLs for dynamic content and longer for static assets

Was this article helpful?