使用 Varnish 和 nginx 时重定向非 https 流量

使用 Varnish 和 nginx 时重定向非 https 流量

我在 nodejs 应用程序中使用了 Stunnel、Varnish 和 nginx,但在重定向非 https 页面时遇到了问题(http://manager.domain.com)到其各自的 https 页面(https://manager.domain.com)。我只是陷入了重定向循环,因为所有流量都首先经过 varnish。这种设置的主要原因是使用带有 ssl 的套接字。

Stunnel 监听端口 443。它终止 SSL 连接并将流量传递到端口 80 上的 Varnish。Varnish 监听端口 80,并根据需要在端口 81 上的 Nginx 和端口 3000 上的 Node.js 之间拆分其他流量。Nginx 监听端口 81。它提供静态文件和其他非 Node.js 页面。

这是 nginx conf 文件

upstream nodejs {
    server 127.0.0.1:3000;
    server 127.0.0.1:3000;
}

server {
    listen 81;
    server_name www.domain.net;
    rewrite ^(.*) http://domain.com$1 permanent;

}

server {
    listen 81;
    server_name manager.domain.com;
    rewrite ^(.*) https://manager.domain.com$1 permanent;

}

server {
    listen 81;
    server_name domain.com manager.domain.com help.domain.com;

    access_log /srv/www/domain.com/logs/access.log timed;
    error_log /srv/www/domain.com/logs/error.log info;
    root /srv/www/domain.com/public;

    #everything else
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass http://nodejs/;
        proxy_redirect off;


    }



    gzip on;
    gzip_comp_level 6;
    gzip_proxied any;
    gzip_min_length  1000;
    gzip_disable     "MSIE [1-6]\."
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}

这是 varnish 的配置文件

backend default {
    .host = "127.0.0.1";
    .port = "81";
    .connect_timeout = 5s;
    .first_byte_timeout = 30s;
    .between_bytes_timeout = 60s;
    .max_connections = 800;
}

backend nodejs {
    .host = "127.0.0.1";
    .port = "3000";
    .connect_timeout = 1s;
    .first_byte_timeout = 2s;
    .between_bytes_timeout = 60s;
    .max_connections = 800;
}

sub vcl_recv {
    set req.backend = default;
    set req.grace = 120s;

    #set the correct IP so my backends don’t log all requests as coming from Varnish
    if (req.restarts == 0) {
        if (req.http.x-forwarded-for) {
            set req.http.X-Forwarded-For =
            req.http.X-Forwarded-For + ", " + client.ip;
        } else {
            set req.http.X-Forwarded-For = client.ip;
        }
    }

    #remove port, so that hostname is normalized
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    #Removed: code for purging

    #part of Varnish’s default config
    if (req.request != "GET" &&
        req.request != "HEAD" &&
        req.request != "PUT" &&
        req.request != "POST" &&
        req.request != "TRACE" &&
        req.request != "OPTIONS" &&
        req.request != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }
    if (req.request != "GET" && req.request != "HEAD") {
        return (pass);
    }

    #pipe websocket connections directly to Node.js
    if (req.http.Upgrade ~ "(?i)websocket") {
        set req.backend = nodejs;
        return (pipe);
    }

    #do not cache large static files
    if (req.url ~ "\.(avi|flv|mp(e?)g|mp4|mp3|gz|tgz|bz2|tbz|ogg)$") {
        return(pass);
    }

    #general URL manipulation and cookie removal
    #lines 60-109 from https://github.com/mattiasgeniar/varnish-3.0-configuration-templates/blob/d86d6c1d7d3d0ddaf92019dd5ef5ce66c9e53700/default.vcl

    if(req.http.Host ~"^(www\.)?domain.com"){
        #Removed: Redirect for URL normalization using error 701
        # Requests made to this path, relate to websockets - pass does not seem to work (even for XHR polling)
        if (req.url ~ "^/socket.io/") {
            set req.backend = nodejs;
            return (pipe);
        }
    #My other PHP/MySQL sites get included here, each in its own block
    }

    # part of Varnish’s default config
    if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }
    return (lookup);
}

sub vcl_pipe {
    #we need to copy the upgrade header
    if (req.http.upgrade) {
        set bereq.http.upgrade = req.http.upgrade;
    }
    #closing the connection is necessary for some applications – I haven’t had any issues with websockets keeping the line below uncommented
    #set bereq.http.Connection = "close";
     return (pipe);
}






sub vcl_pass {
     return (pass);
}

 sub vcl_hash {
     hash_data(req.url);
     if (req.http.host) {
         hash_data(req.http.host);
     } else {
         hash_data(server.ip);
     }
     return (hash);
 }

 sub vcl_hit {
     return (deliver);
 }

 sub vcl_miss {
     return (fetch);
 }

 sub vcl_fetch {
     if (beresp.ttl <= 0s ||
         beresp.http.Set-Cookie ||
         beresp.http.Vary == "*") {
        /*
         * Mark as "Hit-For-Pass" for the next 2 minutes
         */
        set beresp.ttl = 120 s;
        return (hit_for_pass);
     }
     return (deliver);
 }

 sub vcl_deliver {
     return (deliver);
 }

 sub vcl_error {
     set obj.http.Content-Type = "text/html; charset=utf-8";
     set obj.http.Retry-After = "5";
     synthetic {"
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
   <head>
     <title>"} + obj.status + " " + obj.response + {"</title>
   </head>
   <body>
     <h1>Error "} + obj.status + " " + obj.response + {"</h1>
     <p>"} + obj.response + {"</p>
     <h3>Guru Meditation:</h3>
     <p>XID: "} + req.xid + {"</p>
     <hr>
     <p>Varnish cache server</p>
   </body>
 </html>
 "};
     return (deliver);
 }

 sub vcl_init {
    return (ok);
}

 sub vcl_fini {
    return (ok);
 }

答案1

server在端口 81 上有两个manager.domain.com配置为主机头的块 - nginx 无法知道请求是否通过 stunnel,因此第一个块获胜并且重定向始终发生。

我建议让 Varnish 根据请求是否来自 stunnel 进行重定向(检查请求client.ip- 127.0.0.1 表示它来自 stunnel),或者让 Varnish 使用标头标记来自 stunnel 的请求,以便 nginx 可以决定如何处理它们。

相关内容