Varnish Cache with Nginx and WordPress on CentOS

CentOS 7/8 version of Varnish + Nginx + WordPress installation optimized with SSL.

Alby Andersen

Install Varnish & Nginx for CentOS 7/8

# CentOS 7
sudo yum install -y epel-release
sudo rpm --nosignature -i https://packagecloud.io/varnishcache/varnish73/gpgkey
sudo curl -L https://packagecloud.io/varnishcache/varnish73/config_file.repo?os=el&dist=7 -o /etc/yum.repos.d/varnishcache_varnish73.repo

# CentOS 8
sudo dnf install -y epel-release
sudo rpm --nosignature -i https://packagecloud.io/varnishcache/varnish73/gpgkey
sudo curl -L https://packagecloud.io/varnishcache/varnish73/config_file.repo?os=el&dist=8 -o /etc/yum.repos.d/varnishcache_varnish73.repo

# Install packages
sudo yum install -y varnish nginx policycoreutils-python-utils

Configure Nginx

  1. Change Nginx port:
   sudo nano /etc/nginx/nginx.conf

Modify:

   server {
       listen       8080 default_server;
       listen       [::]:8080 default_server;
       server_name  _;
       root         /usr/share/nginx/html;
       # ... rest of config
   }
  1. Create WordPress config:
   sudo nano /etc/nginx/conf.d/wordpress.conf
   server {
       listen 8080;
       server_name yourdomain.com;
       root /var/www/wordpress;
       index index.php;

       location / {
           try_files $uri $uri/ /index.php?$args;
       }

       location ~ \.php$ {
           include fastcgi_params;
           fastcgi_pass unix:/run/php-fpm/www.sock;
           fastcgi_index index.php;
           fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       }
   }
  1. Restart Nginx:
   sudo systemctl restart nginx

SSL Configuration

  1. Install Certbot:
   sudo yum install -y certbot python3-certbot-nginx
  1. Generate Certificates:
   sudo certbot certonly --nginx -d yourdomain.com
  1. Create Combined PEM:
   sudo bash -c "cat /etc/letsencrypt/live/yourdomain.com/fullchain.pem /etc/letsencrypt/live/yourdomain.com/privkey.pem > /etc/varnish/yourdomain.com.pem"
   sudo chown varnish:varnish /etc/varnish/yourdomain.com.pem

Configure Varnish

  1. Edit systemd service:
   sudo nano /etc/systemd/system/varnish.service.d/override.conf
   [Service]
   ExecStart=
   ExecStart=/usr/sbin/varnishd \
       -a :80 \
       -a :443,PROXY \
       -p feature=+http2 \
       -p ssl_cert=/etc/varnish/yourdomain.com.pem \
       -p ssl_key=/etc/varnish/yourdomain.com.pem \
       -s malloc,4G \
       -f /etc/varnish/default.vcl
  1. Reload systemd:
   sudo systemctl daemon-reload

Optimized VCL File

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

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .first_byte_timeout = 300s;
    .probe = {
        .url = "/";
        .interval = 10s;
        .timeout = 5s;
        .window = 5;
        .threshold = 3;
    }
}

sub vcl_recv {
    # Redirect HTTP → HTTPS
    if (req.http.X-Forwarded-Proto !~ "(?i)https" && req.url !~ "^/\.well-known/acme-challenge/") {
        return (synth(750, "Moved Permanently"));
    }

    # Bypass cache for admin/dynamic content
    if (
        req.url ~ "^/(wp-admin|wp-login|cart|checkout|my-account|add-to-cart|logout|xmlrpc.php|rest-api/|graphql)" ||
        req.method != "GET"
    ) {
        return (pass);
    }

    # Strip cookies for static files
    if (req.url ~ "\.(css|js|jpe?g|png|gif|webp|svg|ico|woff2?|ttf|eot|mp4|webm)(\?.*)?$") {
        unset req.http.Cookie;
    }

    # Clean remaining cookies
    if (req.http.Cookie) {
        set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_wpnonce|comment_author|woocommerce_(.*)|wordpress_(.*))[^;]*", "");
        set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
        set req.http.Cookie = regsub(req.http.Cookie, ";\s*$", "");
        if (req.http.Cookie == "") {
            unset req.http.Cookie;
        } else {
            return (pass);
        }
    }
}

sub vcl_backend_response {
    # Cache static files 1 year
    if (beresp.url ~ "\.(css|js|jpe?g|png|gif|webp|svg|ico|woff2?|ttf|eot|mp4|webm)(\?.*)?$") {
        set beresp.ttl = 365d;
        unset beresp.http.Set-Cookie;
    }

    # Cache HTML 2 hours
    else if (beresp.http.Content-Type ~ "text/html") {
        set beresp.ttl = 2h;
        set beresp.grace = 1h;
    }

    # Bypass REST API
    if (bereq.url ~ "^/(wp-json|api)") {
        set beresp.uncacheable = true;
    }
}

sub vcl_synth {
    if (resp.status == 750) {
        set resp.status = 301;
        set resp.http.Location = "https://" + req.http.Host + req.url;
        return (deliver);
    }
}

sub vcl_deliver {
    # Cache headers
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT (" + obj.hits + ")";
    } else {
        set resp.http.X-Cache = "MISS";
    }

    # Security headers
    set resp.http.X-Content-Type-Options = "nosniff";
    set resp.http.X-Frame-Options = "SAMEORIGIN";
    set resp.http.Referrer-Policy = "strict-origin-when-cross-origin";
    unset resp.http.Server;
    unset resp.http.X-Powered-By;
}

WordPress Configuration

Install Varnish HTTP Purge Plugin: Use the Varnish HTTP Purge plugin to clear cache automatically.

SELinux & Firewall

# Allow Varnish to bind to ports
sudo semanage port -a -t http_port_t -p tcp 80
sudo semanage port -a -t http_port_t -p tcp 443

# Firewall rules
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Finalize & Test

sudo systemctl restart varnish nginx

# Test SSL
curl -I https://yourdomain.com

# Verify cache
curl -I http://yourdomain.com | grep X-Cache

# Check Varnish logs
sudo journalctl -u varnish -f

Key CentOS-Specific Notes

  1. SELinux Contexts:
  • If encountering permission issues:
   sudo setsebool -P httpd_can_network_connect 1
   sudo restorecon -Rv /etc/varnish
  1. PHP-FPM Configuration:
    Ensure PHP-FPM is listening on correct socket:
   sudo nano /etc/php-fpm.d/www.conf
   listen = /run/php-fpm/www.sock
   listen.owner = nginx
   listen.group = nginx
  1. Varnish Logs:
    CentOS uses journalctl for logging:
   sudo journalctl -u varnish --since "5 minutes ago"

This CentOS version achieves identical performance to the Ubuntu setup while respecting Red Hat ecosystem conventions. The main differences are in package management and SELinux integration.

Share This Article