步骤 1:确保 HAProxy 发送 X-Forwarded-Proto 标头

步骤 1:确保 HAProxy 发送 X-Forwarded-Proto 标头

在家里,我有 1 台托管服务器,上面有一些网站,使用 Virtualmin(很棒的工具!),一切都运行良好,HTTPS、HTTP……甚至在我的互联网路由器后面,使用 NAT 通过将端口 80 和 443 转发到我的网络服务器。

客户端 443/HTTPS -> 我的互联网路由器 NAT -> 80/HTTP 或 443/HTTPS Apache

我通过在 Apache 前面添加负载平衡器 HA 代理来进行一些改进:运行良好。

客户端 443/HTTPS -> 我的互联网路由器 NAT ->HA 代理 443/HTTPS SSL 终止-> 82/HTTP 或 442/HTTPS Apache (192.168.0.40)

这意味着我的网站仍然可以通过 HTTPS 协议访问,但端口为 442

我甚至添加了 keepalived 并且它运行良好:

客户端 443/HTTPS -> 我的互联网路由器 NAT ->保留 IP 地址-> HA 代理 443/HTTPS SSL 终止 -> 82/HTTP 或 442/HTTPS Apache

现在,我想添加 Web 缓存 Varnish。您可能知道,Varnish 的免费版本不支持 HTTPS。这对我来说不是问题,因为我有处理 SSL 终止的 HA Proxy。我想要做的是将 Varnish 设置在 HA Proxy 后面和 Apache 前面。

客户端 443/HTTPS -> 我的互联网路由器 NAT -> KEEPALIVED IP 地址 -> HA 代理 443/HTTPS SSL 终止 ->清漆 81/HTTP-> 82/HTTP 或 442/HTTPS Apache

但它不起作用...例如,当我尝试使用 HTTPS 访问我的网站时https://myexemple.com,主页已加载,但所有其他静态文件均未加载...查看页面网络检查器(在浏览器中按 F12),我可以看到这些静态文件是使用 HTTP 提供的(参见附加的屏幕截图)。

在此处输入图片描述

仅为本网站安装了 wordpress,没有其他任何内容。

是否有人遇到过类似的问题,或者可能成功实现了像我这样的架构模式:

客户端 443/HTTPS -> KEEPALIVED IP 地址 -> HA 代理 443/HTTPS SSL 终止 ->清漆 81/HTTP-> 82/HTTP 或 442/HTTPS Apache

一般来说,使用 Varnish 时如何处理 HTTPS?特别是使用 Wordpress 时:在后端,我们必须指定网站的 URL(即https://kmx.ovh就我而言)?谢谢

好吧,我尝试在 HA Proxy 后面和 Apache 网站前面设置 Varnish,请参阅以下配置:

这是我的 HA Proxy 的配置(非常简单):

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
        tune.ssl.default-dh-param 4096

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option redispatch
        maxconn 2000
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

frontend http
        description "HTTP handler"
        bind *:80
        mode http
        option httplog
        option http-keep-alive

        maxconn 500

        acl ACL_is_acme_challenge path_beg /.well-known/acme-challenge/

        acl ACL_allowed_ip src 192.168.0.0/24

        http-request allow if ACL_is_acme_challenge
        http-request allow if ACL_allowed_ip

        use_backend be_default

frontend https
        description "SSL Endpoint!"
        bind *:443 ssl crt /etc/haproxy/cert/
        mode http
        option httplog

        acl tls req.ssl_hello_type 1

        option http-server-close
        http-request capture req.hdr(X-Forwarded-Proto) len 10
        http-request add-header X-Forwarded-Proto %[capture.req.hdr(0)]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }

        option forwardfor except 127.0.0.1

        use_backend bes_default

backend be_default
        description 'Forward to Apache HTTP backend'
        mode http
        option forwardfor
        balance roundrobin
        server 37-81 192.168.0.37:81 maxconn 250 check

backend bes_default
        description 'Forward to Apache HTTPS backend'
        mode http
        option forwardfor
        balance roundrobin

        server 37-81 192.168.0.37:81 maxconn 250 check

下面是我的 Varnish 配置文件(非常简单……):

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide for a comprehensive documentation
# at https://www.varnish-cache.org/docs/.

# Marker to tell the VCL compiler that this VCL has been written with the
# 4.0 or 4.1 syntax.
vcl 4.1;

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "192.168.0.37";
    .port = "82";
}

backend tmp-kiminox-net {
    .host = "tmp.kiminox.net";
    .port = "82";
}

backend kmx-ovh {
    .host = "kmx.ovh";
    .port = "82";
}

sub vcl_recv {
    # Happens before we check if we have this in cache already.
    #
    # Typically you clean up the request here, removing cookies you don't need,
    # rewriting the request, etc.

    if (req.http.host == "tmp.kiminox.net") {
        #You will need the following line only if your backend has multiple virtual host names
        set req.http.host = "tmp.kiminox.net";
        set req.backend_hint = tmp-kiminox-net;
        return (pipe);
    }

    if (req.http.host ~ "kmx.ovh") {
        set req.http.Host = req.http.host;
        set req.backend_hint = kmx-ovh;
        return (pipe);
    }
}

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
    set beresp.http.X-Cache2 = "via Varnish cache 37";
}

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }

}

sub vcl_hash {
    if(req.http.X-Forwarded-Proto) {
        hash_data(req.http.X-Forwarded-Proto);
    }
}

Varnish 服务:

[Unit]
Description=Varnish Cache, a high-performance HTTP accelerator
Documentation=https://www.varnish-cache.org/docs/ man:varnishd

[Service]
Type=simple

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

# Locked shared memory - should suffice to lock the shared memory log
# (varnishd -l argument)
# Default log size is 80MB vsl + 1M vsm + header -> 82MB
# unit is bytes
LimitMEMLOCK=85983232
ExecStart=/usr/sbin/varnishd \
          -j unix,user=vcache \
          -F \
          -a :81 \
          -T localhost:6082 \
          -f /etc/varnish/default.vcl \
          -S /etc/varnish/secret \
          -s malloc,256m
ExecReload=/usr/share/varnish/varnishreload
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
PrivateDevices=true

[Install]
WantedBy=multi-user.target

答案1

步骤 1:确保 HAProxy 发送 X-Forwarded-Proto 标头

正如所提到的https://stackoverflow.com/questions/77885246/client-443-https-virtual-ip-ha-proxy-80-http-and-443-https-ssl-terminaison/77885399?noredirect=1#comment137311196_77885399您也问了这个问题,我建议您首先在 HAProxy 后端配置中添加以下标头:

http-request add-header X-Forwarded-Proto https if { ssl_fc }

第 2 步:让 WordPress 理解 X-Forwarded-Proto

现在我知道您正在使用 WordPress,您必须告知 WordPress 有关X-Forwarded-Proto标题的信息,因为它不支持开箱即用的功能。

正如所提到的https://www.varnish-software.com/developers/tutorials/mixed-content-err-too-many-redirects-wordpress-varnish/#checking-the-x-forwarded-proto-header-in-wordpress,将以下代码添加到您的wp-config.php

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 
    strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
    $_SERVER['HTTPS'] = 'on';
}

步骤 3:根据 X-Forwarded-Proto 标头创建缓存变体

为了确保 Varnish 在不同的缓存对象中缓存 HTTPS 和 HTTP 响应,您必须更改vcl_hash子例程并添加X-Forwarded-Proto变体。

以下是实现该功能的代码:

sub vcl_hash {
    if(req.http.X-Forwarded-Proto) {
        hash_data(req.http.X-Forwarded-Proto);
    }
}

但是,为了确保 Varnish 中的缓存正确,你应该使用专门的 VCL 文件。我建议你阅读https://www.varnishsoftware.com/developers/tutorials/configuring-varnish-wordpress/并使用该 VCL 代码以及清除插件。

相关内容