CloudPanel:Part 4

Introduction

Introduction

Varnish Cache is a caching HTTP reverse proxy that speeds up your sites with a factor of 100 – 250x.
A copy of your page is stored in memory after the first time a user visits the page.

Varnish Cache is integrated into CloudPanel as a turn-key solution. Enable Varnish Cache, and your sites will fly.

What is Varnish Cache?

Benefits

  • Blazing Fast Page Loads – Up to 250x faster
  • Up to 80% savings in Infrastructure
  • Improved User Experience
  • Better Search Ranking

Supported Applications

We constantly work to support more Applications, join us in Discord and help us support more Applications.

Right now, the following PHP Applications have support for Varnish Cache:

  • WordPress
  • WooCommerce
  • Codeigniter
  • Laravel
  • Symfony
  • Generic
  • Slim

Settings

Varnish Cache is integrated into CloudPanel as a turn-key solution. Enable Varnish Cache to get blazing fast page loads, up to 250 times faster. Change the Cache Lifetime, Excluded Params, and Excludes to your needs.

Cache Tag Prefix

1. The Cache Tag Prefix is the main cache tag used on every page. Other cache tags use this prefix in front.

Excluded Params

The Excluded Params is a list of GET Parameters to disable caching.

Excludes

Attention

Purge the url/file from the cache after adding it to the Excludes.

In the Excludes, you can configure files or paths that shouldn’t be cached.

Example Excludes:

  • ^/my-account/ –> Urls starting with /my-account/ are not being cached
  • /cart/ –> Urls containing /cart/ are not being cached
  • wp-login.php –> File will not be cached

Purge Cache

To manage a database via phpMyAdmin, click on Manage, and you will be forwarded to phpMyAdmin.

Attention

Do not use phpMyAdmin to export and import databases; it can destroy your database. Use export and import guide from below.
Purge Entire Cache removes the entire cache for a site from Varnish Cache. Under the hood, a PURGE request with the header X-Cache-Tags is being sent to port 6081 (Varnish Cache):
curl -v -X PURGE -H 'X-Cache-Tags: aac6' 127.0.0.1:6081
You can purge more specifically by entering a single url or tags separated by a comma.

Developer Guide - Vhost

Basics

Varnish Cache is a caching HTTP reverse proxy that speeds up your sites by storing the compressed Page Source in memory.
Static files like CSS, JS, and Images are NOT being stored in Varnish Cache because NGINX delivers them faster.

When you open your site, e.g., https://www.domain.com, the request goes to NGINX, where SSL/TLS gets terminated.
If the request is a static file like a Stylesheet, Javascript, or an Image, it gets delivered immediately by NGINX.
All other requests are forwarded to Varnish Cache (Port 6081).

If Varnish Cache has a cache entry for a request, the page source gets immediately returned from memory without being processed by PHP-FPM.

If no cache entry exists, the request gets forwarded by Varnish Cache to NGINX port 8080, where it gets processed by the PHP Application via PHP-FPM.

Vhost Explanation

The Vhost below is being used for WordPress/WooCommerce. In line 1-10 a redirect for domain.com takes place. All requests from http and https are redirected via 301 to https://www.domain.com. The static files like CSS, JS, and Images are delivered at line 97-101. All other requests are going through the location /, line 79-95. At line 80, you see the placeholder {{varnish_proxy_pass}}. When Varnish Cache is disabled, the rendered value for this placeholder is:
proxy_pass http://127.0.0.1:8080;
When Varnish Cache is enabled, it uses the value of Varnish Server from the Varnish Cache Settings, e.g.,
proxy_pass http://127.0.0.1:6081;

Lines 63-67 are special for WordPress/WooCommerce.

All requests to /wp-admin/ and wp-login.php are bypassed, meaning they are NOT going through Varnish Cache; they are forwarded to port 8080 (see lines 12-37), where they get processed by the PHP Application via PHP-FPM.

 server {
  listen 80;
  listen [::]:80;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  {{ssl_certificate_key}}
  {{ssl_certificate}}
  server_name domain.com;
  return 301 https://www.domain.com$request_uri;
}

server {
  listen 8080;
  listen [::]:8080;
  server_name www.domain.com;
  {{root}}

  try_files $uri $uri/ /index.php?$args;
  index index.php index.html;

  location ~ \.php$ {
    include fastcgi_params;
    fastcgi_intercept_errors on;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    try_files $uri =404;
    fastcgi_read_timeout 3600;
    fastcgi_send_timeout 3600;
    fastcgi_param HTTPS "on";
    fastcgi_pass 127.0.0.1:{{php_fpm_port}};
    fastcgi_param PHP_VALUE "{{php_settings}}";
  }
  
  if (-f $request_filename) {
    break;
  }
}

server {
  listen 80;
  listen [::]:80;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  {{ssl_certificate_key}}
  {{ssl_certificate}}
  server_name www.domain.com;
  {{root}}

  {{nginx_access_log}}
  {{nginx_error_log}}

  if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
  }

  location ~ /.well-known {
    auth_basic off;
    allow all;
  }

  {{settings}}

  location ~/(wp-admin/|wp-login.php) {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header Host $host;
    proxy_pass http://127.0.0.1:8080;
    proxy_max_temp_file_size 0;
    proxy_connect_timeout      7200;
    proxy_send_timeout         7200;
    proxy_read_timeout         7200;
    proxy_buffer_size          128k;
    proxy_buffers              4 256k;
    proxy_busy_buffers_size    256k;
    proxy_temp_file_write_size 256k;
  }

  location / {
    {{varnish_proxy_pass}}
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_hide_header X-Varnish;
    proxy_redirect off;
    proxy_max_temp_file_size 0;
    proxy_connect_timeout      720;
    proxy_send_timeout         720;
    proxy_read_timeout         720;
    proxy_buffer_size          128k;
    proxy_buffers              4 256k;
    proxy_busy_buffers_size    256k;
    proxy_temp_file_write_size 256k;
  }

  location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
    add_header Access-Control-Allow-Origin "*";
    expires max;
    access_log off;
  }

  if (-f $request_filename) {
    break;
  }
}

Developer Guide - PHP Controller

Caching a dynamic site like WordPress, WooCommerce, or other PHP Applications isn’t easy.
Most pages can be cached, but some may not be cached as they are individual to each user, such as carts, checkouts, or customer areas.

The caching behavior, like the maximum caching lifetime or if a site path should be excluded from caching, is being controlled via a PHP Controller, which gets added when you enable Varnish Cache in the settings.

The Controller File

The PHP Controller for Varnish Cache is a PHP File that get prepended to the application via auto_prepend_file.

When you enable Varnish Cache, the PHP Controller gets added like other PHP Settings via NGINX VHOST.

auto_prepend_file=/home/siteUser/.varnish-cache/controller.php;

For WordPress/WooCommerce, Laravel, Symfony, and other PHP Applications, we have a controller that can be found in the following git repository https://github.com/cloudpanel-io/varnish-controllers/.

When you create a site for an application that supports Varnish Cache, the right controller file gets automatically added to /home/$siteUser/.varnish-cache/.

The example below shows the PHP Controller File used for WordPress/WooCommerce.

You will find the varnish controller file in the site’s home directory.

/home/$siteUser/.varnish-cache/controller.php

As mentioned earlier, the file gets added via auto_prepend_file, which means it’s the first code that gets executed.

Varnish Cache is being controlled via the Cache-Control header.

By sending the following Cache-Control header, we say Varnish Cache to store a copy of the page for 604800 seconds before it gets expired.

Cache-Control: public, max-age=604800, s-maxage=604800

The controller decides if a page can be cached and is sending headers to Varnish Cache:

  • X-Cache-Lifetime
  • X-Cache-Tags
  • Cache-Control

By checking the response headers of a page, you will find x-cache-age, x-cache-lifetime, and x-cache-tags.

The value of x-cache-age returns the age of the page in seconds stored in Varnish Cache and remains until x-cache-lifetime before expiring.

The controller’s main function is to check if a page can be cached and to enrich the X-Cache-Tags before sending the headers.

header_register_callback

At line 321, you see the callback $headerRegisterCallback registered.

The header_register_callback will be called when PHP starts sending output.

header_register_callback($headerRegisterCallback);

In this callback, additional tags are added and required for specific purge operations.

register_shutdown_function

The register_shutdown_function callback $registerShutdownCallback is responsible for purge operations.
If a specific action is happening, e.g., someone is editing a post in the admin area, all pages for a specific cache tag get purged.

<?php

define('VARNISH_DEVELOPER_MODE', false);
define('VARNISH_WORDPRESS_CONTROLLER_VERSION', '0.0.1');

$currentUser = get_current_user();
$currentDirectory = sprintf('%s/', rtrim(dirname(__FILE__), '/'));
$settingsFile = sprintf('%s/settings.json', rtrim($currentDirectory, '/'));
$logDirectory = sprintf('/home/%s/logs/varnish-cache/', $currentUser);
$varnishPurgeLogfile = sprintf('%s/purge.log', rtrim($logDirectory, '/'));

class ClpVarnish
{
    private $enabled = false;
    private $developerMode = false;
    private $purgeLogfile = '';
    private $server = '';
    private $isCacheable = true;
    static private $cacheTagPrefix = '';
    static private $cacheLifetime = 0;
    static private $cacheTags = [];
    private $excludes = [];
    private $excludedParams = [];
    static private $queuedPurges = [];

    public function setEnabled($flag): void
    {
        $this->enabled = (bool)$flag;
    }

    public function isEnabled(): bool
    {
        return $this->enabled;
    }

    public function setDeveloperMode($flag): void
    {
        $this->developerMode = (bool)$flag;
    }

    public function isDeveloperMode(): bool
    {
        return $this->developerMode;
    }

    public function setPurgeLogfile($purgeLogfile): void
    {
        $this->purgeLogfile = $purgeLogfile;
    }

    public function getPurgeLogfile(): string
    {
        return $this->purgeLogfile;
    }

    static public function setCacheTagPrefix($cacheTagPrefix): void
    {
        self::$cacheTagPrefix = $cacheTagPrefix;
    }

    static public function getCacheTagPrefix(): string
    {
        return self::$cacheTagPrefix;
    }

    static public function setCacheLifetime($cacheLifetime): void
    {
        self::$cacheLifetime = $cacheLifetime;
    }

    static public function getCacheLifetime(): int
    {
        return self::$cacheLifetime;
    }

    static public function addCacheTag($cacheTag): void
    {
        self::$cacheTags[] = $cacheTag;
    }

    public function getCacheTags(): array
    {
        return self::$cacheTags;
    }

    public function setServer($server): void
    {
        $this->server = $server;
    }

    public function getServer(): ?string
    {
        return $this->server;
    }

    public function setExcludes(array $excludes): void
    {
        $this->excludes = $excludes;
    }

    public function getExcludes(): array
    {
        return $this->excludes;
    }

    public function setExcludedParams(array $excludedParams): void
    {
        $this->excludedParams = $excludedParams;
    }

    public function getExcludedParams(): array
    {
        return $this->excludedParams;
    }

    public function setIsCacheable($flag): void
    {
        $this->isCacheable = $flag;
    }

    public function isCacheable(): bool
    {
        if (true === $this->isCacheable) {
            $isEnabled = $this->isEnabled();
            if (false === $isEnabled) {
                return false;
            }
            $cacheLifetime = self::getCacheLifetime();
            if (0 === $cacheLifetime) {
                return false;
            }
            if (false === empty($_POST)) {
                return false;
            }
            if (true === function_exists('is_user_logged_in')) {
                $isUserLoggedIn = is_user_logged_in();
                if (true === $isUserLoggedIn) {
                    return false;
                }
            }
            $excludedParams = (array)$this->getExcludedParams();
            if (false === empty($excludedParams)) {
                foreach ($excludedParams as $excludedParam) {
                    if (true === isset($_GET[$excludedParam])) {
                        return false;
                    }
                }
            }
            $excludes = $this->getExcludes();
            $requestUri = (true === isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '');
            if (false === empty($excludes) && false === empty($requestUri)) {
                foreach ($excludes as $exclude) {
                    $exclude = trim($exclude);
                    if (true === isset($exclude[0]) && '^' == $exclude[0]) {
                        $exclude = substr($exclude, 1);
                        if (substr($requestUri, 0, strlen($exclude)) === $exclude) {
                            return false;
                        }
                    } else {
                        if (strpos($requestUri, $exclude) !== false) {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }

    public function addTagsToPurge(array $tags)
    {
        if (count($tags)) {
            foreach ($tags as $tag) {
                self::$queuedPurges['tags'][] = $tag;
            }
        }
    }

    private function purge(array $headers): void
    {
        try {
            $server = $this->getServer();
            $curlOptionList = [
                CURLOPT_URL               => $server,
                CURLOPT_HTTPHEADER        => $headers,
                CURLOPT_CUSTOMREQUEST     => 'PURGE',
                CURLOPT_VERBOSE           => true,
                CURLOPT_RETURNTRANSFER    => true,
                CURLOPT_NOBODY            => true,
                CURLOPT_CONNECTTIMEOUT_MS => 2000,
            ];
            $curlHandler = curl_init();
            curl_setopt_array($curlHandler, $curlOptionList);
            curl_exec($curlHandler);
            curl_close($curlHandler);
        } catch (\Exception $e) {
            $errorMessage = $e->getMessage();
            echo sprintf('Varnish Cache Purge Failed, Error Message: %s', $errorMessage);
        }
    }

    public function sendCacheHeaders(): void
    {
        $isCacheable = $this->isCacheable();
        if (true === $isCacheable) {
            $cacheTagPrefix = $this->getCacheTagPrefix();
            $cacheLifetime = $this->getCacheLifetime();
            $cacheTags = array_merge([$cacheTagPrefix], self::getCacheTags());
            $cacheTags = array_unique($cacheTags);
            if (count($cacheTags)) {
                header(sprintf('X-Cache-Lifetime: %s', $cacheLifetime));
                header(sprintf('X-Cache-Tags: %s', implode(',', $cacheTags)));
                header(sprintf('Pragma: %s', 'cache'));
                header(sprintf('Cache-Control: public, max-age=%s, s-maxage=%s', $cacheLifetime, $cacheLifetime));
            }
        }
    }

    public function shutdownPurge(): void
    {
        if (count(self::$queuedPurges)) {
            if (true === isset(self::$queuedPurges['tags']) && false === empty(self::$queuedPurges['tags'])) {
                $tags = array_filter(array_unique(self::$queuedPurges['tags']));
                $headers = [
                    sprintf('X-Cache-Tags: %s', implode(',', $tags))
                ];
                $this->purge($headers);
                $this->logPurge($tags);
            }
        }
    }

    private function logPurge(array $data)
    {
        $isDeveloperMode = $this->isDeveloperMode();
        if (true === $isDeveloperMode) {
            $dateTime = new \DateTime('now', new \DateTimeZone('UTC'));
            $logMessage = sprintf('%s, %s', $dateTime->format('Y-m-d H:i:s'), print_r($data, true));
            $purgeLogfile = $this->getPurgeLogfile();
            file_put_contents($purgeLogfile, $logMessage.PHP_EOL, FILE_APPEND | LOCK_EX);
        }
    }
}

if (true === file_exists($settingsFile)) {
    if (false === file_exists($logDirectory)) {
        @mkdir($logDirectory, 0770, true);
    }
    $settings = json_decode(file_get_contents($settingsFile), true);
    $varnishEnabled = (true === isset($settings['enabled']) && true === $settings['enabled'] ? true : false);
    $varnishServer = (true === isset($settings['server']) ? $settings['server'] : '');
    $varnishCacheTagPrefix = (true === isset($settings['cacheTagPrefix']) ? $settings['cacheTagPrefix'] : '');
    $varnishCacheLifetime = (true === isset($settings['cacheLifetime']) ? (int)$settings['cacheLifetime'] : 0);
    $varnishCacheExcludes = (true === isset($settings['excludes']) && true === is_array($settings['excludes']) ? $settings['excludes'] : []);
    $varnishCacheExcludedParams = (true === isset($settings['excludedParams']) && true === is_array($settings['excludedParams']) ? $settings['excludedParams'] : []);
    $clpVarnish = new ClpVarnish();
    $clpVarnish->setEnabled($varnishEnabled);
    $clpVarnish->setDeveloperMode(VARNISH_DEVELOPER_MODE);
    $clpVarnish->setPurgeLogfile($varnishPurgeLogfile);
    $clpVarnish->setServer($varnishServer);
    $clpVarnish->setCacheTagPrefix($varnishCacheTagPrefix);
    $clpVarnish->setCacheLifetime($varnishCacheLifetime);
    $clpVarnish->setExcludes($varnishCacheExcludes);
    $clpVarnish->setExcludedParams($varnishCacheExcludedParams);
    $headerRegisterCallback = function() use ($clpVarnish) {
        $cacheTagPrefix = $clpVarnish->getCacheTagPrefix();
        if (true === function_exists('get_bloginfo')) {
            $wordPressVersion = get_bloginfo('version');
            // Add cache tags
            if (true === isset($GLOBALS['wp_query']) && true === isset($GLOBALS['wp_query']->posts)) {
                $posts = $GLOBALS['wp_query']->posts;
                if (false === empty($posts)) {
                    foreach ($posts as $post) {
                        if (true === isset($post->ID)) {
                            $cacheTag = sprintf('%s-post-%s', $cacheTagPrefix, $post->ID);
                            ClpVarnish::addCacheTag($cacheTag);
                        }
                    }
                }
            }
        }
        $clpVarnish->sendCacheHeaders();
    };
    $registerShutdownCallback = function() use ($clpVarnish) {
        $cacheTagPrefix = $clpVarnish->getCacheTagPrefix();
        if (true === function_exists('get_bloginfo')) {
            $wordPressVersion = get_bloginfo('version');
            // Listen for purge requests for WordPress >= 6.0
            if (true === version_compare($wordPressVersion,'6.0', '>=')) {
                $jsonResponse = file_get_contents('php://input');
                if (false === empty($jsonResponse)) {
                    $jsonResponse = @json_decode($jsonResponse, true);
                    if (true === isset($jsonResponse['id']) && false === empty($jsonResponse['id'])) {
                        $purgeTag = sprintf('%s-post-%s', $cacheTagPrefix, $jsonResponse['id']);
                        $clpVarnish->addTagsToPurge([$purgeTag]);
                    }
                }
            } else { // Listen for purge requests for WordPress < 6.0
                if (true === isset($_POST['post_id']) && false === empty($_POST['post_id'])) {
                    $postId = (int)$_POST['post_id'];
                    $purgeTag = sprintf('%s-post-%s', $cacheTagPrefix, $postId);
                    $clpVarnish->addTagsToPurge([$purgeTag]);
                }
            }
            // WooCommerce
            // Product Update
            if (true === isset($_POST['post_ID']) && false === empty($_POST['post_ID'])) {
                $postId = (int)$_POST['post_ID'];
                $purgeTag = sprintf('%s-post-%s', $cacheTagPrefix, $postId);
                $clpVarnish->addTagsToPurge([$purgeTag]);
            }
            // Category Update
            if (true === isset($_POST['taxonomy']) && 'product_cat' == $_POST['taxonomy'] && true === isset($_POST['tag_ID'])) {
                // Purge everything when a category gets updated, as it affects all sites.
                $clpVarnish->addTagsToPurge([$cacheTagPrefix]);
            }
        }
        $clpVarnish->shutdownPurge();
    };
    header_register_callback($headerRegisterCallback);
    register_shutdown_function($registerShutdownCallback);
}

Custom Applications

You can set the caching lifetime to your needs for custom PHP Applications based on Laravel, Symfony, or other PHP frameworks.

For example, if you have a page that should only be cached for 10 minutes, you can call the static method setCacheLifetime.

ClpVarnish::setCacheLifetime(600);

For enriching cache tags, e.g., a list of product ids, you can call the static method addCacheTag.
Make sure that you use the cache-tag prefix in front.

<?php
$cacheTagPrefix = ClpVarnish::getCacheTagPrefix();
$cacheTag = sprintf('%s-%s', $cacheTagPrefix, 'my-cache-tag');
ClpVarnish::addCacheTag($cacheTag);

Developer Mode

When the developer mode is enabled, all purge requests are logged into the following log file:

/home/$siteUser/logs/varnish-cache/purge.log

To enable the developer mode, do the following:

  • Login via SSH with the site user.

  • Open the controller.php file:

nano ~/.varnish-cache/controller.php
  • Set VARNISH_DEVELOPER_MODE to true:
define('VARNISH_DEVELOPER_MODE', true);
  • Tail the purge.log to see the purges:
tail -f ~/logs/varnish-cache/purge.log -n1000

Migration

Attention

The following script is to enable Varnish Cache for sites that have been created before 2.1.
  1. Login via SSH as root user.
  2. Download the script to enable varnish.
curl -sSL https://raw.githubusercontent.com/cloudpanel-io/scripts/master/varnish/enable.php > /tmp/enable-varnish.php
  1. Run the command to enable Varnish Cache for your site.
Copy the command below and replace www.domain.com with your Domain Name.

WordPress

php8.1 /tmp/enable-varnish.php www.domain.com 'WordPress'

Generic

php8.1 /tmp/enable-varnish.php www.domain.com

CodeIgniter

php8.1 /tmp/enable-varnish.php www.domain.com 'CodeIgniter 4'

Laravel

Laravel 9
php8.1 /tmp/enable-varnish.php www.domain.com 'Laravel 9'
Laravel 8
php8.1 /tmp/enable-varnish.php www.domain.com 'Laravel 8'

Before you can use Varnish Cache, you need to replace the vhost.

  1. Go to the Vhost of your site and make a backup.

Copy the Varnish Cache Vhost from below and replace server_name www.domain.com with your domain.

Redirect

The redirect at the beginning of the vhost from non-www to www and vice versa must stay untouched.

In this example, a redirect from domain.com to www.domain.com takes place; we need to leave it as it is and copy the new vhost template below.

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name domain.com;
return 301 https://www.domain.com$request_uri;
}

WordPress

server {
listen 8080;
listen [::]:8080;
server_name www.domain.com;
{{root}}

try_files $uri $uri/ /index.php?$args;
index index.php index.html;

location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_param HTTPS "on";
fastcgi_pass 127.0.0.1:{{php_fpm_port}};
fastcgi_param PHP_VALUE "{{php_settings}}";
}

if (-f $request_filename) {
break;
}
}

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.domain.com;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}

location ~ /.well-known {
auth_basic off;
allow all;
}

{{settings}}

location ~/(wp-admin/|wp-login.php) {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8080;
proxy_max_temp_file_size 0;
proxy_connect_timeout 7200;
proxy_send_timeout 7200;
proxy_read_timeout 7200;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location / {
{{varnish_proxy_pass}}
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header X-Varnish;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_connect_timeout 720;
proxy_send_timeout 720;
proxy_read_timeout 720;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
add_header Access-Control-Allow-Origin "*";
expires max;
access_log off;
}

if (-f $request_filename) {
break;
}
}

Generic

server {
listen 8080;
listen [::]:8080;
server_name www.domain.com;
{{root}}

try_files $uri $uri/ /index.php?$args;
index index.php index.html;

location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_param HTTPS "on";
fastcgi_pass 127.0.0.1:{{php_fpm_port}};
fastcgi_param PHP_VALUE "{{php_settings}}";
}

if (-f $request_filename) {
break;
}
}

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.domain.com;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}

location ~ /.well-known {
auth_basic off;
allow all;
}

{{settings}}

location / {
{{varnish_proxy_pass}}
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header X-Varnish;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_connect_timeout 720;
proxy_send_timeout 720;
proxy_read_timeout 720;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
add_header Access-Control-Allow-Origin "*";
expires max;
access_log off;
}

if (-f $request_filename) {
break;
}
}

Codeigniter

server {
listen 8080;
listen [::]:8080;
server_name www.domain.com;
{{root}}

try_files $uri $uri/ /index.php?$args;
index index.php index.html;

location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_param HTTPS "on";
fastcgi_pass 127.0.0.1:{{php_fpm_port}};
fastcgi_param PHP_VALUE "{{php_settings}}";
}

if (-f $request_filename) {
break;
}
}

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.domain.com;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}

location ~ /.well-known {
auth_basic off;
allow all;
}

{{settings}}

location / {
{{varnish_proxy_pass}}
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header X-Varnish;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_connect_timeout 720;
proxy_send_timeout 720;
proxy_read_timeout 720;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
add_header Access-Control-Allow-Origin "*";
expires max;
access_log off;
}

if (-f $request_filename) {
break;
}
}

Laravel

server {
listen 8080;
listen [::]:8080;
server_name www.domain.com;
{{root}}

try_files $uri $uri/ /index.php?$args;
index index.php index.html;

location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_param HTTPS "on";
fastcgi_pass 127.0.0.1:{{php_fpm_port}};
fastcgi_param PHP_VALUE "{{php_settings}}";
}

if (-f $request_filename) {
break;
}
}

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.domain.com;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}

location ~ /.well-known {
auth_basic off;
allow all;
}

{{settings}}

location / {
{{varnish_proxy_pass}}
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header X-Varnish;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_connect_timeout 720;
proxy_send_timeout 720;
proxy_read_timeout 720;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
add_header Access-Control-Allow-Origin "*";
expires max;
access_log off;
}

if (-f $request_filename) {
break;
}
}

Symfony

server {
listen 8080;
listen [::]:8080;
server_name www.domain.com;
{{root}}

try_files $uri $uri/ /index.php?$args;
index index.php index.html;

location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_param HTTPS "on";
fastcgi_pass 127.0.0.1:{{php_fpm_port}};
fastcgi_param PHP_VALUE "{{php_settings}}";
}

if (-f $request_filename) {
break;
}
}

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.domain.com;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}

location ~ /.well-known {
auth_basic off;
allow all;
}

{{settings}}

location / {
{{varnish_proxy_pass}}
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header X-Varnish;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_connect_timeout 720;
proxy_send_timeout 720;
proxy_read_timeout 720;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
add_header Access-Control-Allow-Origin "*";
expires max;
access_log off;
}

if (-f $request_filename) {
break;
}
}

Slim

server {
listen 8080;
listen [::]:8080;
server_name www.domain.com;
{{root}}

try_files $uri $uri/ /index.php?$args;
index index.php index.html;

location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_param HTTPS "on";
fastcgi_pass 127.0.0.1:{{php_fpm_port}};
fastcgi_param PHP_VALUE "{{php_settings}}";
}

if (-f $request_filename) {
break;
}
}

server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.domain.com;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}

location ~ /.well-known {
auth_basic off;
allow all;
}

{{settings}}

location / {
{{varnish_proxy_pass}}
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_hide_header X-Varnish;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_connect_timeout 720;
proxy_send_timeout 720;
proxy_read_timeout 720;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
add_header Access-Control-Allow-Origin "*";
expires max;
access_log off;
}

if (-f $request_filename) {
break;
}
}

Done. You can now go to Settings and enable Varnish Cache.