web-dev-qa-db-ja.com

node.jsアプリをVarnish / Nginxサーバーにデプロイするための最良の方法

新しいnode.jsアプリケーションをデプロイしようとしていますが、これを設定するためのサポートが必要です。

私の現在の設定は次のとおりです。

external_ip:80でVarnishを実行しています

Nginxをinternal_ip:80で実行しています

どちらもポート80、1つの内部ポート、1つの外部でリッスンしています。

注:node.jsアプリはWebSocketsで実行されます

これで、ポート8080でリッスンする新しいnode.jsアプリケーションができました。

Nginxとnode.jsの両方の前にニスを設定できますか?.

VarnishはWebSocketをポート8080にプロキシする必要がありますが、css、jsなどの静的ファイルはポート80を経由してnignxに移動する必要があります。

Nginxは、すぐに使用できるWebSocketをサポートしていません。それ以外の場合は、次のような設定を行います。

ニス-> nignx-> node.js

5
Saif Bechan

あなたが説明したものと本質的に同じプロジェクトをセットアップしたので、私のアプローチを共有します-それが「最高」であるという保証はありませんが、それは機能します。

私のサーバースタックは

  • ワニス(v3.0.2)-すべてのインターフェース、ポート80
  • Nginx(v1.0.14)-ローカルインターフェイス、ポート81
  • Node.js(v0.6.13)-ローカルインターフェース、ポート1337
  • オペレーティングシステムはCentOS 6.2(または同様のもの)

私のNode.jsアプリはWebsocket(sockets.io-v0.9.0)とExpress(v2.5.8)を使用しており、永久に使用して起動されます。 (同じサーバーには他のサイトもあります-主にPHP NginxとVarnishの同じインスタンスを使用します)。

私のアプローチの基本的な意図は次のとおりです。

  • WebSocketと「通常の」データの両方の単一のパブリックポート/アドレス
  • ワニスを使用して一部のアセットをキャッシュする
  • (キャッシュされていない)静的アセットをnginxから直接提供する
  • 'Webページ'のリクエストをnginxに渡し、プロキシからNode.jsに渡します
  • Webソケットリクエストを直接(Varnishから)Node.jsに渡します(nginxをバイパスします)。

ワニス設定-/ etc/varnish/default.vcl:

#Nginx - on port 81
backend default {
  .Host = "127.0.0.1";
  .port = "81";
  .connect_timeout = 5s;
  .first_byte_timeout = 30s;
  .between_bytes_timeout = 60s;
  .max_connections = 800;
}
#Node.js - on port 1337
backend nodejs{
  .Host = "127.0.0.1";
  .port = "1337";
  .connect_timeout = 1s;
  .first_byte_timeout = 2s;
  .between_bytes_timeout = 60s;
  .max_connections = 800;
}

sub vcl_recv {
    set req.backend = default;

    #Keeping the IP addresses correct for my logs
    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, if included, to normalize Host
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    #Part of the standard Varnish 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") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }

    #Taken from the Varnish help on dealing with Websockets - pipe directly to Node.js
    if (req.http.Upgrade ~ "(?i)websocket") {
        set req.backend = nodejs;
        return (pipe);
    }

    ###Removed some cookie manipulation and compression settings##


    if(req.http.Host ~"^(www\.)?example.com"){
            #Removed some redirects and Host normalization
            #Requests made to this path, even if XHR polling still benefit from piping - pass does not seem to work
        if (req.url ~ "^/socket.io/") {
            set req.backend = nodejs;
            return (pipe);
        }

    #I have a bunch of other sites which get included here, each in its own block
    }elseif (req.http.Host ~ "^(www\.)?othersite.tld"){
        #...
    }

 #Part of the standard Varnish config
 if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }

    #Everything else, lookup
    return (lookup);
}


sub vcl_pipe {
    #Need to copy the upgrade for websockets to work
    if (req.http.upgrade) {
        set bereq.http.upgrade = req.http.upgrade;
    }
    set bereq.http.Connection = "close";
    return (pipe);
 }
 #All other functions should be fine unmodified (for basic functionality - most of mine are altered to my purposes; I find that adding a grace period, in particular, helps.

Nginx設定-/etc/nginx/*/example.com.conf:

server {
    listen *:81;
    server_name example.com www.example.com static.example.com;
    root /var/www/example.com/web;
    error_log /var/log/nginx/example.com/error.log info;
    access_log /var/log/nginx/example.com/access.log timed;

    #removed error page setup

    #home page
    location = / {
        proxy_pass http://node_js;
    }

    #everything else
    location / {
        try_files $uri $uri/ @proxy;
    }
    location @proxy{
        proxy_pass http://node_js;
    }

    #removed some standard settings I use
}

upstream node_js {
    server 127.0.0.1:1337;
    server 127.0.0.1:1337;
}

私はproxy_passステートメントの繰り返しに特に夢中ではありませんが、残念ながら、まだよりクリーンな代替手段を見つけることに慣れていません。 1つのアプローチは、静的ファイル拡張子を明示的に指定するロケーションブロックを持ち、proxy_passステートメントをロケーションブロックの外に残すことです。

/etc/nginx/nginx.confからのいくつかの設定:

set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;

log_format  timed  '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                   '"$http_user_agent" "$http_x_forwarded_for" '
                   '$request_time $upstream_response_time $pipe';

port_in_redirect off;

他のサーバーブロックと設定の中で、nginx構成でgzipとキープアライブも有効にしています。 (余談ですが、TCP WebSocketの使用を可能にするTCP $ ===モジュールがあると思いますが、私は「バニラ」バージョンのソフトウェア(および関連するリポジトリ)を使用するのが好きなので、それは私にとって本当に選択肢ではありませんでした)。

このセットアップの以前のバージョンでは、ワニスのパイピングで異常な「ブロッキング」動作が発生していました。基本的に、パイプソケット接続が確立されると、次の要求はパイプがタイムアウトするまで(最大60秒)遅延します。この設定で同じ再発はまだ見ていませんが、同様の動作が見られるかどうかを知りたいと思います。

10
cyberx86