
nodejs 앱과 함께 Stunnel, Varnish 및 nginx를 사용하고 있는데 https가 아닌 페이지를 리디렉션하는 데 문제가 있습니다(http://manager.domain.com)을 해당 https 페이지(https://manager.domain.com). 모든 트래픽이 먼저 바니시를 통과하기 때문에 리디렉션 루프에 갇히게 됩니다. 이 설정의 주된 이유는 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;
}
여기에 광택 구성 파일이 있습니다.
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을 통과했는지 여부를 알 수 없으므로 첫 번째 블록이 승리하고 리디렉션이 항상 발생합니다.
요청이 stunnel에서 왔는지 여부에 따라 Varnish가 리디렉션을 수행하도록 하거나(요청 확인 client.ip
- 127.0.0.1은 stunnel에서 온 것임을 의미함) nginx가 결정할 수 있도록 Varnish가 stunnel의 요청을 헤더로 표시하도록 하는 것이 좋습니다. 어떻게 처리해야 할까요?