转自:https://www.kancloud.cn/zouhongzhao/magento2-in-action/647798

注意:这篇文章讲的是varnish和ssl同时存在的情况,比较复杂。如果你只需要配置ssl,不需要varnish的话,请参考
https://bbs.mallol.cn/thread-622.htm

配置Varnish

注意:Varnish默认只支持http(80)端口,不支持https(443),若要支持https(443),必须配置Nginx反向代理才能生效

当然你可以不用Varnish,只配置SSL 也可以。

以下操作在/var/www/magento2-live项目下执行。
请自行更改你的项目路径和URL。
没有SSL证书的去 https://freessl.cn/ 免费申请

参考:
https://devdocs.magento.com/guides/v2.3/config-guide/varnish/config-varnish-install.html?itm_source=devdocs&itm_medium=search_page&itm_campaign=federated_search&itm_term=varnish

M2后台启用Varnish缓存

从你的Magento管理仪表板上点击 STORES button (leftside) > Configuration > ADVANCED > System > Full Page Cache

取消选择使用系统值并从缓存应用程序列表中选择Varnish Cache (Recommended),保存配置,单击Varnish Configuration链接并单击Export VCL for Varnish 4按钮。

我们下载保存这个varnish.vcl范例文件,备用。

最后,使用以下命令刷新Magento缓存:

cd /var/www/magento2-live
php bin/magento cache:flush

完成后,你可以继续配置Varnish。

服务器安装并配置Varnish

确保安装在你的服务器上的所有软件包都是最新的

sudo apt-get update && sudo apt-get upgrade

Varnish在官方Ubuntu 16.04版本库中提供,所以我们可以使用apt-get命令轻松安装它:

sudo apt-get install varnish

一旦安装完成,我们将配置Varnish在端口80上侦听,并使用将在端口8080上监听的Nginx Web服务器作为后端。

输入以下命令编辑Varnish缓存文件并创建一个新的配置文件/etc/systemd/system/varnish.service.d/

sudo mkdir -p /etc/systemd/system/varnish.service.d
sudo systemctl edit varnish.service

添加/追加下列配置选项:
将Varnish端口6082更改为HTTP端口80。

[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :80 -T localhost:6082 -p thread_pools=4 -p thread_pool_max=1500 -p connect_timeout=300 -p listen_depth=512 -p http_resp_hdr_len=65536 -p http_resp_size=98304 -p workspace_backend=98304 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,1024m

并重新加载systemd单元

sudo systemctl daemon-reload

接下来,编辑默认的Varnish vcl文件

sudo vim /etc/varnish/default.vcl

把刚才下载的varnish.vcl范例文件代码复制进去。

配置文件内容如下:

vcl 4.0;

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

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

acl purge {
    "127.0.0.1";
}

sub vcl_recv {
    if (req.url ~ "(jpg|jpeg|png|gif|tiff|bmp)$") {
        return (pipe);
    }
    if (req.method == "PURGE") {
        if (client.ip !~ purge) {
            return (synth(405, "Method not allowed"));
        }
        if (!req.http.X-Magento-Tags-Pattern) {
            return (synth(400, "X-Magento-Tags-Pattern header required"));
        }
        ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
        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);
    }

    # 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 {
            # unkown algorithm
            unset req.http.Accept-Encoding;
        }
    }

    # Remove Google gclid parameters to minimize the cache objects
    set req.url = regsuball(req.url,"\?gclid=[^&]+$",""); # strips when QS = "?gclid=AAA"
    set req.url = regsuball(req.url,"\?gclid=[^&]+&","?"); # strips when QS = "?gclid=AAA&foo=bar"
    set req.url = regsuball(req.url,"&gclid=[^&]+",""); # strips when QS = "?foo=bar&gclid=AAA" or QS = "?foo=bar&gclid=AAA&bar=baz"

    # static files are always cacheable. remove SSL flag and cookie
        if (req.url ~ "^/(pub/)?(media|static)/.*\.(ico|css|js|jpg|jpeg|png|gif|tiff|bmp|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)$") {
        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);
    }

}

sub vcl_backend_response {
    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;
    }

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

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

    # validate if we need to cache it and prevent from setting cookie
    # images, css and js are cacheable by default so we have to remove cookie also
    if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
        unset beresp.http.set-cookie;
        if (bereq.url !~ "\.(ico|css|js|jpg|jpeg|png|gif|tiff|bmp|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)(\?|$)") {
            set beresp.http.Pragma = "no-cache";
            set beresp.http.Expires = "-1";
            set beresp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
            set beresp.grace = 1m;
        }
    }

   # 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.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";
        } else {
            set resp.http.X-Magento-Cache-Debug = "MISS";
        }
    } else {
        unset resp.http.Age;
    }

    unset resp.http.X-Magento-Debug;
    unset resp.http.X-Magento-Tags;
    unset resp.http.X-Powered-By;
    unset resp.http.Server;
    unset resp.http.X-Varnish;
    unset resp.http.Via;
    unset resp.http.Link;
}

保存更改并重新启动Varnish以使更改生效

sudo systemctl restart varnish

配置Nginx SSL

将Web服务器配置为侦听除默认端口80以外的端口(例如:8080),因为Varnish直接响应传入的HTTP请求,而不是Web服务器。为此,在'server'块中添加'listen'指令,如下所示:

sudo nano /etc/nginx/sites-enabled/magento2-live

将侦听端口更改为8080,并启用Nginx SSL HTTP2,
打开Nginx配置文件并将其更改如下:

upstream fastcgi_backend {
  server   unix:/run/php/php7.0-fpm.sock;
}

server {
    server_name yourdomain.com www.yourdomain.com;
    listen 8080;
    set $MAGE_ROOT /var/www/magento2-live;
    set $MAGE_MODE production; # or developer

    access_log /var/log/nginx/magento2-access.log;
    error_log /var/log/nginx/magento2-error.log;

    include /var/www/magento2-live/nginx.conf.sample;        
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate /etc/nginx/ssl/magento2/ssl-cert-snakeoil.pem; # change with your SSL cert
    ssl_certificate_key /etc/nginx/ssl/magento2/ssl-cert-snakeoil.key; # change with your SSL key
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers               'AES128+EECDH:AES128+EDH:!aNULL';
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout 24h;
    keepalive_timeout 300s;

    location / {
        proxy_pass http://127.0.0.1;
        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_set_header Ssl-Offloaded "1";
        proxy_set_header      X-Forwarded-Proto https;
        proxy_set_header      X-Forwarded-Port 443;
        #proxy_hide_header X-Varnish;
        #proxy_hide_header Via;
        proxy_set_header X-Forwarded-Proto $scheme;

    }

}

如果您还没有SSL证书,则可以去购买可信SSL证书。

/etc/nginx/sites-enabled/default文件中也进行相同的更改(把listen 80改成listen 8080)。

测试Nginx配置

通过执行以下命令保存更改并测试Nginx配置

sudo nginx -t

输出应该看起来像这样

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新启动Varnish和Nginx

最后,重新启动Nginx以使更改生效

sudo systemctl restart nginx
sudo systemctl restart varnish

验证

我假设你已经遵循了上述所有步骤(安装和配置)。现在让我们来检查Varnish缓存服务器是否考虑了HTTP响应。

检查Varnish状态

systemctl status varnish

检查Varnish是否正在侦听端口80,运行以下命令

netstat -tulpn | grep varnishd

验证HTTP响应头,您可以简单地使用CLI:

注意:必须在开发者模式下才能看到HTTP响应标题
https://devdocs.magento.com/guides/v2.3/config-guide/varnish/config-varnish-final.html

curl -I -v --location-trusted 'http://www.yourdomain.com/'

应该会看到这些重要的标题

X-Magento-Cache-Control: max-age=86400, public, s-maxage=86400
Age: 0
X-Magento-Cache-Debug: MISS

将基础URL更改为https并刷新缓存

php bin/magento setup:store-config:set --use-secure=1 --use-secure-admin=1 --base-url-secure="https://www.yourdomain.com/"
php bin/magento cache:flush

要对Magento Admin和店面都使用安全套接字层(SSL)(也称为HTTPS),你必须设置以下所有参数:

--use-secure:设置为1
--base-url-secure:设置为安全的URL(即以https://开头)
--use-secure-admin:设置为1

如果现在一切正常,你应该可以通过https://www.yourdomain.com/adminlogin
登录到你的Magento后端。

现在,一旦你在浏览器中访问你的网站,它应该通过Varnish来提供服务。
就是这样。
你已经用Varnish和Nginx成功配置了Magento。
你的Magento网站现在应该会明显更快。

测试

如果有问题的话,
先清下m2的varnish缓存:

php bin/magento cache:flush full_page

或者后台清缓存

click SYSTEM > Tools > Cache Management, then click Flush Magento Cache.

清除varnish缓存:

sudo systemctl restart varnish

再更新下系统:

php bin/magento maintenance:enable && git pull origin master

rm -rf var/di/* && rm -rf var/generation/* && rm -rf var/cache/* && rm -rf var/page_cache/* && rm -rf var/view_preprocessed/* && rm -rf pub/static/* && rm -rf generated/* && mkdir var/di

php bin/magento setup:upgrade && php bin/magento setup:di:compile

php bin/magento setup:static-content:deploy -f && php bin/magento indexer:reindex && php bin/magento maintenance:disable && php bin/magento cache:clean && php bin/magento cache:flush

总结

这一章比较绕,其实大致流程如下:

1,访客打开网站

如果是通过SSL(https,一般是443端口)访问,请求会转到Nginx。Nginx再把请求转给Varnish。
如果是通过非SSL(http,一般是80端口)访问,请求会转到Varnish,被重定向到SSL URL

2,Varnish接收

Varnish收到请求后,会检查请求是否有缓存,
有缓存的话 会将缓存的数据传递给Nginx。
没有缓存的话 就请求Magento2获取数据,再缓存后 返回给Nginx。

3,数据传递给Nginx

一旦Varnish有回应,它将被传递回Nginx,以便它可以传递给访问者。
因为Varnish不直接支持SSL。
这就是Nginx需要站在中间的原因,所以它可以通过SSL将响应传递给访问者。

4,向访问者提供数据

一旦Nginx有响应数据,它通过SSL安全地将数据传递给访问者。因为Varnish不能直接用于安全的SSL响应。

参考文章

关于其他系统(Centos/Red Hat/Debian)下的Varnish配置,可以参考下面这篇文章:
https://docs.varnish-software.com/tutorials/configuring-systemd-services/

相关问题

1,重启nginx警告*hash_max_size,*hash_bucket_size

Starting nginx: nginx: [warn] could not build optimal proxy_headers_hash, you should increase either proxy_headers_hash_max_size: 512 or proxy_headers_hash_bucket_size: 64; ignoring proxy_headers_hash_bucket_size
nginx: [warn] could not build optimal proxy_headers_hash, you should increase either proxy_headers_hash_max_size: 512 or proxy_headers_hash_bucket_size: 64; ignoring proxy_headers_hash_bucket_size
nginx: [warn] could not build optimal proxy_headers_hash, you should increase either proxy_headers_hash_max_size: 512 or proxy_headers_hash_bucket_size: 64; ignoring proxy_headers_hash_bucket_size

解决办法:
编辑vim /etc/nginx/nginx.conf,在http里面增加

proxy_headers_hash_max_size 51200;
proxy_headers_hash_bucket_size 6400;

2,不管怎么操作,总是出现503 backend fetch failed

这是magento2的一个bug,还未修复。
2.2.x版本有问题。老版本有些是好的。
https://github.com/magento/magento2/issues/11692

如果是用的直接从后台导出的Varnish配置文件,可能会有问题。
直接用我的varnish.vcl范例文件代码试试。

3,Cannot open socket: :80: Address already in use

先查看是哪个进程占用的80端口,一般是nginx

sudo netstat -nlpt

找到进程号后,杀死这个进程

sudo kill 进程号 -9

如果是nginx占用80端口的话,你还需要改nginx虚拟主机配置文件。/etc/nginx/sites-enabled/下面的所有主机配置文件。
listen 80都改成listen 8080
最后再重启nginx

ssl下的多网店vhost配置

store view多网店多域名为例:

upstream fastcgi_backend {
        server  unix:/run/php/php7.0-fpm.sock;
}
map $http_host $MAGE_RUN_CODE {
    magento2demo.texiaoyao.cn default;
    magento2demo-zh.texiaoyao.cn cn;
}
server {
        listen 8080;
        server_name magento2demo.texiaoyao.cn;
        set $MAGE_ROOT /var/www/magento2-live;
        set $MAGE_MODE production;
        set $MAGE_RUN_TYPE store;
        include /var/www/magento2-live/nginx.conf.sample;
        error_log /var/log/magento2-live/nginx/error.log;
}
server {
        listen 8080;
        server_name magento2demo-zh.texiaoyao.cn;
        set $MAGE_ROOT /var/www/magento2-live;
        set $MAGE_MODE production;
        set $MAGE_RUN_TYPE store;
        include /var/www/magento2-live/nginx.conf.sample;
        error_log /var/log/magento2-live/nginx/error.log;
}

server {
    listen 443 ssl http2;
    server_name magento2demo.texiaoyao.cn magento2demo-zh.texiaoyao.cn;
    ssl_certificate /usr/local/nginx/conf/ssl/magento2demo.texiaoyao.cn.crt;
    ssl_certificate_key /usr/local/nginx/conf/ssl/magento2demo.texiaoyao.cn.key;
    ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers               'AES128+EECDH:AES128+EDH:!aNULL';
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout 24h;
    keepalive_timeout 300s;
    location / {
        proxy_pass http://127.0.0.1;
        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_set_header Ssl-Offloaded "1";
        proxy_set_header      X-Forwarded-Proto https;
        proxy_set_header      X-Forwarded-Port 443;
        #proxy_hide_header X-Varnish;
        #proxy_hide_header Via;
        proxy_connect_timeout 1800s;
        proxy_read_timeout 1800s;
        proxy_send_timeout 1800s;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

强制HTTPS

1) 只有SSL,没安装Varnish的情况下

Nginx配置文件

server
{
    listen 80;
   listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;
    index index.php index.html index.htm default.php default.htm default.html;
    set $MAGE_ROOT /var/www/magento2-live/;
    set $MAGE_MODE production;
    set $MAGE_RUN_TYPE store;
    include /var/www/magento2-live/nginx.conf.sample; 
    #SSL-START 
    #error_page 404/404.html;
    #HTTP_TO_HTTPS_START
    if ($server_port !~ 443){
        rewrite ^(/.*)$ https://$host$1 permanent;
    }
    #HTTP_TO_HTTPS_END
    ssl_certificate /etc/nginx/ssl/magento2/ssl-cert-snakeoil.pem; #change with your SSL cert
    ssl_certificate_key /etc/nginx/ssl/magento2/ssl-cert-snakeoil.key; # change with your SSL key
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    #SSL-END

}

2) SSL和Varnish同时存在的情况下

需要改下 vim /etc/varnish/default.vcl,添加几行代码

sub vcl_recv {
    if (client.ip != "127.0.0.1" && req.http.host ~ "^(?i)www.domain.com" && req.http.X-Forwarded-Proto !~ "(?i)https") {
       return (synth(750, ""));
    }
    ....
}
sub vcl_synth {
    if (resp.status == 750) {
        set resp.status = 301;
        set resp.http.Location = "https://www.domain.com" + req.url;
        return(deliver);
    }
}

还需要修改下Nginx配置文件

server {
  listen  8080;
  listen  [::]:8080;
  server_name  yourdomain.com;
  return       301 https://www.yourdomain.com$request_uri;
}
server {
    server_name www.yourdomain.com;
    listen 8080;
    listen [::]:8080;
    #HTTP_TO_HTTPS_START
    #HTTP_TO_HTTPS_END
    set $MAGE_ROOT /var/www/www.yourdomain.com;
    set $MAGE_MODE production; # or developer
    #access_log /var/log/domains/www.yourdomain.com/nginx/access.log;
    error_log /var/log/domains/www.yourdomain.com/nginx/error.log;
    include /var/www/www.yourdomain.com/nginx.conf.sample;
}

然后M2的web/unsecure/base_url也要改成https,跟web/secure/base_url一样