Nginx può essere utilizzato come proxy inverso per un server WebSocket di back-end?

Stiamo lavorando a un’app Ruby on Rails che ha bisogno di sfruttare i websocket html5. Al momento, abbiamo due “server” separati per intenderci: la nostra app principale in esecuzione su nginx + passenger e un server separato che utilizza il framework Cramp di Pratik Naik (che funziona su Thin ) per gestire le connessioni websocket.

Idealmente, quando arriverà il momento della distribuzione, avremo l’app per i binari in esecuzione su nginx + passenger, e il server websocket sarà sottoposto a proxy dietro nginx, quindi non avremmo bisogno di avere il server websocket in esecuzione su una porta diversa.

Il problema è che in questa configurazione sembra che nginx stia chiudendo troppo presto le connessioni a Thin. La connessione viene stabilita con successo sul server Thin, quindi immediatamente chiusa con un codice di risposta di 200. La nostra ipotesi è che nginx non si rende conto che il client sta tentando di stabilire una connessione di lunga durata per il traffico websocket.

Devo ammettere che non sono molto esperto con nginx config, quindi è ansible configurare nginx come proxy inverso per un server websocket? O devo aspettare che nginx offra supporto per la nuova roba di handshake websocket? Supponendo che avere sia l’app server che il server websocket in ascolto sulla porta 80 sia un requisito, potrebbe significare che devo avere Thin in esecuzione su un server separato senza nginx in primo piano per ora?

Grazie in anticipo per qualsiasi consiglio o suggerimento. 🙂

-John

Al momento non puoi usare nginx per questo [non è più vero] , ma ti suggerisco di guardare HAProxy. L’ho usato esattamente per questo scopo.

Il trucco è impostare lunghi timeout in modo che le connessioni socket non siano chiuse. Qualcosa di simile a:

timeout client 86400000 # In the frontend timeout server 86400000 # In the backend 

Se si vuole servire dire un’applicazione di rails e cramp sulla stessa porta, è ansible utilizzare le regole ACL per rilevare una connessione websocket e utilizzare un back-end diverso. Quindi la tua configurazione di frontend haProxy sarebbe simile a qualcosa

 frontend all 0.0.0.0:80 timeout client 86400000 default_backend rails_backend acl websocket hdr(Upgrade) -i WebSocket use_backend cramp_backend if websocket 

Per completezza dovrebbe apparire il backend

 backend cramp_backend timeout server 86400000 server cramp1 localhost:8090 maxconn 200 check 

Che ne dici di utilizzare il mio modulo nginx_tcp_proxy_module ?

Questo modulo è progettato per il proxy TCP generale con Nginx. Penso che sia adatto anche per websocket. E aggiungo tcp_ssl_module nel ramo di sviluppo.

nginx (> = 1.3.13) ora supporta le web socket socket proxy.

 # the upstream server doesn't need a prefix! # no need for wss:// or http:// because nginx will upgrade to http1.1 in the config below upstream app_server { server localhost:3000; } server { # ... location / { proxy_pass http://app_server; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_redirect off; } } 

Fuori dalla scatola (es. Fonti ufficiali) Nginx può stabilire solo connessioni HTTP 1.0 ad un upstream (= backend), il che significa che non è ansible alcun keepalive: Nginx selezionerà un server upstream, connessione aperta ad esso, proxy, cache (se vuoi ) e chiudi la connessione. Questo è tutto.

Questo è il motivo fondamentale per cui framework che richiedono connessioni persistenti al backend non funzionerebbero con Nginx (nessun HTTP / 1.1 = nessun keepalive e nessun websocket credo). Nonostante abbia questo svantaggio, c’è un evidente vantaggio: Nginx può scegliere tra diversi upstream (bilanciamento del carico) e il failover su uno vivo nel caso in cui alcuni di essi falliscono.

Modifica : Nginx supporta HTTP 1.1 per i backend e keepalive dalla versione 1.1.4. Sono supportati upstream “fastcgi” e “proxy”. Ecco i documenti

Per chiunque si stia interrogando sullo stesso problema, nginx ora supporta ufficialmente HTTP 1.1 upstream. Vedere la documentazione di nginx per “keepalive” e “proxy_http_version 1.1”.

Che ne dici di Nginx con il nuovo modulo Push HTTP: http://pushmodule.slact.net/ . Si prende cura della connessione giocoleria (per così dire) che potrebbe essere necessario preoccuparsi di un proxy inverso. È sicuramente un’alternativa valida ai Websocket che non sono ancora completamente integrati nel mix. So che lo sviluppatore del modulo Push HTTP sta ancora lavorando su una versione completamente stabile, ma è in sviluppo attivo. Ci sono versioni di esso che vengono utilizzate nelle codebase di produzione. Per citare l’autore, “Uno strumento utile con un nome noioso.”

Io uso nginx per invertire il proxy su un server di stile comet con connessioni polling lunghe e funziona alla grande. Assicurati di configurare proxy_send_timeout e proxy_read_timeout su valori appropriati. Inoltre assicurati che il tuo server back-end nginx sia proxy per supportare http 1.0 perché non penso che il modulo proxy di nginx faccia ancora l’HTTP 1.1.

Solo per chiarire un po ‘di confusione in alcune delle risposte: Keepalive consente a un client di riutilizzare una connessione per inviare un’altra richiesta HTTP. Non ha nulla a che fare con il polling prolungato o mantenendo aperte le connessioni fino a quando si verifica un evento che è ciò a cui la domanda originale stava chiedendo. Quindi non importa che il modulo proxy di nginx supporti solo HTTP 1.0 che non ha keepalive.