Установка и настройка кеширующего прокси-сервера VARNISH за NGINX и Apache2 на Ubuntu 18.04 LTS для WordPress в 2019 году
Устанавливаем Varnish:
apt-get install varnish
Файл параметров запуска располагается здесь — /etc/default/varnish. В DAEMON_OPTS задаём следующие параметры:
DAEMON_OPTS="-a :8181 \ -T 127.0.0.1:8282 \ -f /etc/varnish/default.vcl \ -S /etc/varnish/secret \ -s malloc,128m"
-a — задаёт порт, на котором Varnish будет принимать соединения, в нашем случае от фронтенда — nginx;
-T — здесь крутится админка, подробнее в описании к флагу -S;
-f — файл с конфигурацией VCL — специальном языке, предназначенном для определения правил обработки запросов и кэширования в Varnish;
-S — Varnish имеет панель администрирования. Для входа необходимо выполнить команду varnishadm, при этом пользователь должен иметь права на чтение файла /etc/varnish/secret для прохождения аутентификации;
-s указание места хранения кэша и его размер, в данном случае 128Mб в оперативной памяти.
Как вы уже, наверное, поняли, самое интересное нас ждёт в файле с правилами обработки запросов. Во время старта процесса Varnish’а данный файл компилируется. В VCL используется несколько подразделов-функций, в которых описываются эти правила. Кратко расскажу о них, полное описание рекомендую прочитать на официальном сайте.
sub vcl_recv — данная функция используется когда приходит запрос от клиента;
sub vcl_pass — выполняется, когда запрос клиента необходимо передать напрямую бэкенду, не кэшировать и не искать соответствия в кэше;
sub vcl_hash — определяет правила кэширования, можно использовать несколько хранилищ для одного и того же документа, в зависимости от разных условий, например, поддержки сжатия клиентом, или каких-либо других особенностей клиента. В нашем случае не будет использоваться, так как клиент у нас для Varnish’а один — nginx на фронтенде;
sub vcl_backend_response — данная функция используется когда приходит запрос от бэкенда (nginx);
sub vcl_deliver — используется непосредственно перед отправкой данных клиенту, например, для добавления/изменения заголовков.
Схема работы компонентов VCL может быть представлена следующим образом:
Если обращение к бэкенду происходит при этом из функции vcl_miss ответ бэкенда отправляется и в кэш. Сам язык очень похож на C. Приступим к настройке. Открываем файл /etc/varnish/default.vcl и начинаем кодить:
# Сообщаем компилятору о том, что используется новая версия VCL 4
vcl 4.0;
# Настройки бэкенда
backend default {
.host = "127.0.0.1";
.port = "8080";
}
# Диапазон IP/Хостов, которым разрешено выполнять PURGE-запросы для очистки кэша
acl purge {
"localhost";
"127.0.0.1";
}
# Получение запроса от клиента
sub vcl_recv {
# Разрешить очистку кэша вышеописанному диапазону
if (req.method == "PURGE") {
# Если запрос не из списка, то разворачивать
if (!client.ip ~ purge) {
return(synth(405, "This IP is not allowed to send PURGE requests."));
}
return (purge);
}
# POST-запросы а также страницы с Basic-авторизацией пропускать
if (req.http.Authorization || req.method == "POST") {
return (pass);
}
# Пропускать админку и страницу входа
if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") {
return (pass);
}
# Пропускать sitemap и файл robots, у меня sitemap генерируется плагином Google XML Sitemaps
if (req.url ~ "sitemap" || req.url ~ "robots") {
return (pass);
}
# Удаляем cookies, содержащие "has_js" и "__*", добавляемые CloudFlare и Google Analytics, так как Varnish не будет кэшировать запросы, для которых установлены cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
# Удаление префикса ";" в cookies, если вдруг будет обнаружен
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
# Удаляем Quant Capital cookies (добавляются некоторыми плагинами)
set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
# Удаляем wp-settings-1 cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", "");
# Удаляем wp-settings-time-1 cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", "");
# Удаляем wp test cookie
set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");
# Удаляем cookie, состоящие только из пробелов (или вообще пустые)
if (req.http.cookie ~ "^ *$") {
unset req.http.cookie;
}
# Для статических документов удаляем все cookies, пусть себе кэшируются
if (req.url ~ "\.(css|js|png|gif|jp(e)?g|swf|ico|woff|svg|htm|html)") {
unset req.http.cookie;
}
# Если установлены cookies "wordpress_" или "comment_" пропускаем напряиую к бэкенду
if (req.http.Cookie ~ "wordpress_" || req.http.Cookie ~ "comment_") {
return (pass);
}
# Если cookie не найдено, удаляем данный параметр из пришедшего запроса как таковой
if (!req.http.cookie) {
unset req.http.cookie;
}
# Не кэшировать запросы с установленными cookies, это уже не касается WordPress
if (req.http.Authorization || req.http.Cookie) {
# Not cacheable by default
return (pass);
}
# Кэшировать всё остальное
return (hash);
}
sub vcl_pass {
return (fetch);
}
sub vcl_hash {
hash_data(req.url);
return (lookup);
}
# Приём ответа от бэкенда
sub vcl_backend_response {
# Удаляем ненужные заголовки
unset beresp.http.Server;
unset beresp.http.X-Powered-By;
# Не хранить в кэше robots и sitemap и .xml файлы
if (bereq.url ~ "sitemap" || bereq.url ~ "robots" || bereq.url ~ ".xml") {
set beresp.uncacheable = true;
set beresp.ttl = 30s;
return (deliver);
}
# Для статических файлов, которые отдаёт бэкенд...
if (bereq.url ~ "\.(css|js|png|gif|jp(e?)g)|swf|ico|woff|svg|htm|html") {
# Удаляем все куки
unset beresp.http.cookie;
# Устанавливаем срок хранения в кэше - 70 дней
set beresp.ttl = 70d;
# Устанавливаем заголовки Cache-Control и Expires, сообщая браузеру о том, что эти файлы стоит сохранить в кэше клиента и не нагружать лишниий раз наш сервер
unset beresp.http.Cache-Control;
set beresp.http.Cache-Control = "public, max-age=6048000";
set beresp.http.Expires = now + beresp.ttl;
}
# Не кэшировать админку и страницу логина
if (bereq.url ~ "wp-(login|admin)" || bereq.url ~ "preview=true") {
set beresp.uncacheable = true;
set beresp.ttl = 30s;
return (deliver);
}
# Разрешить устанавливать куки только при обращении к этим путям, всё остальное будет резаться
if (!(bereq.url ~ "(wp-login|wp-admin|preview=true)")) {
unset beresp.http.set-cookie;
}
# Не кэшировать результат ответа на POST-запрос или Basic авторизации
if ( bereq.method == "POST" || bereq.http.Authorization ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# Не кэшировать результаты поиска
if ( bereq.url ~ "\?s=" ){
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# Не кэшировать страницы ошибок, только нужные вещи в кэше!
if ( beresp.status != 200 ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# Хранить в кэше всё прочее на протяжении одного дня
set beresp.ttl = 1d;
# Срок жизни кэша после истечения его TTL
set beresp.grace = 30s;
return (deliver);
}
# Действия перед отдачей результата пользователю
sub vcl_deliver {
# Удаляем ненужные заголовки
unset resp.http.X-Powered-By;
unset resp.http.Server;
unset resp.http.Via;
unset resp.http.X-Varnish;
return (deliver);
}
После чего выполняем команду:
service varnish restart
Проблема Varnish и UBUNTU 18.04 LTS
А что если вы захотите изменить порт, на котором Varnish будет принимать входящие соединения или изменить объём кэша. Судя по официальной документации нужно изменить файл с параметрами запуска Varnish, располагающийся по пути: /etc/default/varnish и перезапустить сервис. Но нет! Ничего не изменится, и если мы зайдём в top и нажмем на клавишу ‘c’, то увидим, что сервис запущен с прежними настройками. А всё дело в том, что в новой версии Ubuntu используется systemd вместо init.d в качестве системы инициализации, и поэтому нужно зайти в файл /lib/systemd/system/varnish.service и прописать там в директиве ExecStart те же параметры запуска:
[Unit]
Description=Varnish HTTP accelerator
[Service]
Type=forking
LimitNOFILE=131072
LimitMEMLOCK=82000
ExecStartPre=/usr/sbin/varnishd -C -f /etc/varnish/default.vcl
ExecStart=/usr/sbin/varnishd -a :8181 -T 127.0.0.1:8282 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,128m
ExecReload=/usr/share/varnish/reload-vcl
[Install]
WantedBy=multi-user.target
После сохранения выполнить следующие команды для вступления изменений в силу:
systemctl daemon-reload service varnish restart
В данный момент данная проблема отписана разработчикам, когда и как они её решат — неизвестно, поэтому на всякий случай производите одинаковые изменения в обоих файлах, чтобы однажды после апдейта всё не упало.
После чего нужно изменить порт доступа у nginx
proxy_pass: http://127.0.0.1:8181/;
Настройка WordPress — плагин «Varnish HTTP Purge»
Устанавливаем в панели администрирования WP плагин «Varnish HTTP Purge». Теперь при обновлении данных на измененные страницы будет отправлен PURGE-запрос, очищающий кэш в Varnish, и для посетителей данные всегда будут обновлёнными.
После чего нужно ещё настроить пару строчек по примеру:
Varnish Vontrol Key берется из файла: /etc/varnish/secret
Статья на основе: https://habr.com/ru/post/278189/
Настройка множества сайтов на одном сервере: https://stackoverflow.com/questions/3334023/configure-multiple-sites-with-varnish