zaLinux.ru

Установка и настройка Varnish: ч. 2: как настроить Varnish, примеры правил


Оглавление

1. Как установить Varnish в Debian и Ubuntu

2. Как настроить Varnish, примеры правил

2.1 Как изменить параметры Varnish

2.2 Как изменить время хранения кэша в Varnish

2.3 Как сделать так, чтобы Varnish не создавал новый кэш для разных браузеров

2.4 В кэш Varnish попала страница 403 и теперь она показывается всем пользователям

2.5 Как сделать так, чтобы в логах Apache вместо 127.0.0.1 показывался реальный IP адрес при использовании с Varnish

2.6 Как удалить куки, которые препятствую кэшированию

2.7 Как исключить из кэширования определённые страницы

2.8 Как исключить из кэширования домашнюю страницу

2.9 Как увеличить размер кэша Varnish

2.10 Как увеличить таймаут соединения в Varnish

2.11 Как исключить определённый сайт из кэширования Varnish

2.12 Как кэшировать только определённый домен в Varnish

2.13 Как в Varnish перенаправить HTTP на HTTPS

2.14 Как удалять кукиз со всех хостов, кроме страниц определённого хоста

2.15 Как удалять кукиз со всех страниц за исключением определённых URL

2.16 Добавление и удаление HTTP-заголовков

2.17 Дополнительная документация

3. Вспомогательные программы Varnish


4. Модули Varnish


Это вторая часть из серии статей, посвящённой Varnish. В первой части мы установили и настроили Varnish на работу с веб-сервером. Казалось бы, всё работает нормально и теперь можно перейти к другим делам. Но правда в том, что с настройками по умолчанию Varnish (почти) полностью бесполезен. Дело в том, что по умолчанию:

  • срок хранения кэша 2 минуты
  • для КАЖДОГО User Agent создаётся НОВЫЙ кэш. То есть если страница была запрошена пользователем с брузером Chrome одной версии, а затем пришёл пользователь с другой версией Chrome или с другим браузером, то для него будет создана новая страница, вместо того, чтобы показать сохранённую в кэше.

То есть в кэше по 2 минуты хранятся данные, которые с вероятностью 99% за эти две минуты не будут никому показаны, а затем данные удаляться.

Более того, с настройками по умолчанию Varnish даже вреден: может закэшироваться страница с кодом ответа 503 (ошибка на сервере) или 403 (доступ запрещён) и эта страница будет показывать всем, даже когда проблема исправлена.

В общем, несмотря на то, что многие мануалы в интернете кончаются после этапа установки Varnish и настройки веб-сервера, необходимо продолжить и сделать всё как надо. Именно этому и посвящена данная статья. Здесь мы рассмотрим минимальную необходимую настройку Varnish чтобы от него была польза и не было вреда, а также здесь будут перечислены примеры конфигурации Varnish которые вы можете использовать в различных ситуациях.

Как изменить параметры Varnish

Настроить Varnish можно в конфигурационном файле /etc/varnish/default.vcl, а также отредактировав опции запуска строки команды:

systemctl edit --full varnish

Мы будем использовать оба способа.

Чтобы вступили в силу изменения, сделанные в файле default.vcl, необходимо выполнить команду:

systemctl reload varnish

Эта команда перезагрузит конфигурацию, но сохранит кэш.

Чтобы вступили изменения, внесённые в команду запуска, необходимо выполнить:


systemctl restart varnish

Эта команда не сохранит кэш — он будет очищен.

Как изменить время хранения кэша в Varnish

По умолчанию Varnish хранит кэш всего 2 минуты — для многих ситуаций это слишком мало.

Вопрос хранения кэша в Varnish довольно сложный и ему можно посвятить отдельную статью. Здесь рассмотрим самые основы.

Во-первых, существует три периода, которые Varnish хранит данные в кэше:

  1. TTL — Time To Live. Это время жизни данных. Это тот период, в который данные хранятся в кэше и считаются свежими. «Свежие» - это означает, что при получении запроса на показ страницы, будет отдано содержимое кэша.
  2. Grace. Льготный период. Этот период наступает после TTL. Данные по-прежнему хранятся в кэше, и при получении на них запроса отдаются данные из кэша, в то же самое время запускается обновление данных — делается запрос в веб-серверу.
  3. Keep. Период хранения. Это период, который наступает после TTL и Grace. Данные по-прежнему хранятся в кэше, но отдаются пользователю при определённых условиях.

Все эти периоды можно настроить:

  • в конфигурационном файле
  • в строке команды
  • HTTP заголовками

Мы будем использовать конфигурационный файл /etc/varnish/default.vcl. Откройте его:

vim /etc/varnish/default.vcl

Настройки нужно вносить в раздел vcl_backend_response. Доступно три параметра, соответствующих каждому периоду

  • beresp.ttl
  • beresp.grace
  • beresp.keep

Пример:

sub vcl_backend_response {

	# Вначале мы устанавливаем значение TTL для большинства контента, который нужно кэшировать
	set beresp.ttl = 10m;
	set beresp.grace = 2h;

	# Теперь мы можем установить особые TTL основываясь на контенте, который нужно кэшировать
	# Для VoD мы устанавливаем средне-длинный TTL и долгий льготный (grace) период, поскольку VoD
	# контент не склонен к изменению. Это позволяет нам использовать этот кэш
	# для самого часто запрашиваемого контента

	if (beresp.url ~ "/vod") {
		set beresp.ttl = 30m;
		set beresp.grace = 24h;
	}

	# Для живого контента мы используем очень маленькое TTL и ещё меньших льготный период
	# поскольку живой контент больше не *живой* как только он был потреблён
	
	if (beresp.url ~ "/url") {
		set beresp.ttl = 10s;
		set beresp.grace = 2s;
	}
	
	# Мы увеличиваем продолжительность *keep* (хранения) для IMS

	if (bereq.http.If-Modified-Since) {
		set beresp.keep = 10m;
	}
}	

Как вы могли увидеть из примера, используются суффиксы:

  • ms — миллисекунды
  • s — секунды
  • m — минуты
  • h — часы
  • d — дни
  • w — недели
  • y — года

Дополнительная информация:

Как сделать так, чтобы Varnish не создавал новый кэш для разных браузеров

Если веб-сервер отправляет HTTP заголовок

Vary: User-Agent

То Varnish создаёт новые страницы для каждой версии браузера. То есть для Chrome 85 и Chrome 86 будут созданы разные записи в кэше! По умолчанию Apache отправляет этот HTTP заголовок.

Продемонстрируем это.

Для начала сделаем запрос к веб-сайту используя порт 8080 (то есть минуя кэш подключаемся напрямую к Apache):

curl -I 'http://w-e-b.site:8080/?act=all-country-ip&city=Pattaya'

Обратите внимание на строку:

Vary: User-Agent,Accept-Encoding

Могут быть другие варианты, например:

Vary: User-Agent

Теперь мы дважды запустим команду

time curl -s 'https://w-e-b.site/?act=all-country-ip&city=Pattaya' -A 'Chrome' > /dev/null

В ней мы меряем время и можем убедиться, что второй раз, когда создан кэш, время получения страницы намного меньше. Также в качестве User Agent мы указали Chrome.


Но если поменять значение User Agent, то по затраченному времени видно, что кэш создаётся заново:

time curl -s 'https://w-e-b.site/?act=all-country-ip&city=Pattaya' -A 'Firefox' > /dev/null

Такое поведение системы кэширования обычно не имеет смысла. Поэтому нужно сделать так, чтобы Varnish использовал один и тот же кэш для всех User Agent.

Есть несколько способов это сделать. Самый простой — изменить настройки веб-сервера так, чтобы он не отправлял HTTP заголовок Vary: User-Agent.

Далее показано, как изменить настройки Apache, чтобы он не отправлял Vary: User-Agent.

В Debian и производных:

a2enmod headers

Затем в конфигурационный файл /etc/apache2/apache2.conf добавьте строку:

Header set Vary "Accept-Encoding"

Перезагрузите сервер:

systemctl restart apache2

В Arch Linux и производных:

Убедитесь, что в файле /etc/httpd/conf/httpd.conf раскомментирвоана строка:

LoadModule headers_module modules/mod_headers.so

Затем добавьте в этот же файл строку:

Header set Vary "Accept-Encoding"

Перезагрузите сервер, чтобы изменения вступили в силу:

systemctl restart httpd.service

Мы перезаписали значение HTTP заголовка Vary так, что будет иметь только Accept-Encoding.

Эта настройка точно стоит затраченных усилий! Теперь Varnish будет иметь один кэш для всех веб браузеров.

Дополнительная информация:

В кэш Varnish попала страница 403 и теперь она показывается всем пользователям

Может случиться так, что пользователь, которому запрещён просмотр сайта (забанен по IP или по User Agent) открыл страницу и она попала в кэш. В результате теперь всем пользователям вместо нормальной страницы будет показываться сообщение, что доступ закрыт.

Чтобы это исправить, добавьте следующую настройку:

sub vcl_backend_response {	
	if (beresp.status == 403 || beresp.status == 404 || beresp.status >= 500)
	{
		set beresp.ttl = 3s;
	}
}

Как сделать так, чтобы в логах Apache вместо 127.0.0.1 показывался реальный IP адрес при использовании с Varnish

Поскольку Apache теперь получает запросы от Varnish, то теперь журналах веб-сервера в качестве IP адресов клиентов показывается всегда 127.0.0.1.

Это можно исправить следующим образом:

  • Мы указываем Varnish при отправке запросов к Apache серверу добавлять HTTP заголовок X-Forwarded-For содержащий реальный IP адрес пользователя
  • А в Apache мы включаем модуль mod_remoteip и указываем в настройках использовать IP адрес из HTTP заголовка X-Forwarded-For в качестве реального IP адреса пользователя

То есть необходимо настраивать и Varnish, и Apache. Но настройка весьма полезная и стоит того!

Начнём с настройки Varnish, в конфигурационный файл которой добавьте:

sub vcl_recv {
    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;
       }
    }
}

Настройки веб-сервера немного различаются в зависимости от дистрибутива.

В Debian и производных:

a2enmod remoteip

Затем в конфигурационный файл /etc/apache2/apache2.conf добавьте строку:

RemoteIPHeader x-forwarded-for

Перезагрузите сервер:

systemctl restart apache2

В Arch Linux и производных:


Убедитесь, что в файле /etc/httpd/conf/httpd.conf раскомментирвоана строка:

LoadModule remoteip_module modules/mod_remoteip.so

Затем добавьте в этот же файл строку:

RemoteIPHeader x-forwarded-for

Перезагрузите сервер, чтобы изменения вступили в силу:

systemctl restart httpd.service

Дополнительная информация:

В некоторых руководствах можно встретить совет модифицировать формат логов Apache — это тоже сработает, если сделать правильно, но это займёт больше времени.

Как удалить куки, которые препятствую кэшированию

Запросы, в которых присылаются кукиз, не кэшируются. Если у вас на сайте имеются блоки рекламы или метрики (счётчики), то можно сказать, что Varnish ничего не кэширует. Причём в случае с кукиз рекламных сетей и счётчиков, это ещё и абсолютно бесполезные данные для сервера.

Чтобы удалить все кукиз и позволить данным кэшироваться добавьте:

sub vcl_recv {
	unset req.http.Cookie;
}

Эта настройка нарушит работу сайтов, полагающихся на кукиз. Например, если у вас WordPress сайт с регистрацией для пользователей, то для идентификации пользователей необходимы кукиз. В таких случаях лучше воспользоваться другим решением, например, Memcached. Смотрите статью «Виртуальный хостинг с Memcached и WP-FFPC».

Как исключить из кэширования определённые страницы

Для исключения из кэширования всех путей, содержащих в любом месте URL строку «/путь/для/исключения/»:

sub vcl_recv {
	if (req.url ~ "^/путь/для/исключения/") {
		return (pass);
	}
}

Обратите внимание, что символ ~ (тильда) означает, что поиск выполняется по регулярному выражению. А символ ^ (каретка) означает начало строки.

Если вы хотите, чтобы были исключены URL, в которых «/путь/для/исключения/» встречается в любой части URL, то уберите символ ^, например:

sub vcl_recv {
	if (req.url ~ "/путь/для/исключения/") {
		return (pass);
	}
}

Если вы хотите, чтобы поиск выполнялся не по регулярному выражению, а по точному совпадению, то замените ~ на ==, например:

sub vcl_recv {
	if (req.url == "/путь/для/исключения/") {
		return (pass);
	}
}

Вы можете использовать конструкцию if () {} несколько раз или объединить их в одну. Символ || означает логическое «ИЛИ»:

sub vcl_recv {
	if (req.url ~ "myip" || req.url ~ "proxy-checker" || req.url ~ "my-user-agent") {
		return (pass);
	}
}

То есть предыдущая настройка исключит из кэширования все страницы, в любом месте URL которых встречается строка «myip» или строка «proxy-checker» или строка «my-user-agent».

Пример, в котором для хоста suip.biz исключаются из кэша страницы, содержащие в URL строку «/ru»:

sub vcl_recv {
	if (req.http.host == "suip.biz" && req.url == "/ru") {
		return (pass);
	}
}

Как исключить из кэширования домашнюю страницу

В следующем примере для хоста suip.biz исключается из кэша домашняя страница:

sub vcl_recv {
	if (req.http.host == "suip.biz" && req.url == "/") {
		return (pass);
	}
}

Как увеличить размер кэша Varnish

Настройки размера кэша нужно менять в строке запуска команды, для этого:

systemctl edit --full varnish

Для изменения размера кэша в оперативной памяти отредактируйте опцию -s. Кстати, malloc означает, что кэш хранится в оперативной памяти. Вы можете указать хранить его в файле — если вам это нужно, то обратитесь к документации.

Укажите желаемый размер кэша, например -s malloc,1400m.

Чтобы изменения вступили в силу, перезагрузите службу varnish:

systemctl restart varnish

Как увеличить таймаут соединения в Varnish

Если отправка данных от Varnish клиенту не закончена в течение 60 секунд, то такое соединение прерывается. Для обычных сайтов это нормально, но для видео порталов или сервисов, выполняющих продолжительное действие, этого может не хватить.

В Varnish довольно много параметров таймаутов, вы можете просмотреть их значение командой:

varnishadm param.show | grep timeout

Пример вывода:

backend_idle_timeout          60.000 [seconds] (default)
between_bytes_timeout         60.000 [seconds] (default)
cli_timeout                   60.000 [seconds] (default)
connect_timeout               3.500 [seconds] (default)
first_byte_timeout            60.000 [seconds] (default)
idle_send_timeout             60.000 [seconds] (default)
pipe_timeout                  60.000 [seconds] (default)
send_timeout                  60.000 [seconds] (default)
thread_pool_timeout           300.000 [seconds] (default)
timeout_idle                  5.000 [seconds] (default)
timeout_linger                0.050 [seconds] (default)

Нужный нам параметр, отвечающий за максимальное время отправки данных в течение одного соединения, называется send_timeout.

Чтобы его изменить, необходимо отредактировать строку команды

systemctl edit --full varnish

Добавьте к команде опцию вида:

-p send_timeout=СЕКУНДЫ

Например, чтобы установить таймаут соединения на 10 минут:

-p send_timeout=600

Обратите внимание, что нельзя указывать суффикс «s» или любой другой, иначе программа не запустится. Нужно указать только число, означающие секунды для таймаута соединения.

Этой настройкой мы изменили значение максимального времени отправки данных. Но есть ещё один таймаут, который устанавливает максимальную продолжительность соединения. Для его редактирования откройте файл /etc/varnish/default.vcl и добавьте туда настройки:

backend default {
	.connect_timeout = 600s;
	.first_byte_timeout = 600s;
	.between_bytes_timeout = 600s;
}

Чтобы не редактировать опции запуска службы, я пытался добавить опцию send_timeout в конфигурационный файл, но в этом случае служба не запускается из-за ошибки. Если вы знаете, в чём дело и как обойтись без добавления опции в строке команды, то пишите в комментариях.

Чтобы изменения вступили в силу, перезагрузите службу varnish:

systemctl restart varnish

Дополнительная информация:

Как исключить определённый сайт из кэширования Varnish

Исключение из хеширования сайта softocracy.ru:

sub vcl_recv {
   if (req.http.host ~ "(www\.)?softocracy\.ru") {
     return(pass);
   }
}

Если вы не хотите, чтобы какой-либо сайт кэшировался, то целиком исключите его из кэширования. В примере выше поменяйте softocracy.ru на домен сайта, который не должен кэшироваться.

Как кэшировать только определённый домен в Varnish

Для всех других доменов нужно возвратить pass:

sub vcl_recv {
	# если это любой домен, кроме example.com, то пропускаем кэширование
	if (! req.http.host ~ "(www\.)?example\.com") {
		return (pass);
	}
	# в противном случае переключаемся на поведение по умолчанию
}

pass говорит Varnish не заглядывать в его кэш, он всегда будет получать контент от конечного веб-сервера.

Как в Varnish перенаправить HTTP на HTTPS

Из предыдущей части вы уже знаете, что методами веб-сервера уже невозможно сделать редирект на HTTPS, поскольку Apache больше не работает с HTTPS соединениями и даже не прослушивает порт 443.

Следующий пример покажет настройку Varnish для перенаправления всех запросов на сайт suip.biz с HTTP на HTTPS протокол.

import std;

sub vcl_recv {
	# Просим Varnish выдать 750 статус для HTTP запросов с внешних IP на 80 порт,
	# но не с SSL Termination Proxy (Hitch).
	if ((client.ip != "127.0.0.1" && std.port(server.ip) == 80) && (req.http.host ~ "^(?i)(www\.)?suip.biz")) {
		set req.http.x-redir = "https://" + req.http.host + req.url;
		return (synth(750, ""));
	}
}


sub vcl_synth {
	# Слушаем 750 статус от vcl_recv.
	if (resp.status == 750) {
		// Перенаправляем на HTTPS со статусом 301.
		set resp.status = 301;
		set resp.http.Location = req.http.x-redir;
		return(deliver);
	}
}

В предыдущем примере конфигурации замените домен «suip.biz» на ваш собственный.

Как удалять кукиз со всех хостов, кроме страниц определённого хоста

Если вы хотите, чтобы кукиз удалялись для страниц всех хостов, кроме страниц определённого хоста, то используйте настройку вида:

sub vcl_recv {
	if (! req.http.host ~ "(www\.)?ЗДЕСЬ\.ДОМЕН") {
		unset req.http.Cookie;
	}
}

Вместо «ЗДЕСЬ\.ДОМЕН» впишите домен, на котором не нужно удалять кукиз. Обратите внимание на экранирование точки.

Пример настройки, в которой удаляются кукиз со всех доменов, кроме страниц доменов wxmaxima.ru и softocracy.ru:

sub vcl_recv {
	if (! req.http.host ~ "(www\.)?wxmaxima\.ru" && ! req.http.host ~ "(www\.)?softocracy\.ru") {
		unset req.http.Cookie;
	}
}

Внимание:

1. Перезапустите службу varnish, чтобы изменения вступили в силу:

systemctl restart varnish

2. В конфигурационном файле используйте «unset req.http.Cookie;» только один раз! Если вы будете использовать два и более раза, то поведение будет не тем, каким вы ожидаете. Сгруппируйте все нужные вам условия с помощью логических И и ИЛИ перед единственным использованием «unset req.http.Cookie;».

Как удалять кукиз со всех страниц за исключением определённых URL

Если вы хотите исключить из удаления кукиз только определённые страницы, то используйте настройку вида:

sub vcl_recv {
	if (! req.url ~ "^/путь/для/исключения/") {
		unset req.http.Cookie;
	}
}

Пример настройки, в которой удаляются кукиз со всех доменов, кроме страниц доменов wxmaxima.ru и страниц на любых доменах, в чьём URL адресе есть строка «phpmyadmin»:

sub vcl_recv {
	if (! req.http.host ~ "(www\.)?wxmaxima\.ru" && ! req.url ~ "^/phpmyadmin") {
		unset req.http.Cookie;
	}
}

Внимание:

1. Перезапустите службу varnish, чтобы изменения вступили в силу:

systemctl restart varnish

2. В конфигурационном файле используйте «unset req.http.Cookie;» только один раз! Если вы будете использовать два и более раза, то поведение будет не тем, каким вы ожидаете. Сгруппируйте все нужные вам условия с помощью логических И и ИЛИ перед единственным использованием «unset req.http.Cookie;».

Добавление и удаление HTTP-заголовков

Varnish Cache даёт вам возможность изменять, добавлять и удалять заголовки HTTP для объекта запроса и ответа.

Заголовки запроса

Подпрограмма vcl_recv вызывается в начале запроса, и именно здесь мы будем изменять заголовки запроса. Мы добавим заголовок hello со значением world и удалим заголовок пользовательского агента.

sub vcl_recv {
	...

	set req.http.hello = "world";
	unset req.http.user-agent;

	...
}

Объект req.http предназначен для доступа к любому заголовку запроса и доступен для чтения только из vcl_recv и vcl_deliver.

Заголовки ответа

Подпрограмма vcl_backend_response вызывается, когда Varnish Cache получает заголовки ответа от вышестоящей службы. Мы изменим элемент управления кешем заголовков и установим значение public, max-age=600, и удалим заголовок сервера.

sub vcl_backend_response {
	...

	set beresp.http.cache-control = "public, max-age=600";
	unset beresp.http.server;

	...
}

Объект beresp.http предназначен для доступа к любому заголовку ответа и доступен для чтения только из vcl_backend_response и vcl_deliver.

Дополнительная документация:


Рекомендуемые статьи:

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *