繁体   English   中英

如何为包含 WordPress 的多个应用程序和以 nginx 作为代理的 Ghost CMS 配置 Varnish?

[英]How to config Varnish for multiple application containing WordPress and Ghost CMS with nginx as proxy?

我们正在为 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 所有 WordPress 站点的 Vhost

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

一旦我们为 Ghost 添加另一个 vcl 文件,这就完美了,我们得到 ghost cms 的 503 后端获取错误。(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 文件的帮助。 我们已经尝试了一切,但似乎没有任何效果。

清漆版本 (varnish-7.1.1)

有两种方法可以让事情井井有条:

  1. 使用 VCL 标签
  2. 使用包括

VCL标签

有关 VCL 标签的教程,请参阅https://varnish-cache.org/docs/trunk/users-guide/vcl-separate.html

这个想法是将多个 VCL 文件加载到varnishd程序中,并为每个 VCL 文件分配一个 label。 然后是一个主 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);
    }
}

使用以下命令,您可以为 WordPress 和 Ghost 加载 2 个单独的 VCL 文件,同时标记它们:

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 配置,您就可以在单个 Varnish 实例上托管多个网站的 VCL 配置

包括

另一种方法是通过 VCL 包含,它在启动时将包含文件中的代码直接粘贴到占位符中。

这是同一个示例,但使用 include 而不是标签进行了重构:

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会清除这些配置。

一种避免这种情况的方法是在varnishd中指定-I运行时参数。 -I指向包含将在启动时执行的 CLI 命令的文件。 这样您就可以填充标记的子配置,而不会在重启后丢失它们。

使用 include 简单很多,但隔离度较低。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM