AMH-7.1 面板:实战LNGX+Varnish反向代理,提升WordPress网站打开速度

20231103163513387-AMH

AMH是业内不错的主机控制面板软件,在8月份的时候,AMH增加了varnish程序的支持,借助varnish可以显著提升网站的打开速度。但是AMH默认安装的varnish并没有一个比较好的配置,也没有清除缓存的动作。不太合理。

那么今天就来实战一下,以wordpress网站的反代为例,分享一下边缘节点反代+缓存的实战经验。

程序安装

AMH默认安装时,是自带LNMP环境的,但反代则需要另外安装LNGX反向代理环境。

登录AMH-7.1面板后台之后,在右上角找到软件商店,然后在网站环境管理里面安装LNGX。

20231103144756916-WX20231103-144625

然后还需要安装Varnish缓存程序

20231103144946374-WX20231103-144852

AMH环境配置

配置LNGX环境

软件安装成功之后,需要增加反向代理的环境,在软件商店找到LNGX,点击管理

20231103151549132-WX20231103-151455

添加一个lngx01的环境

20231103151744156-WX20231103-151719

配置varnish

这部分没有其他的配置,主要是需要替换varnish的vcl配置文件,可以在下图找到

20231103152347323-WX20231103-152314

用以下内容替换

/*-
 * Copyright (c) 2006 Verdens Gang AS
 * Copyright (c) 2006-2015 Varnish Software AS
 * All rights reserved.
 *
 * Author: Shing Lau <icodex@msn.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This is the builtin VCL code
 */

# We're using unix sockets, so we need to declare that we're using VCL 4.1
vcl 4.1;

# Import Varnish Standard Module so I can serve custom error pages
import std;

import cookie;
import directors;

acl purger {
    "localhost";
    "127.0.0.1";
    "172.17.0.1";
    "10.0.0.0"/8;
}

# Setup the backend
backend backend1 {
    .host = "1.1.1.1"; # `改为源站IP地址`
    .port = "80"; # `改为源站端口`
    .first_byte_timeout = 300s;
    .connect_timeout = 5s;
    .between_bytes_timeout = 5s;
}

#######################################################################
# Client side

# Regex purging
# Treat the request URL as a regular expression.
sub purge_regex {
    ban("obj.http.X-VC-Req-URL ~ " + req.url + " && obj.http.X-VC-Req-Host == " + req.http.host);
}

# Exact purging
# Use the exact request URL (including any query params)
sub purge_exact {
    ban("obj.http.X-VC-Req-URL == " + req.url + " && obj.http.X-VC-Req-Host == " + req.http.host);
}

# Page purging (default)
# Use the exact request URL, but ignore any query params
sub purge_page {
    set req.url = regsub(req.url, "\?.*$", "");
    ban("obj.http.X-VC-Req-URL-Base == " + req.url + " && obj.http.X-VC-Req-Host == " + req.http.host);
}

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

    if (req.http.host ~ "(?i)(.*)") {
        set req.backend_hint = backend1;
    } else {
        return (synth(403, "Hostname not found."));
    }

    if (req.restarts == 0) {
        std.collect(req.http.x-forwarded-for);

        if (req.http.x-forwarded-for) {
            set req.http.x-forwarded-for = regsub(req.http.x-forwarded-for + ", " + client.ip, "\s*,.*$", "");
        } else {
            set req.http.x-forwarded-for = client.ip;
        }
    }

    if (req.http.X-Forwarded-Ssl ~ "(?i)on" ||
        req.http.Cloudfront-Forwarded-Proto ~ "(?i)https" ||
        req.http.X-Forwarded-Proto ~ "(?i)https" ||
        req.http.Proto ~ "(?i)ssl"
        ) {
        set req.http.X-Forwarded-Proto = "https";
        set req.http.X-Forwarded-Port = "443";
    }

    #return (pass);

    if (req.method == "PRI") {
        /* We do not support SPDY or HTTP/2.0 */
        return (synth(405, "We do not support SPDY or HTTP/2.0"));
    }

    if (req.method != "GET" &&
        req.method != "HEAD" &&
        req.method != "PUT" &&
        req.method != "POST" &&
        req.method != "TRACE" &&
        req.method != "OPTIONS" &&
        req.method != "DELETE" &&
        req.method != "PATCH") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }

    # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
    if (req.http.upgrade ~ "(?i)websocket") {
        return (pipe);
    }

    # We only deal with GET and HEAD by default
    if (req.method != "GET" && req.method != "HEAD") {
        /* We only deal with GET and HEAD by default */
        set req.http.X-VC-Cacheable = "NO:Request method:" + req.method;
        return (pass);
    }

    # Set initial grace period usage status
    set req.http.grace = "none";

    set req.hash_ignore_busy = true;

    # Normalize the header, remove the port (in case you're testing this on various TCP ports)
    set req.http.Host = regsub(req.http.host, ":[0-9]+", "");

    # Normalize the query arguments
    set req.url = std.querysort(regsub(req.url, "^http[s]?://", ""));

    # collect all cookies
    std.collect(req.http.Cookie);

    if (req.http.Range ~ "bytes=") {
        set req.http.x-range = req.http.Range;
    }

    # Strip hash, server doesn't need it.
    if (req.url ~ "\#") {
        set req.url = regsub(req.url, "\#.*$", "");
    }

    # Strip a trailing ? if it exists
    if (req.url ~ "\?$") {
        set req.url = regsub(req.url, "\?$", "");
    }

    # remove ?xxx=xxxxx strings from urls so css and js files are cached.
    set req.url = regsub(req.url, "\.js\?.*$", ".js");
    set req.url = regsub(req.url, "\.css\?.*$", ".css");

    set req.url = regsub(req.url, "\?ver=.*$", "");
    set req.url = regsub(req.url, "\?replytocom=.*$", "");

    if (req.http.Authorization ||
        req.http.Authenticate ||
        req.http.WWW-Authenticate) {
        /* Not cacheable by default */
        set req.http.X-VC-Cacheable = "NO:Requested with: Authenticate";
        # set req.hash_always_miss = true;
        return (pass);
    }

    # # don't cache logged-in users. you can set users `logged in cookie` name in settings
    # if (req.http.Cookie) {
    #     set req.http.X-VC-Cacheable = "NO:Found logged in cookie";
    #     # set req.hash_always_miss = true;
    #     return (pass);
    # }

    # don't cache XMLHttpRequest
    if (req.http.X-Requested-With == "XMLHttpRequest") {
        set req.http.X-VC-Cacheable = "NO:Requested with: XMLHttpRequest";
        # set req.hash_always_miss = true;
        return (pass);
    }

    if (req.http.Cache-Control && req.http.Cache-Control ~ "(?i)private") {
        set req.http.X-VC-Cacheable = "NO:Private Use";
        # set req.hash_always_miss = true;
        return (pass);
    }

    if (req.url ~ "^[^?]*\.(?i)(asp|aspx|ashx|php|php4|php5|cgi|pl|perl|jsp|do)(\?.*)?$" || req.url ~ "\?nocache") {
        set req.http.X-VC-Cacheable = "NO:Pass through the dynamic request";
        # set req.hash_always_miss = true;
        return (pass);
    }

    # don't cache ajax request
    if (req.url ~ "^.*/ajax/.*$" || req.url ~ "^.*/ahah/.*$") {
        set req.http.X-VC-Cacheable = "NO:Requested with: Ajax";
        return (pass);
    }

    if (req.url ~ "^/admin/" || req.url ~ "/paypal/") {
        set req.http.X-VC-Cacheable = "NO:Requested with: manager area";
        return (pass);
    }

    if ( req.url ~ "(?i)(phpmyadmin|status|munin|server-status|nocache|feed|get|ip)" ||
      req.url ~ "(?i)(sitemap.xml($|\.gz$))" ) {
        set req.http.X-VC-Cacheable = "NO:Pass through the known exclude";
        set req.hash_always_miss = true;
        return (pass);
    }

    # don't cache logged-in users. you can set users `logged in cookie` name in settings
    if (req.http.Cookie ~ "(?i)(wp-postpass_|wordpress_logged_in_|comment_author)") {
        set req.http.X-VC-Cacheable = "NO:Found logged in cookie";
        # set req.hash_always_miss = true;
        return (pass);
    }

    # don't cache these special pages
    if (req.url ~ "(?i)(nocache|wp-admin|wp-(json|comments-post|login|activate|mail)\.php|bb-admin|server-status|control\.php|bb-login\.php|bb-reset-password\.php|register\.php)") {
        set req.http.X-VC-Cacheable = "NO:Special page: " + req.url;
        # set req.hash_always_miss = true;
        return (pass);
    }

    # Pass through the WooCommerce dynamic pages
    if (req.url ~ "^/(cart|my-account/*|checkout|wc-api/*|addons|logout|lost-password|product/*)") {
        set req.http.X-VC-Cacheable = "NO:Pass through the WooCommerce dynamic pages";
        # set req.hash_always_miss = true;
        return (pass);
    }
    # Pass through the WooCommerce add to cart
    if (req.url ~ "\?add-to-cart=" ) {
        set req.http.X-VC-Cacheable = "NO:Pass through the WooCommerce add to cart";
        # set req.hash_always_miss = true;
        return (pass);
    }
    # Pass through the WooCommerce API
    if (req.url ~ "\?wc-api=" ) {
        set req.http.X-VC-Cacheable = "NO:Pass through the WooCommerce API";
        # set req.hash_always_miss = true;
        return (pass);
    }

    if (req.url ~ "^[^?]*\.(?i)(xmlrpc.php|wlmanifest.xml)(\?.*)?$") {
        # unset cookie only if no http auth
        if (!req.http.Authorization) {
            unset req.http.Cookie;
        }
        return (pass);
    }

    if (req.http.Accept-Encoding) {
        # Do no compress compressed files...
        if (req.url ~ "^[^?]*\.(?i)(jpg|jpeg|webp|png|gif|bmp|gz|tgz|bz2|tbz|lzma|mp3|ogg|swf|ico)(\?.*)?$") {
            # 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, "[?|&]+$", "");
    }

    # Remove all cookies for static files
    # A valid discussion could be held on this line: do you really need to cache static files that don't cause load? Only if you have memory left.
    # Sure, there's disk I/O, but chances are your OS will already have these files in their buffers (thus memory).
    # Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
    if (req.method ~ "^(GET|HEAD)$" &&
        (req.http.Content-Type ~ "(?i)(octet-stream|audio|video)" ||
        req.url ~ "^[^?]*\.(?i)(bmp|css|csv|doc|docx|eot|gif|ico|jpeg|jpg|js|less|pdf|png|ppt|pptx|rtf|svg|svgz|swf|ttf|txt|webp|woff|woff2|xls|xlsx|xml|avi|flac|flv|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|wav|webm|7z|bz2|gz|rar|tar|tgz|tbz|txz|xz|zip)(\?.*)?$")) {
        # enable this if you need it
        if (req.url ~ "nocache") {
            set req.http.X-VC-Cacheable = "NO:Not cacheable, nocache in URL";
            return (pass);
        }
        # unset cookie only if no http auth
        if (!req.http.Authorization) {
            unset req.http.Cookie;
        }
    }

    # Send Surrogate-Capability headers to announce ESI support to backend
    set req.http.Surrogate-Capability = "key=ESI/1.0";

    set req.http.X-VC-My-Purge-Key = "";
    if (req.method == "PURGE" || req.method == "SOFTPURGE" || req.method == "BAN") {
        if (req.http.X-VC-Purge-Key == req.http.X-VC-My-Purge-Key) {
            set req.http.X-VC-Purge-Key-Auth = "true";
        } else {
            set req.http.X-VC-Purge-Key-Auth = "false";
        }
        if (client.ip !~ purger && req.http.X-VC-Purge-Key-Auth != "true") {
#            return (synth(405, "Not allowed from " + client.ip));
        }

        if (req.http.X-VC-Purge-Method) {
            if (req.http.X-VC-Purge-Method ~ "(?i)regex") {
                call purge_regex;
            } elsif (req.http.X-VC-Purge-Method ~ "(?i)exact") {
                call purge_exact;
            } else {
                call purge_page;
            }
        } else {
            # No X-VC-Purge-Method header was specified.
            # Do our best to figure out which one they want.
            if (req.url ~ "\.\*" || req.url ~ "^\^" || req.url ~ "\$$" || req.url ~ "\\[.?*+^$|()]") {
                call purge_regex;
            } elsif (req.url ~ "\?") {
                call purge_exact;
            } else {
                call purge_page;
            }
        }

        if (req.method == "BAN") {
            ban("obj.http.X-URL ~ " + req.http.X-Ban);
            /* Throw a synthetic page so the request won't go to the backend. */
            return(synth(200, "Ban added"));
        } else {
            # If you got this stage (and didn't error out above), purge the cached result
            return (purge);
        }

        return (synth(200,"Purged " + req.url + " " + req.http.host));
    }
    unset req.http.X-VC-My-Purge-Key;
    # unset Varnish Caching custom headers from client
    #unset req.http.X-VC-Cacheable;
    #unset req.http.X-VC-Debug;

    return (hash);
}

sub vcl_hash {
    hash_data(req.url);
    if (req.http.x-range ~ "bytes=") {
        hash_data(req.http.x-range);
        unset req.http.Range;
    }

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

sub vcl_backend_response {
    set beresp.grace = 3d;
    set beresp.http.X-VC-Req-Host = bereq.http.host;
    set beresp.http.X-VC-Req-URL = bereq.url;
    set beresp.http.X-VC-Req-URL-Base = regsub(bereq.url, "\?.*$", "");

    if (bereq.http.x-range ~ "bytes=" && beresp.status == 206) {
        set beresp.ttl = 10m;
        set beresp.http.CR = beresp.http.content-range;
    }

    if (beresp.http.Surrogate-Control) {
        set beresp.ttl = std.duration(regsub(beresp.http.Surrogate-Control,"^.*max-age=(\d+).*$","\1"),  beresp.ttl);
        set beresp.grace = std.duration(regsub(beresp.http.Surrogate-Control,"^.*max-age=\d+\+(\d+).*$","\1"),beresp.grace);
    }

    if (beresp.http.Vary ~ "User-Agent") {
        set beresp.http.Vary = regsub(beresp.http.Vary, ",? *User-Agent *", "");
        set beresp.http.Vary = regsub(beresp.http.Vary, "^, *", "");
        if (beresp.http.Vary == "") {
            unset beresp.http.Vary;
        }
    }

    # Varnish determined the object is not cacheable
    if (beresp.http.Authorization ||
        beresp.http.Authenticate ||
        beresp.http.WWW-Authenticate ||
        beresp.http.X-Requested-With == "(?i)XMLHttpRequest") {
        set beresp.http.X-VC-Cacheable = "NO: Authenticate ";
        set beresp.uncacheable = true;
        set beresp.http.magicmarker = 1;
        # overwrite ttl with X-VC-TTL
        set beresp.http.X-VC-TTL = 0;
        set beresp.ttl = 0s;
    }

    if (beresp.http.Pragma ~ "(?i)no-cache" ||
        (!beresp.http.Surrogate-Control && beresp.http.Cache-Control ~ "(?i)no-cache|no-store|private")) {
        set beresp.http.Smug-Cacheable = "No";
        set beresp.http.magicmarker = "1";
    }

    if (beresp.http.Set-Cookie && beresp.http.Set-Cookie !~ "(?i)(wp-postpass_|wordpress_logged_in_|comment_author|PHPSESSID)") {
        set beresp.http.X-VC-Cacheable = "NO: !obj.Set-Cookie";
        set beresp.ttl = 0s;
        set beresp.http.Smug-Cacheable = "No";
        set beresp.http.magicmarker = "1";
        set beresp.uncacheable = true;
    }

    # Pause ESI request and remove Surrogate-Control header
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        set beresp.do_gunzip = true;
        set beresp.do_esi = true;
    }

    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.http.X-VC-Cacheable = "NO: Private Use";
        set beresp.uncacheable = true;
        set beresp.http.magicmarker = 1;
        # overwrite ttl with X-VC-TTL
        set beresp.http.X-VC-TTL = 0;
        set beresp.ttl = 0s;
    }

    if (beresp.status == 301 || beresp.status == 302) {
        set beresp.http.X-VC-Cacheable = "YES: but for 10s - Status : " + beresp.status;
        set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", "");
        unset beresp.http.Server;
        # overwrite ttl with X-VC-TTL
        set beresp.http.X-VC-TTL = 10;
    }

    if (beresp.status == 403 || beresp.status == 404) {
        set beresp.http.X-VC-Cacheable = "YES: but for 30s - Status : " + beresp.status;
        set beresp.grace = 15s;
        # overwrite ttl with X-VC-TTL
        set beresp.http.X-VC-TTL = 15;
    }

    if (beresp.status >= 500 && beresp.status < 600 && bereq.retries < 5) {
        if (bereq.method != "POST") {
            set beresp.http.X-VC-Cacheable = "NO: Status : " + beresp.status;
            set beresp.ttl = 0s;
            set beresp.grace = 15s;
            # return (abandon);
        }
    }

    if (beresp.status >= 200 && beresp.status < 300 && bereq.method ~ "^(GET|HEAD)$") {
        if (bereq.url ~ "^[^?]*\.(?i)(bmp|css|csv|doc|docx|eot|gif|ico|jpeg|jpg|js|less|pdf|png|ppt|pptx|rtf|svg|svgz|swf|ttf|txt|webp|woff|woff2|xls|xlsx|xml)(\?.*)?$") {
            unset beresp.http.Set-Cookie;
            # overwrite ttl with X-VC-TTL
            set beresp.http.X-VC-TTL = 24*60*60*7;
        }

        if (beresp.http.Content-Type ~ "(?i)(html|xml)") {
            set beresp.do_gzip = true;
            set beresp.do_esi = true;
            # overwrite ttl with X-VC-TTL
            set beresp.http.X-VC-TTL = 60*60;
        } elsif (beresp.http.Content-Type ~ "(?i)(css|javascript)" ||
            beresp.http.Content-Type ~ "(?i)application/(x-)?javascript" ||
            beresp.http.Content-Type ~ "(?i)application/(x-)?font-ttf" ||
            beresp.http.Content-Type ~ "(?i)application/(x-)?font-opentype" ||
            beresp.http.Content-Type ~ "(?i)application/font-woff" ||
            beresp.http.Content-Type ~ "(?i)application/vnd\.ms-fontobject" ||
            beresp.http.Content-Type ~ "(?i)image/svg\+xml") {
            set beresp.do_gzip = true;
            # overwrite ttl with X-VC-TTL
            set beresp.http.X-VC-TTL = 24*60*60*7;
        }

        # Large static files are delivered directly to the end-user without
        # waiting for Varnish to fully read the file first.
        # Varnish 4 fully supports Streaming, so use streaming here to avoid locking.
        if (beresp.http.Content-Type ~ "(?i)(octet-stream|audio|video)" ||
            bereq.url ~ "^[^?]*\.(?i)(avi|flac|flv|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|wav|webm)(\?.*)?$") {
            unset beresp.http.Set-Cookie;
            # the backend doesn't send a Content-Length header, so only enable it for big objects
            set beresp.do_gzip = false; # Don't try to compress it for storage
            # Stream large objects, <= 128 MiB
            if (std.integer(beresp.http.Content-Length,0) <= 134217728) {
                set beresp.do_stream = true;  # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if
                # overwrite ttl with X-VC-TTL
                set beresp.http.X-VC-TTL = 60*60;
            # do not cache files > 128 MiB
            } elsif (std.integer(beresp.http.Content-Length,0) > 134217728) {
                set beresp.http.X-VC-Cacheable = "NO:Large static files";
                set beresp.uncacheable = true;
                set beresp.http.magicmarker = 1;
                # overwrite ttl with X-VC-TTL
                set beresp.http.X-VC-TTL = 0;
                set beresp.ttl = 0s;
            }
        }
    }

    # Don't cache object as instructed by header bereq.X-VC-Cacheable
    if (bereq.http.X-VC-Cacheable ~ "^NO") {
        set beresp.http.X-VC-Cacheable = bereq.http.X-VC-Cacheable;
        set beresp.uncacheable = true;
        # overwrite ttl with X-VC-TTL
        set beresp.http.X-VC-TTL = 0;
        set beresp.ttl = 0s;
    }

    # 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.X-VC-Enabled ~ "true") {
        if (!beresp.http.X-VC-Cacheable) {
            set beresp.http.X-VC-Cacheable = "YES: Is cacheable, ttl: " + std.duration(beresp.http.X-VC-TTL + "s", 0s);
        }
    } elseif (beresp.http.X-VC-Enabled ~ "false") {
        if (!beresp.http.X-VC-Cacheable) {
            set beresp.http.X-VC-Cacheable = "NO:Disabled";
        }
        set beresp.http.X-VC-TTL = 0;
    }

    # All tests passed, therefore item is cacheable
    # set beresp.http.X-VC-Cacheable = "YES: Is cacheable, ttl: " + std.duration(beresp.http.X-VC-TTL + "s", 0s);

    # overwrite ttl with X-VC-TTL
    if (beresp.http.X-VC-TTL) {
        set beresp.ttl = std.duration(beresp.http.X-VC-TTL + "s", 0s);
    }

    # 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;
    set resp.http.X-Cache-Alive = regsub(obj.ttl, "^(\d+).[0-9]+", "\1");
    unset resp.http.Age;

    if (resp.http.CR) {
        set resp.http.Content-Range = resp.http.CR;
        unset resp.http.CR;
    }

    # From http://varnish-cache.org/wiki/VCLExampleLongerCaching
    if (resp.http.magicmarker) {
        /* Remove the magic marker */
        unset resp.http.magicmarker;

        /* By definition we have a fresh object */
        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-VC-Req-Host;
    unset resp.http.X-VC-Req-URL;
    unset resp.http.X-VC-Req-URL-Base;

    if (obj.hits > 0) {
        set resp.http.X-VC-Cache = "HIT";
    } else {
        set resp.http.X-VC-Cache = "MISS";
    }

    if (req.http.X-VC-Debug ~ "true" || resp.http.X-VC-Debug ~ "true") {
        set resp.http.X-VC-Hash = req.http.hash;
        if (req.http.X-VC-DebugMessage) {
            set resp.http.X-VC-DebugMessage = req.http.X-VC-DebugMessage;
        }
    } else {
        unset resp.http.X-VC-Enabled;
        unset resp.http.X-VC-Cache;
        unset resp.http.X-VC-Debug;
        unset resp.http.X-VC-DebugMessage;
        unset resp.http.X-VC-Cacheable;
        unset resp.http.X-VC-Purge-Key-Auth;
        unset resp.http.X-VC-TTL;
    }

    # Change some headers
    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;
    unset resp.http.X-Drupal-Cache;
    unset resp.http.X-Page-Speed;
    unset resp.http.X-AspNet-Version;
    unset resp.http.X-Generator;
    unset resp.http.X-Via;

    if (obj.hits > 0) {
        set resp.http.X-Cache-Remote = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
        set resp.http.X-Cache-Remote = "MISS";
    }

    set resp.http.X-Cache-Lookup = "Lookup From Disktank";

    # HTTP headers for all sites
    set resp.http.X-Are-Dinosaurs-Awesome = "HELL YES";
    set resp.http.X-Hack = "don't hack me bro";

    return (deliver);
}

sub vcl_backend_fetch {
    if (bereq.method == "GET") {
        unset bereq.body;
    }

    std.collect(bereq.http.x-forwarded-for);

    if (bereq.http.x-range) {
        set bereq.http.Range = bereq.http.x-range;
    }

    if (bereq.http.x-forwarded-for) {
        set bereq.http.x-forwarded-for = regsub(bereq.http.x-forwarded-for + ", " + client.ip, "\s*,.*$", "");
    } else {
        set bereq.http.x-forwarded-for = client.ip;
    }

    return (fetch);
}


sub vcl_purge {
    # Only handle actual PURGE HTTP methods, everything else is discarded
    if (req.method != "PURGE") {
        # restart request
        set req.http.X-Purge = "Yes";
        return (restart);
    }
}

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

实战WordPress Varnish反向代理

以本站作为反代案例,源站在欧洲某国,国内访问则通过CN2GIA的VPS作为边缘节点,现在就在这台VPS上安装AMH做反代,在完成以上所有配置之后,开始以下配置

一、首先切换到LNGX反代环境

20231103153418587-WX20231103-153345

二、添加反代网站

20231103153655468-WX20231103-153642

缓存是用varnish做的,因此后端监听地址这里务必填http://127.0.0.1:6081,这个是varnish的监听地址。所以记得要取消LNGX自带的缓存(Cache)。

20231103154007127-WX20231103-153942

三、配置varnish

在上面的后端地址已经指定了用varnish做缓存,所以真正的后端地址的配置就需要在varnish上做配置了,找到varnish的配置,在backend部分指定源站IP和端口:

...

# Setup the backend
backend backend1 {
    .host = "1.1.1.1"; # `改为源站IP地址`
    .port = "80"; # `改为源站端口`
    .first_byte_timeout = 300s;
    .connect_timeout = 5s;
    .between_bytes_timeout = 5s;
}

backend backend2 {
    .host = "1.1.1.1"; # `改为源站IP地址`
    .port = "80"; # `改为源站端口`
    .first_byte_timeout = 300s;
    .connect_timeout = 5s;
    .between_bytes_timeout = 5s;
}

...

sub vcl_recv {
    ...

    if (req.http.host ~ "(?i)(^((.*).)?evlit.com)") {
        set req.backend_hint = backend1;
    } elseif (req.http.host ~ "(?i)(^((.*).)?other.domain.com)") {
        set req.backend_hint = backend2;
    } else {
        return (synth(403, "Hostname not found."));
    }

    ...
}

以上配置中的backend1是本例的配置关键,backend2则是配置其他域名的。

完成以上配置之后,配置好本机hosts之后,就可以访问了。

但WordPress访问仍然是有问题的,https和http会反复横跳。继续往下看⬇️

四、WordPress配置

打开wp-config.php,在第二行添加配置:

if ((isset($_ENV["HTTPS"]) && ("on" == $_ENV["HTTPS"]))
  || (isset($_SERVER["HTTP_X_FORWARDED_SSL"]) && (strpos($_SERVER["HTTP_X_FORWARDED_SSL"], "1") !== false))
  || (isset($_SERVER["HTTP_X_FORWARDED_SSL"]) && (strpos($_SERVER["HTTP_X_FORWARDED_SSL"], "on") !== false))
  || (isset($_SERVER["HTTP_CF_VISITOR"]) && (strpos($_SERVER["HTTP_CF_VISITOR"], "https") !== false))
  || (isset($_SERVER["HTTP_CLOUDFRONT_FORWARDED_PROTO"]) && (strpos($_SERVER["HTTP_CLOUDFRONT_FORWARDED_PROTO"], "https") !== false))
  || (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && (strpos($_SERVER["HTTP_X_FORWARDED_PROTO"], "https") !== false))
  || (isset($_SERVER["HTTP_X_PROTO"]) && (strpos($_SERVER["HTTP_X_PROTO"], "SSL") !== false))
) {
  $_SERVER["HTTPS"] = "on";
}

五、WordPress插件管理缓存

前面提到缓存,如果缓存不能被管理,那么这个缓存就没什么意义。需要到WordPress后台插件搜索varnish,然后找到 Purge Varnish Cache 安装就好。

20231103160602357-WX20231103-160511

安装后激活,然后需要进行配置

20231103161115992-WX20231103-161102

配置主要有两个地方,Varnish Control Terminal是一个varnish的API管理接口,varnish默认监听的是本地回环地址127.0.0.1:6082,但在本例中需要改为公网监听地址。

首先在AMH的varnish的启动参数里面,将127.0.0.1地址改为0.0.0.0,这样就可以在公网访问这个高位端口了

20231103160859603-WX20231103-160815

Varnish Control Key则是作为API管理接口的鉴权密钥,可以在linux终端里查看到varnish的启动命令行里找到

20231103161825546-WX20231103-161811

这串4f043f13c9891ae61e6f2d2eb就是密钥了,将它填到wordpress插件里就好了。

最后

AMH默认其实也有缓存的,我没实际测试,主要是我一直以来习惯使用varnish做边缘节点的缓存工具,而且搭配wordpress插件,也可以很方便地刷新缓存,其他的配置,比如发帖自动刷新varnish的缓存,可以直接保持默认就好。

当然,现在你也可以测试一下了。?

20231103162547515-WX20231103-162409

© 版权声明
THE END
喜欢就支持一下吧
点赞16 分享