Varnish Cache is a high-performance HTTP accelerator designed to sit in front of web servers and serve cached responses at near-wire speed, offloading PHP and database work from your backend. On RHEL 8, Varnish is packaged in the default AppStream repository, making installation straightforward. This guide shows how to install Varnish, write a VCL configuration that caches responses from an Nginx backend running on port 8080, and use varnishstat and varnishlog to monitor cache behavior. When finished, Varnish will accept public traffic on port 80 and forward only cache misses to Nginx.
Prerequisites
- RHEL 8 server with a sudo-capable user
- Nginx already installed and serving content
- Ports 80 and 6081 available (Varnish will occupy port 80 or 6081)
firewalldactive- Basic familiarity with VCL (Varnish Configuration Language)
Step 1 — Install Varnish
Varnish 6 is available in the RHEL 8 AppStream. Install it and enable the service.
sudo dnf install -y varnish
sudo systemctl enable varnish
sudo systemctl start varnish
sudo systemctl status varnish
By default, Varnish listens on port 6081. You will change this to port 80 in a later step.
Step 2 — Reconfigure Nginx to Listen on Port 8080
Varnish will take over port 80, so Nginx must move to port 8080. Edit your Nginx virtual-host configuration:
sudo sed -i 's/listen 80;/listen 8080;/' /etc/nginx/conf.d/example.com.conf
sudo sed -i 's/listen [::]:80;/listen [::]:8080;/' /etc/nginx/nginx.conf
sudo nginx -t && sudo systemctl reload nginx
# Verify Nginx now listens on 8080
ss -tlnp | grep 8080
Step 3 — Write the VCL Configuration
Edit /etc/varnish/default.vcl to define your backend, caching logic, and cache invalidation. The vcl_recv subroutine decides what to cache; vcl_backend_response controls how long objects are retained.
sudo nano /etc/varnish/default.vcl
Replace the file contents with:
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 90s;
.between_bytes_timeout = 2s;
}
sub vcl_recv {
# Remove port from Host header so cache keys stay consistent
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Do not cache authenticated WordPress users or cart pages
if (req.http.Cookie ~ "wordpress_logged_in|woocommerce_cart") {
return (pass);
}
# Do not cache POST/PUT/DELETE
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Strip cookies for static assets so they are cacheable
if (req.url ~ ".(css|js|png|jpg|gif|ico|woff2?)(?.*)?$") {
unset req.http.Cookie;
}
return (hash);
}
sub vcl_backend_response {
# Cache 200 and 301 responses for 10 minutes
if (beresp.status == 200 || beresp.status == 301) {
set beresp.ttl = 10m;
set beresp.grace = 1h;
}
# Cache 404s for 1 minute
if (beresp.status == 404) {
set beresp.ttl = 1m;
}
# Remove Set-Cookie for static assets
if (bereq.url ~ ".(css|js|png|jpg|gif|ico|woff2?)(?.*)?$") {
unset beresp.http.Set-Cookie;
}
}
sub vcl_deliver {
# Add a header so you can see HIT or MISS in responses
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
set resp.http.Age = obj.ttl;
} else {
set resp.http.X-Cache = "MISS";
}
}
Step 4 — Configure Varnish to Listen on Port 80
Edit the Varnish systemd override to change the listening port from 6081 to 80.
sudo mkdir -p /etc/systemd/system/varnish.service.d
sudo tee /etc/systemd/system/varnish.service.d/override.conf <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -a :80 -f /etc/varnish/default.vcl -s malloc,256m
EOF
sudo systemctl daemon-reload
sudo systemctl restart varnish
# Allow port 80 through firewalld (replace 6081 if it was open)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Step 5 — Purge Objects from the Cache
Send an HTTP PURGE request from localhost to invalidate a specific URL. Add a purge ACL to your VCL to restrict who can purge.
# Add to default.vcl before sub vcl_recv:
# acl purge { "127.0.0.1"; }
# sub vcl_recv { if (req.method == "PURGE") {
# if (!client.ip ~ purge) { return(synth(405,"Not allowed")); }
# return (purge); } }
# Purge a single URL
curl -X PURGE http://127.0.0.1/some-page/
# Purge everything (restart clears all in-memory objects)
sudo systemctl restart varnish
Step 6 — Monitor Varnish with varnishstat and varnishlog
Use the built-in command-line tools to inspect cache performance in real time.
# Live counters: hit rate, object count, backend connections
varnishstat
# Stream live request/response log
varnishlog
# Show only cache-miss events
varnishlog -q "RespHeader:X-Cache eq MISS"
# One-shot summary statistics
varnishstat -1 | grep -E "MAIN.(cache_hit|cache_miss|n_object)"
Conclusion
You have installed Varnish on RHEL 8, reconfigured Nginx to listen on port 8080 as a backend, written a VCL file that caches responses while bypassing cache for authenticated WordPress users, and moved Varnish to port 80 via a systemd override. The X-Cache header in responses lets you confirm hit or miss at a glance, and varnishstat provides live counters to track your overall hit rate. This architecture can serve thousands of requests per second from RAM without touching PHP or MySQL for cached pages.
Next steps: How to Configure HAProxy for HTTP and TCP Load Balancing on RHEL 8, How to Configure Nginx FastCGI Caching on RHEL 8, and How to Set Up a LEMP Stack on RHEL 8.