Apache-2.2

無法讓 Varnish 在 HTTPS 上工作

  • October 31, 2020

我已經與 Apache 一起設置了 Varnish,我沒有使用 Hitch 或 Pound,只是一個帶有 Apache mods 的簡單代理配置。

Apache 監聽 8080

我的清漆配置:

# Configuration file for varnish
#
# /etc/init.d/varnish expects the variables $DAEMON_OPTS, $NFILES and $MEMLOCK
# to be set from this shell script fragment.
#
# Note: If systemd is installed, this file is obsolete and ignored.  Please see 
# /usr/share/doc/varnish/examples/varnish.systemd-drop-in.conf

# Should we start varnishd at boot?  Set to "no" to disable.
START=yes

# Maximum number of open files (for ulimit -n)
NFILES=131072

# Maximum locked memory size (for ulimit -l)
# Used for locking the shared memory log in memory.  If you increase log size,
# you need to increase this number as well
MEMLOCK=82000

# Default varnish instance name is the local nodename.  Can be overridden with
# the -n switch, to have more instances on a single server.
# You may need to uncomment this variable for alternatives 1 and 3 below.
# INSTANCE=$(uname -n)

# This file contains 4 alternatives, please use only one.

## Alternative 1, Minimal configuration, no VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# content server on localhost:8080.  Use a 1GB fixed-size cache file.
#
# This example uses the INSTANCE variable above, which you need to uncomment.
#
# DAEMON_OPTS="-a :80 \
#        -T localhost:6082 \
#        -b localhost:8080 \
#        -u varnish -g varnish \
#        -S /etc/varnish/secret \
#        -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"

f
## Alternative 2, Configuration with VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# one content server selected by the vcl file, based on the request.
#
DAEMON_OPTS="-a :80 \
            -T localhost:6082 \
            -f /etc/varnish/default.vcl \
            -S /etc/varnish/secret \
            -s malloc,256m"


## Alternative 3, Advanced configuration
#
# This example uses the INSTANCE variable above, which you need to uncomment.
#
# See varnishd(1) for more information.
#
# # Main configuration file. You probably want to change it :)
# VARNISH_VCL_CONF=/etc/varnish/default.vcl
#
# # Default address and port to bind to
# # Blank address means all IPv4 and IPv6 interfaces, otherwise specify
# # a host name, an IPv4 dotted quad, or an IPv6 address in brackets.
# VARNISH_LISTEN_ADDRESS=
VARNISH_LISTEN_PORT=80
#
# # Telnet admin interface listen address and port
# VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
# VARNISH_ADMIN_LISTEN_PORT=6082
#
# # Cache file location
# VARNISH_STORAGE_FILE=/var/lib/varnish/$INSTANCE/varnish_storage.bin
#
# # Cache file size: in bytes, optionally using k / M / G / T suffix,
# # or in percentage of available disk space using the % suffix.
# VARNISH_STORAGE_SIZE=1G
#
# # File containing administration secret
# VARNISH_SECRET_FILE=/etc/varnish/secret
# 
# # Backend storage specification
# VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"
#
# # Default TTL used when the backend does not specify one
# VARNISH_TTL=120
#
# # DAEMON_OPTS is used by the init script.  If you add or remove options, make
# # sure you update this section, too.
# DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
#              -f ${VARNISH_VCL_CONF} \
#              -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
#              -t ${VARNISH_TTL} \
#          -S ${VARNISH_SECRET_FILE} \
#              -s ${VARNISH_STORAGE}"
#


## Alternative 4, Do It Yourself
#
# DAEMON_OPTS=""

DAEMON_OPTS="-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m"

預設.vcl

# VCL version 5.0 is not supported so it should be 4.0 even though actually used Varnish version is 5
vcl 4.0;

import std;
# The minimal Varnish version is 5.0
# For SSL offloading, pass the following header in your proxy server or load balancer: 'X-Forwarded-Proto: https'

backend default {
   .host = "localhost";
   .port = "8080";
}

acl purge {
   "localhost";
}

sub vcl_recv {
   if (req.method == "PURGE") {
       if (client.ip !~ purge) {
           return (synth(405, "Method not allowed"));
       }
       # To use the X-Pool header for purging varnish during automated deployments, make sure the X-Pool header
       # has been added to the response in your backend server config. This is used, for example, by the
       # capistrano-magento2 gem for purging old content from varnish during it's deploy routine.
       if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
           return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required"));
       }
       if (req.http.X-Magento-Tags-Pattern) {
         ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
       }
       if (req.http.X-Pool) {
         ban("obj.http.X-Pool ~ " + req.http.X-Pool);
       }
       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);
   }

   # Bypass shopping cart, checkout and search requests
   if (req.url ~ "/checkout" || req.url ~ "/catalogsearch") {
       return (pass);
   }

   # Bypass health check requests
   if (req.url ~ "/pub/health_check.php") {
       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);

   # Compression filter. See https://www.varnish-cache.org/trac/wiki/FAQ/Compression
   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;
       }
   }

   # Remove all marketing get parameters to minimize the cache objects
   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, "[?|&]+$", "");
   }

   # Static files caching
   if (req.url ~ "^/(pub/)?(media|static)/") {
       # Static files should not be cached by default
       return (pass);

       # But if you use a few locales and don't use CDN you can enable caching static files by commenting previous line (#return (pass);) and uncommenting next 3 lines
       #unset req.http.Https;
       #unset req.http.X-Forwarded-Proto;
       #unset req.http.Cookie;
   }

   return (hash);
}

sub vcl_hash {
   if (req.http.cookie ~ "X-Magento-Vary=") {
       hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
   }

   # For multi site configurations to not cache each other's content
   if (req.http.host) {
       hash_data(req.http.host);
   } else {
       hash_data(server.ip);
   }

                              
                                    
    

   # To make sure http users don't see ssl warning
   if (req.http.X-Forwarded-Proto) {
       hash_data(req.http.X-Forwarded-Proto);
   }
   

   if (req.url ~ "/graphql") {
       call process_graphql_headers;
   }
}

sub process_graphql_headers {
   if (req.http.Store) {
       hash_data(req.http.Store);
   }
   if (req.http.Content-Currency) {
       hash_data(req.http.Content-Currency);
   }
}

sub vcl_backend_response {

   set beresp.grace = 3d;

   if (beresp.http.content-type ~ "text") {
       set beresp.do_esi = true;
   }

   if (bereq.url ~ "\.js$" || beresp.http.content-type ~ "text") {
       set beresp.do_gzip = true;
   }

   if (beresp.http.X-Magento-Debug) {
       set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
   }

   # cache only successfully responses and 404s
   if (beresp.status != 200 && beresp.status != 404) {
       set beresp.ttl = 0s;
       set beresp.uncacheable = true;
       return (deliver);
   } elsif (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 page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass
  if (beresp.ttl <= 0s ||
      beresp.http.Surrogate-control ~ "no-store" ||
      (!beresp.http.Surrogate-Control &&
      beresp.http.Cache-Control ~ "no-cache|no-store") ||
      beresp.http.Vary == "*") {
       # Mark as Hit-For-Pass for the next 2 minutes
       set beresp.ttl = 120s;
       set beresp.uncacheable = true;
   }

   return (deliver);
}

sub vcl_deliver {
   if (resp.http.X-Magento-Debug) {
       if (resp.http.x-varnish ~ " ") {
           set resp.http.X-Magento-Cache-Debug = "HIT";
           set resp.http.Grace = req.http.grace;
       } else {
           set resp.http.X-Magento-Cache-Debug = "MISS";
       }
   } else {
       unset resp.http.Age;
   }

   # Not letting browser to cache non-static files.
   if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
       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.Via;
   unset resp.http.Link;
}

sub vcl_hit {
   if (obj.ttl >= 0s) {
       # Hit within TTL period
       return (deliver);
   }
   if (std.healthy(req.backend_hint)) {
       if (obj.ttl + 300s > 0s) {
           # Hit after TTL expiration, but within grace period
           set req.http.grace = "normal (healthy server)";
           return (deliver);
       } else {
           # Hit after TTL and grace expiration
           return (miss);
       }
   } else {
       # server is not healthy, retrieve from cache
       set req.http.grace = "unlimited (unhealthy server)";
       return (deliver);
   }
}

我正在使用此配置(https 之一)將請求代理回 Varnish:

# Sample LAMP virtual host file from Vultr. The default Apache conf files are located in /var/default-conf/apache2

<IfModule mod_ssl.c>
   <VirtualHost _default_:443>
   
       <Directory /var/www/html/>
           Options Indexes FollowSymLinks
           AllowOverride All
           Require all granted
       </Directory>

       <Files ".ht*">
           Require all denied
       </Files>

       #ServerAdmin webmaster@example.com
       #ServerName host.example.com
       RequestHeader set X-Forwarded-Proto "https"

       DocumentRoot /var/www/html
       
       SetEnvIf Request_URI "^/favicon\.ico$" dontlog
       SetEnvIf Request_URI "^/robots\.txt$" dontlog

       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined
       
       DirectoryIndex index.php index.html

       SSLEngine on
       SSLCertificateFile      /etc/apache2/ssl/server.crt
       SSLCertificateKeyFile   /etc/apache2/ssl/server.key

       ProxyPreserveHost On
       ProxyPass / http://127.0.0.1:80/
       ProxyPassReverse / http://127.0.0.1:80/
       # Ubuntu default: Enable StdEnvVars
       <FilesMatch "\.(cgi|shtml|phtml|php)$">
               SSLOptions +StdEnvVars
       </FilesMatch>
       <Directory /usr/lib/cgi-bin>
               SSLOptions +StdEnvVars
       </Directory>

   </VirtualHost>
</IfModule>

這是預設的 apache http 配置:

# Sample LAMP virtual host file from Vultr. The default Apache conf files are located in /var/default-conf/apache2

<VirtualHost *:8080>

   <Directory /var/www/html/>
       Options Indexes FollowSymLinks
       AllowOverride All
       Require all granted
   </Directory>

   <Files ".ht*">
       Require all denied
   </Files>
   
   ServerAdmin test@gmail.com
   ServerName melamstyles.com

   DocumentRoot /var/www/html
   
   SetEnvIf Request_URI "^/favicon\.ico$" dontlog
   SetEnvIf Request_URI "^/robots\.txt$" dontlog
   
   ErrorLog ${APACHE_LOG_DIR}/error.log
   CustomLog ${APACHE_LOG_DIR}/access.log combined
   
   DirectoryIndex index.php index.html
RewriteEngine on
RewriteCond %{SERVER_NAME} =melamstyles.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

我苦苦掙扎了好幾天,無法讓它工作,嘗試了 Hitch 但沒有用,我也在使用帶有 HTTPS 模式的 Cloudflare。

當我使用埠 80 捲曲到 IP 時,我找到了 Varnish 標頭,但除此之外,什麼也沒有。

我通過讓 Apache 專門監聽 Varnish 監聽的 IP 來解決這個問題,即 127.0.0.1:8080 而不僅僅是埠。

引用自:https://serverfault.com/questions/1034462