How to speed up Drupal using Varnish on Debian 9

How to Speed Up Drupal Using Varnish on Debian 9

We’ll show you how to speed up Drupal using Varnish on a Debian 9 VPS. Drupal is a popular open source web content management software written in PHP. Drupal is compatible with Varnish 3 and Varnish 4. It is a cross-platform application and supports all popular operating systems, but this tutorial was written for Debian 9 OS. At the time of writing this tutorial, the latest stable version of Drupal is 8.4.4, and it requires:

  • PHP 5.5.9 or higher (preferably PHP 7.0), with GD library, JSON, cURL, mysqli , Mbstring, DOM, OpenSSL and XML PHP extensions enabled. PHP 7.2 is not supported on the current release.
  • MySQL – 5.5.3 (MariaDB 5.5.20, Percona 5.5.8) or higher with an InnoDB-compatible primary storage engine, PostgreSQL – 9.1.2 or higher, or QLite – 3.6.8 or higher
  • Apache web server 2.2 or higher compiled with mod_rewrite module and AllowOverride set to ‘All’ (please note, the default setting for AllowOverride in Apache 2.3.9 and higher is ‘None’).

This install guide assumes that Apache and MySQL/MariaDB are already installed and configured on your virtual server.
Let’s start with the installation procedure.

1. Update the System Packages

Make sure your server Debian 9 OS packages are fully up-to-date:

apt-get update 
apt-get upgrade

2. Install the Required Packages

Install the required PHP packages for Drupal 8:

apt-get install php7.0 php7.0-cli php7.0-common php7.0-mbstring php7.0-curl php7.0-gd php7.0-json php7.0-mcrypt php7.0-mysql php7.0-xml

3. Enable Apache Rewrite Module

Enable Apache rewrite module if it is not already done so:

a2enmod rewrite

4. Restart Apache

Restart the Apache service for the changes to take effect:

service apache2 restart

5. Download and Extract Drupal 8 Files

Download Drupal 8 and install if from source, or install Drupal 8 using Composer.

5.1 Download Drupal 8 from source

Download the latest version of Drupal available at https://www.drupal.org/download in the /opt/ directory on the server:

cd /opt/
mkdir -p /var/www/html/yourdomain.com/
wget -O drupal8.tar.gz https://ftp.drupal.org/files/projects/drupal-8.4.4.tar.gz
tar -xvzf drupal*
mv drupal-*/* /var/www/html/yourdomain.com/

5.2 Download and Install Drupal 8 using Composer – a PHP dependency manager

If you downloaded and extracted Drupal from source, you can skip this step and go to step 6.
Install Composer:

apt-get install composer
mkdir -p /var/www/html/yourdomain.com/
cd /var/www/html/yourdomain.com/

To install the Drupal 8 website on a development server, run:

composer create-project drupal-composer/drupal-project:8.x-dev /var/www/html/yourdomain.com/ --stability dev --no-interaction

Optionally, install Twig C extension:

composer require twig/twig:~1.0

To install the Drupal 8 website on a production server, you also need to run:

composer install --no-dev

This will run the composer install process again remove everyhing from the “require-dev” section from the composer.lock file.

6. Set Proper Ownership of Drupal Files

All files have to be readable by the web server, so set a proper ownership:

chown www-data:www-data -R /var/www/html/yourdomain.com/

7. Create MySQL Database and User

Create a new MySQL database and user:

mysql -u root -p
mysql> SET GLOBAL sql_mode='';
mysql> CREATE DATABASE drupaldb;
mysql> CREATE USER 'drupaluser'@'localhost' IDENTIFIED BY 'y0uR-pa5sW0rd';
mysql> GRANT ALL PRIVILEGES ON drupaldb.* TO 'drupaluser'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> quit

Do not forget to replace ‘y0uR-pa5sW0rd’ with a strong password.

8. Install and Configure Varnish

apt-get install varnish

Configure Varnish to listen on port 80. Edit the ‘/etc/default/varnish’ Varnish configuration file:

nano etc/default/varnish

Add these lines at the end:

DAEMON _OPTS="-a :80\
  -T localhost:6082
  -f /etc/varnish/default.vcl
  -s malloc,512m"
  -S /etc/varnish/secret

Create a new varnish startup script for systemd:

nano /etc/systemd/system/varnish.service
[Unit]
Description=Varnish HTTP accelerator
Documentation=https://www.varnish-cache.org/docs/4.1/ man:varnishd

[Service]
Type=simple
LimitNOFILE=131072
LimitMEMLOCK=82000
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
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
PrivateDevices=true

[Install]
WantedBy=multi-user.target

Run the following command to reload systemd manager configuration:

systemctl daemon-reload

Back up default.vcl:

mv /etc/varnish/default.vcl /etc/varnish/default.vcl.bak

Create a new default.vcl file (do not forget to change yourdomain.com with the actual domain name):

nano /etc/varnish/default.vcl

Add these lines

backend default {

.host = “yourdomain.com“;

.port = “8080”;

}

# Access control list for PURGE requests.
# Here you need to put the IP address of your web server
acl purge {
“127.0.0.1”;
}

# Respond to incoming requests.
sub vcl_recv {
# Add an X-Forwarded-For header with the client IP address.
if (req.restarts == 0) {
if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + “, ” + client.ip;
}
else {
set req.http.X-Forwarded-For = client.ip;
}
}

# Only allow PURGE requests from IP addresses in the ‘purge’ ACL.
if (req.method == “PURGE”) {
if (!client.ip ~ purge) {
return (synth(405, “Not allowed.”));
}
return (hash);
}

# Only allow BAN requests from IP addresses in the ‘purge’ ACL.
if (req.method == “BAN”) {
# Same ACL check as above:
if (!client.ip ~ purge) {
return (synth(403, “Not allowed.”));
}

# Logic for the ban, using the Cache-Tags header. For more info
# see https://github.com/geerlingguy/drupal-vm/issues/397.
if (req.http.Cache-Tags) {
ban(“obj.http.Cache-Tags ~ ” + req.http.Cache-Tags);
}
else {
return (synth(403, “Cache-Tags header missing.”));
}

# Throw a synthetic page so the request won’t go to the backend.
return (synth(200, “Ban added.”));
}

# Only cache GET and HEAD requests (pass through POST requests).
if (req.method != “GET” && req.method != “HEAD”) {
return (pass);
}

# Pass through any administrative or AJAX-related paths.
if (req.url ~ “^/status\.php$” ||
req.url ~ “^/update\.php$” ||
req.url ~ “^/admin$” ||
req.url ~ “^/admin/.*$” ||
req.url ~ “^/flag/.*$” ||
req.url ~ “^.*/ajax/.*$” ||
req.url ~ “^.*/ahah/.*$”) {
return (pass);
}

# Removing cookies for static content so Varnish caches these files.
if (req.url ~ “(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$”) {
unset req.http.Cookie;
}

# Remove all cookies that Drupal doesn’t need to know about. We explicitly
# list the ones that Drupal does need, the SESS and NO_CACHE. If, after
# running this code we find that either of these two cookies remains, we
# will pass as the page cannot be cached.
if (req.http.Cookie) {
# 1. Append a semi-colon to the front of the cookie string.
# 2. Remove all spaces that appear after semi-colons.
# 3. Match the cookies we want to keep, adding the space we removed
# previously back. (\1) is first matching group in the regsuball.
# 4. Remove all other cookies, identifying them by the fact that they have
# no space after the preceding semi-colon.
# 5. Remove all spaces and semi-colons from the beginning and end of the
# cookie string.
set req.http.Cookie = “;” + req.http.Cookie;
set req.http.Cookie = regsuball(req.http.Cookie, “; +”, “;”);
set req.http.Cookie = regsuball(req.http.Cookie, “;(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=”, “; \1=”);
set req.http.Cookie = regsuball(req.http.Cookie, “;[^ ][^;]*”, “”);
set req.http.Cookie = regsuball(req.http.Cookie, “^[; ]+|[; ]+$”, “”);

if (req.http.Cookie == “”) {
# If there are no remaining cookies, remove the cookie header. If there
# aren’t any cookie headers, Varnish’s default behavior will be to cache
# the page.
unset req.http.Cookie;
}
else {
# If there is any cookies left (a session or NO_CACHE cookie), do not
# cache the page. Pass it on to Apache directly.
return (pass);
}
}
}

# Set a header to track a cache HITs and MISSes.
sub vcl_deliver {
# Remove ban-lurker friendly custom headers when delivering to client.
unset resp.http.X-Url;
unset resp.http.X-Host;
# Comment these for easier Drupal cache tag debugging in development.
unset resp.http.Cache-Tags;
unset resp.http.X-Drupal-Cache-Contexts;

if (obj.hits > 0) {
set resp.http.Cache-Tags = “HIT”;
}
else {
set resp.http.Cache-Tags = “MISS”;
}
}

# Instruct Varnish what to do in the case of certain backend responses (beresp).
sub vcl_backend_response {
# Set ban-lurker friendly custom headers.
set beresp.http.X-Url = bereq.url;
set beresp.http.X-Host = bereq.http.host;

# Cache 404s, 301s, at 500s with a short lifetime to protect the backend.
if (beresp.status == 404 || beresp.status == 301 || beresp.status == 500) {
set beresp.ttl = 10m;
}

# Don’t allow static files to set cookies.
# (?i) denotes case insensitive in PCRE (perl compatible regular expressions).
# This list of extensions appears twice, once here and again in vcl_recv so
# make sure you edit both and keep them equal.
if (bereq.url ~ “(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$”) {
unset beresp.http.set-cookie;
}

# Allow items to remain in cache up to 6 hours past their cache expiration.
set beresp.grace = 6h;
}

9. Change Apache Listening ports

nano /etc/apache2/ports.conf
Change:
Listen 80
to
Listen 8080

Edit the main Apache configuration file (/etc/apache2/apache2.conf), search for ” and change ‘AllowOverride None’ to ‘AllowOverride All’ so it looks like:

<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

Also, change the port from 80 to 8080 in all virtual hosts located in /etc/apache2/sites-available directory.

10. Create a New Virtual Host in Apache

Create a new virtual host directive in Apache. For example, create a new Apache configuration file named ‘yourdomain.conf’ on your virtual server:

touch /etc/apache2/sites-available/yourdomain.conf
ln -s /etc/apache2/sites-available/yourdomain.conf /etc/apache2/sites-enabled/yourdomain.conf
nano /etc/apache2/sites-available/yourdomain.conf

Then, add the following lines:

<VirtualHost *:8080>
ServerAdmin [email protected]
DocumentRoot /var/www/html/yourdomain.com
ServerName yourdomain.com
ServerAlias www.yourdomain.com
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /var/www/html/yourdomain.com>
DirectoryIndex index.php
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/apache2/yourdomain.com-error_log
CustomLog /var/log/apache2/yourdomain.com-access_log common
</VirtualHost>

If you downloaded Drupal 8 using Composer, replace ‘/var/www/html/yourdomain.com’ with ‘/var/www/html/yourdomain.com/web’ in the ‘DocumentRoot’ and ‘Directory’ virtual host directives.

11. Restart Apache and Varnish

Restart Apache and Varnish services for the changes to take effect:

service apache2 restart
service varnish restart

12. Install Drupal 8

Open http://yourdomain.com in a web browser , choose install language, click on the ‘Save and continue’ button, select an installation profile (standard), enter the database name, username and password and start the installation. Once installed, you will automatically be redirected to the Drupal 8 administration back-end.

13. Configure Caching

Go to the Drupal 8 administration back-end, click Configuration >> Performance >> set the page cache maximum age and click on the ‘Save configuration’ button:

How to speed up Drupal using Varnish on Debian 9

14. Install Purge and Varnish Purger Modules in Drupal 8

Install the Purge module from the Drupal 8 administration back-end by clicking on Extend >> Install new module , then enter: https://ftp.drupal.org/files/projects/purge-8.x-3.0-beta8.tar.gz in the ‘Install from a URL’ field and click on the ‘Install’ button.

speed up Drupal using Varnish on Debian 9

Then, install the Varnish Purger module by clicking on Extend >> Install new module >> enter: https://ftp.drupal.org/files/projects/purge-8.x-3.0-beta8.tar.gz in the ‘Install from a URL’ field and click on the ‘Install’ button.

Open http://yourdomain.com/admin/modules and select Purge, Purge Drush, Purge Tokens, Purge UI, Cron processor, Late runtime processor, Core tags queuer, Varnish Focal Point Purger, Varnish Image Purge, Varnish Purger and Varnish Purger Tags, then click on the ‘Install’ button.

15. Configure Varnish Purger

Open http://yourdomain.com/admin/config/development/performance/purge , click Add purger >> Varnish Purger and click on the ‘Add’ button. Click on the newly created button, select configure and add ‘Varnish Purger’ in the name field:

how to speed up Drupal using Varnish on Debian 9

Configure the Purger’s headers by clicking on Headers >> and enter ‘Cache-Tags’  in the header field with the value [invalidation:expression] and click on the ‘Save configuration’ button.

16. Test if Varnish Caching works

In order to test if Varnish caching is woking properly, run the following command on your server:

curl -s --head http://yourdomain.com/about | grep -i cache
Cache-Tags: MISS

Then, run it once again:

curl -s --head http://yourdomain.com/about | grep -i cache

You should receive an output like this:

Cache-Tags: HIT

You can also use varnishadm, varnishstat and varnishlog command line utilities to check if everything works OK.

That is it. Drupal 8 has been configured to use Varnish.


Of course you don’t have to speed up Drupal using Varnish on Debian 9, if you use one of our Linux Server Support Services, in which case you can simply ask our expert Linux admins to do this for you. They are available 24×7 and will take care of your request immediately.

PS. If you liked this post, on how to speed up Drupal using Varnish on Debian, please share it with your friends on the social networks using the buttons on the left or simply leave a reply below. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *