Как настроить Varnish для нескольких приложений, содержащих WordPress и Ghost CMS с nginx в качестве прокси?

Мы настраиваем систему кеширования лака для платформы блогов WordPress и Ghost с nginx в качестве веб-сервера/прокси.

Wordpress Vcl (по умолчанию)

vcl 4.0;

import std;

backend default {
.host = "127.0.0.1";
.port = "8080";
.first_byte_timeout = 600s;
}

acl purger {
"localhost";
"127.0.0.1";
"172.17.0.1";
}

sub vcl_recv {
if (req.restarts \> 0) {
set req.hash_always_miss = true;
}

    #return (pass);
    
    if (req.method == "PURGE") {
        if (client.ip !~ purger) {
            return (synth(405, "Method not allowed"));
        }
        if (req.http.X-Cache-Tags) {
          ban("obj.http.X-Cache-Tags ~ " + req.http.X-Cache-Tags);
        } else {
          ban("req.http.host == " +req.http.host+" && req.url ~ "+req.url);
          return (synth(200, "Purged"));
        }
        return (synth(200, "Purged"));
    }
    
    if (req.method != "GET" &&
        req.method != "HEAD" &&
        req.method != "PUT" &&
        req.method != "POST" &&
        req.method != "TRACE" &&
        req.method != "OPTIONS" &&
        req.method != "DELETE") {
          /* Non-RFC2616 or CONNECT which is weird. */
          return (pipe);
    }
    
    # We only deal with GET and HEAD by default
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }
    
    # Set initial grace period usage status
    set req.http.grace = "none";
    
    # normalize url in case of leading HTTP scheme and domain
    set req.url = regsub(req.url, "^http[s]?://", "");
    
    # collect all cookies
    std.collect(req.http.Cookie);
    
    if (req.url ~ "^/admin/" || req.url ~ "/paypal/") {
        return (pass);
    }
    
    if (req.http.cookie ~ "wordpress_logged_in_") {
        return (pass);
    }
    
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
            # No point in compressing these
            unset req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } elsif (req.http.Accept-Encoding ~ "deflate" && req.http.user-agent !~ "MSIE") {
            set req.http.Accept-Encoding = "deflate";
        } else {
            # unknown algorithm
            unset req.http.Accept-Encoding;
        }
    }
    
    if (req.url ~ "(\?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+) = ") {
        set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
        set req.url = regsub(req.url, "[?|&]+$", "");
    }
    
    if (req.http.Authorization ~ "^Bearer") {
        return (pass);
    }
    
    return (hash);

}

sub vcl_hash {
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
}

sub vcl_backend_response {

    set beresp.grace = 3d;
    
    if (beresp.http.content-type ~ "text") {
        set beresp.do_esi = true;
    }
    
    if (beresp.http.content-type ~ "text") {
        set beresp.do_gzip = true;
    }
    
    # cache only successfully responses and 404s that are not marked as private
    if (beresp.status != 200 && beresp.status != 404 && beresp.http.Cache-Control ~ "private") {
        set beresp.uncacheable = true;
        set beresp.ttl = 86400s;
        return (deliver);
    }
    
    # validate if we need to cache it and prevent from setting cookie
    if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
        unset beresp.http.set-cookie;
    }

if (!beresp.http.cache-control) {
set beresp.ttl = 0s;
set beresp.uncacheable = true;
}

    return (deliver);

}

sub vcl_deliver {

    set resp.http.X-Cache-Age = resp.http.Age;
    unset resp.http.Age;
    
    # Avoid being cached by the browser.
    if (resp.http.Cache-Control !~ "private") {
      set resp.http.Pragma = "no-cache";
      set resp.http.Expires = "-1";
      set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
    }
    
    unset resp.http.X-Powered-By;
    unset resp.http.Server;
    unset resp.http.X-Varnish;
    unset resp.http.Via;
    unset resp.http.Link;
    unset resp.http.X-Frame-Options;
    unset resp.http.X-Content-Type-Options;
    unset resp.http.X-Xss-Protection;
    unset resp.http.Referer-Policy;
    unset resp.http.X-Permitted-cross-domain-policies;

}

sub vcl_hit {
if (obj.ttl \>= 0s) {
return (deliver);
}
set req.http.grace = "unlimited (unhealthy server)";
return (deliver);
}

include "all-vhosts.vcl";

Nginx Vhost для всех сайтов WordPress

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

server {
listen 8080;
listen \[::\]:8080;
server_name yourdomain.in www1.yourdomain.in;
{{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_param SERVER_PORT 443;
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 yourdomain.in www1.yourdomain.in;
{{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 \~/.git {
deny all;
}

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;
}
}

это работает отлично, как только мы добавим еще один файл vcl для Ghost, мы получим ошибку выборки бэкэнда 503 для Ghost cms (wordpress все еще работает нормально). Ghost работает на порту 3021. лак порт 6081

Призрак Vcl

vcl 4.0;
import std;

backend ghost {
.host = "127.0.0.1";
.port = "3021";
}

acl purge {
"127.0.0.1";
}

# first vcl_recv block handles the cache purging

sub vcl_recv {
set req.backend_hint = ghost;
return (hash);

if (req.url \~ "/rebuild/purge") {
if (client.ip !\~ purge) {
return (synth(405, "Method Not Allowed"));
}
ban("req.http.host == yourdomain.you");
return(synth(200, "Cache cleared"));
}
}

# second vcl_recv block handles the actual caching

sub vcl_recv {
if (req.url \~ "/assets" || req.url \~ "/content/images") {
return (hash);
} else {
return (pass);
}
}

sub vcl_backend_response {
if (bereq.url \~ "/assets" || bereq.url \~ "/content/images") {
set beresp.http.cache-control = "public, max-age=259200";
set beresp.ttl = 3d;
return (deliver);
}
}

sub vcl_deliver {

# nothing here

}

ПРИЗРАК

proxy_cache_path /tmp/nginx_ghost levels=1:2 keys_zone=ghostcache:600m max_size=100m inactive=24h;
server {
listen 80;
listen \[::\]:80;
listen 443 ssl http2;
listen \[::\]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name $yourdomain;
{{root}}

{{nginx_access_log}}
{{nginx_error_log}}

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

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

{{settings}}

index index.html;

location / {
proxy_pass http://127.0.0.1:6081/;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
\# Remove cookies which are useless for anonymous visitor and prevent caching
proxy_ignore_headers Set-Cookie Cache-Control;
proxy_hide_header Set-Cookie;
\# Add header for cache status (miss or hit)
add_header X-Cache-Status $upstream_cache_status;
proxy_cache ghostcache;
\# Default TTL: 1 day
proxy_cache_valid 1d;
\# Cache 404 pages for 1h
proxy_cache_valid 404 1h;
\# use conditional GET requests to refresh the content from origin servers
proxy_cache_revalidate on;
proxy_buffering on;
\# Allows starting a background subrequest to update an expired cache item,
\# while a stale cached response is returned to the client.
proxy_cache_background_update on;
\# Bypass cache for errors
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_pass_request_headers on;
proxy_max_temp_file_size 0;
proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
}

# No cache + keep cookies for admin and previews

location \~ ^/(ghost/|p/) {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://127.0.0.1:{{app_port}};
}

# Bypass ghost for static assets

location ^\~ /assets/ {
root /home/$yourpath/htdocs/$yourpath/content/themes/$yourtheme;
}

# Bypass ghost for original images but not resized ones

location ^\~ /content/images/(!size) {
root /home/$yourpath/htdocs/$yourpath;
}

}

нам нужна помощь в том, как работать с несколькими файлами vcl, когда речь идет о нескольких приложениях. мы пробовали все, но ничего не работает.

Лаковая версия (лак-7.1.1)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть два способа навести порядок:

  1. Используйте метки VCL
  2. Использование включает

этикетки VCL

См. https://varnish-cache.org/docs/trunk/users-guide/vcl-separate.html учебник по меткам VCL.

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

Вот пример реализации:

vcl 4.1;

import std;

# We have to have a backend, even if we do not use it
backend default { .host = "127.0.0.1"; }

sub vcl_recv {
    # Normalize host header
    set req.http.host = std.tolower(req.http.host);

    if (req.http.host ~ "^(www.)?domain.ext$") {
        return (vcl(wordpress));
    }
    if (req.http.host == "ghost.domain.ext") {
        return (vcl(ghost));
    }
    return (synth(302, "http://www.domain.ext"));
}

sub vcl_synth {
    if (resp.status == 301 || resp.status == 302) {
        set resp.http.location = resp.reason;
        set resp.reason = "Moved";
        return (deliver);
    }
}

С помощью следующих команд вы можете загрузить 2 отдельных файла VCL для WordPress и Ghost, одновременно пометив их:

varnishadm vcl.load vc_wordpress /path/to/wordpress.vcl
varnishadm vcl.load vc_ghost /path/to/ghost.vcl
varnishadm vcl.label wordpress vc_wordpress
varnishadm vcl.label ghost vc_ghost

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

Включает в себя

Другой способ сделать это — включить VCL, который буквально вставляет код из файлов включения в заполнители при запуске.

Вот тот же пример, но измененный с включением вместо меток:

vcl 4.1;

import std;

# We have to have a backend, even if we do not use it
backend default { .host = "127.0.0.1"; }

sub vcl_recv {
    # Normalize host header
    set req.http.host = std.tolower(req.http.host);

    if (req.http.host ~ "^(www.)?domain.ext$") {
        include "wordpress.vcl";
    }elseif (req.http.host == "ghost.domain.ext") {
        include "ghost.vcl";
    } else {
        return (synth(302, "http://www.domain.ext"));
    }
}

sub vcl_synth {
    if (resp.status == 301 || resp.status == 302) {
        set resp.http.location = resp.reason;
        set resp.reason = "Moved";
        return (deliver);
    }
}

Что выбрать?

Лично я предпочитаю метки, потому что они обеспечивают лучшую изоляцию между различными конфигурациями VCL.

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

Недостатком является то, что вы должны постоянно следить за тем, чтобы подконфигурации присутствовали. Перезапуск varnishd стирает эти конфигурации.

Чтобы обойти это, укажите параметр времени выполнения -I в varnishd. -I указывает на файл, содержащий команды CLI, которые будут выполняться при запуске. Таким образом, вы можете заполнить свои помеченные подконфигурации без риска их потери после перезапуска.

Использование include намного проще, но обеспечивает меньшую изоляцию.

я преклоняюсь перед тобой. ты для меня Бог. я не знаю, как отблагодарить вас. @thijs-feryn

Happy Home Furniture 29.11.2022 15:23

Другие вопросы по теме