WebSockets ve Apache proxy'si: mod_proxy_wstunnel nasıl yapılandırılır?


101

Sahibim :

  1. Apachebenim sunucunun 80 numaralı bağlantı noktasında (v2.4) www.domain1.comile, mod_proxy ve mod_proxy_wstunnel etkin

  2. node.js + socket.io aynı sunucunun 3001 numaralı bağlantı noktasında.

Erişim www.domain2.com(bağlantı noktası 80 ile) burada açıklanan yöntem sayesinde 2.'ye yönlendirir . Bunu Apache yapılandırmasında ayarladım:

<VirtualHost *:80>
    ServerName www.domain2.com
    ProxyPass / http://localhost:3001/
    ProxyPassReverse / http://localhost:3001/
    ProxyPass / ws://localhost:3001/
    ProxyPassReverse / ws://localhost:3001/
</VirtualHost>

Websocket kısmı hariç her şey için çalışır: ws://...proxy tarafından olması gerektiği gibi iletilmez.

Sayfaya eriştiğimde www.domain2.com, elimde:

Impossible to connect ws://www.domain2.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.

Soru: Apache proxy'sini WebSockets olarak nasıl yapabilirim?

Yanıtlar:


164

Bu konu sayesinde nihayet başardım .

YAPMAK:

1) Apache 2.4'ü kurun (2.2 ile çalışmaz) ve şunları yapın:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2) nodejs3001 numaralı bağlantı noktasında çalışıyor

3) Bunu Apache yapılandırmasında yapın

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
  RewriteCond %{QUERY_STRING} transport=websocket    [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]

  ProxyPass / http://localhost:3001/
  ProxyPassReverse / http://localhost:3001/
</VirtualHost>

Not: Aynı sunucuda web soketleri kullanan birden fazla hizmetiniz varsa, bunları ayırmak için bunu yapmak isteyebilirsiniz .


CentOS 7.1'deki FWIW, Apache 2.4'te bu hata vardır, bu nedenle yeniden yazma işlemi ws: // protokolünü tanımaz ve alt isteği göndermeden önce etki alanının başına eklenir. [P] roxy bayrağını [R] edirect olarak değiştirerek kendinizi test edebilirsiniz.
Andor

3
Bunu yaparken ws: // rotalarım için hala 502 bozuk ağ geçidi alıyorum. Apache 2.4'ü Ubuntu 14.04'te Çalıştırma
Alex Muro

1
Bu işe yarıyor çünkü tüm HTTP trafiği de iletiliyor, ancak sadece soket trafiğinizi iletmek istiyorsanız, lütfen Socket.io'nun bir HTTP sorgulama isteği ile iletişime başladığını unutmayın. Daha fazla bilgi burada .
Erik Koopmans

4
443 wss'den WS'ye yönlendirme nasıl yapılır? yeniden yazma saniyesi değişir mi?
Hernán Eche

1
Durum RewriteCond %{QUERY_STRING} transport=websocket [NC]doğru şekilde çalışmadı. RewriteCond %{HTTP:Upgrade} =websocket [NC]Bunun yerine kullanmayı öneriyorum.
Martin

103

URL'ye göre filtrelemek yerine, HTTP başlığına göre de filtreleyebilirsiniz. Bu yapılandırma, websockets kullanan tüm web uygulamaları için, ayrıca socket.io kullanmıyorlarsa da çalışacaktır:

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule /(.*)           http://localhost:3001/$1 [P,L]

  ProxyPassReverse / http://localhost:3001/
</VirtualHost>

Bu benim için iyi çalışıyor, ancak bir alt yol için proxy yapıyorum ve normal ifade bir alt dizeyi aradığı için ^ bağlantıları eklemenin önemli olduğunu gördüm. Örneğin, RewriteRule ^ [^ /] * / foo /(.*) http: // $ {FOO_HOST} / $ 1 [P, L] (aksi takdirde / bar / foo, / foo ile aynı yere yönlendirilecektir)
Steve Lilly

Bu yapılandırma en iyi alibaba bulutu üzerinde çalışır. Buna ek olarak, net :: ERR_RESPONSE_HEADERS_TRUNCATED "Birinin bunu faydalı bulmasını umuyoruz.
Mike Musni

SignalR'yi kullanarak bunun benim için en iyisi olduğunu söyleyebilirim +1 Teşekkürler
Vojtěch Mráz

18

Yararlı olabilir. Yalnızca tüm sorgular ws aracılığıyla düğüme gönderilir

<VirtualHost *:80>
  ServerName www.domain2.com

  <Location "/">
    ProxyPass "ws://localhost:3001/"
  </Location>
</VirtualHost>

Teşekkürler @Sergey. Bu, her şeyi kök belgesine yönlendirmek yerine yalnızca ws tarafından referans verilen doğrudan yolu kullandığımda bana yardımcı oldu. Başkalarının yararı için aşağıda bir cevapta ne yaptığımı gösterdim.
Anwaarullah

Bu cevap basit web soketleri için işe yarar (socket.io yok) bu yüzden benim için bu daha iyi cevap
Tomas

Harika! Bu, diğer yeniden yazma ve proxy girişimleri sorunumu çözmediğinde anında benim için çalışıyordu.
Stephan

Teşekkür ederim!! Temel kullanım durumu için mükemmel, ws: // kullanan basit bir web soketi
Antonia Blair

18

Socket.IO 1.0'dan (Mayıs 2014) itibaren, tüm bağlantılar bir HTTP yoklama isteğiyle başlar (daha fazla bilgi burada ). Bu, WebSocket trafiğini iletmeye ek olarak, herhangi bir transport=pollingHTTP isteğini iletmeniz gerektiği anlamına gelir .

Aşağıdaki çözüm, diğer trafiği yeniden yönlendirmeden tüm soket trafiğini doğru bir şekilde yeniden yönlendirmelidir.

  1. Aşağıdaki Apache2 modlarını etkinleştirin:

    sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
    
  2. Bu ayarları * .conf dosyanızda (örn. /etc/apache2/sites-available/mysite.com.conf) Kullanın . Her parçayı açıklamak için yorumlar ekledim:

    <VirtualHost *:80>
        ServerName www.mydomain.com
    
        # Enable the rewrite engine
        # Requires: sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
        # In the rules/conds, [NC] means case-insensitve, [P] means proxy
        RewriteEngine On
    
        # socket.io 1.0+ starts all connections with an HTTP polling request
        RewriteCond %{QUERY_STRING} transport=polling       [NC]
        RewriteRule /(.*)           http://localhost:3001/$1 [P]
    
        # When socket.io wants to initiate a WebSocket connection, it sends an
        # "upgrade: websocket" request that should be transferred to ws://
        RewriteCond %{HTTP:Upgrade} websocket               [NC]
        RewriteRule /(.*)           ws://localhost:3001/$1  [P]
    
        # OPTIONAL: Route all HTTP traffic at /node to port 3001
        ProxyRequests Off
        ProxyPass           /node   http://localhost:3001
        ProxyPassReverse    /node   http://localhost:3001
    </VirtualHost>
    
  3. /nodeKullanışlı bulduğum trafiği yönlendirmek için fazladan bir bölüm ekledim, daha fazla bilgi için buraya bakın .


1
Bu benim için mükemmel çalışıyor. İstekleriniz kök dışında bir URL'ye geliyorsa, örneğin şunları yapabilirsinizRewriteRule /path/(.*)
Rob Gwynn-Jones

9

Benim için httpd.conf'a aşağıdaki gibi sadece bir satır ekledikten sonra çalışıyor (kalın çizgi).


<VirtualHost *:80>
    ServerName: xxxxx

    #ProxyPassReverse is not needed
    ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>

Apache sürümü CentOS üzerinde 2.4.6'dır.


8

Bu cevapların yardımıyla nihayet bu Apache2 site yapılandırmasını kullanarak Ubuntu Mate ve Apache2 çalışırken bir Raspberry Pi üzerinde çalışan Node-RED için ters proxy elde ettim:

<VirtualHost *:80>
    ServerName nodered.domain.com
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://localhost:1880/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteRule /(.*)           http://localhost:1880/$1 [P,L]
</VirtualHost>

Ayrıca bunun gibi modülleri etkinleştirmem gerekiyordu:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel

5

Kurulumum:

  • Apache 2.4.10 (Debian'ı çalıştırıyor)
  • Node.js (sürüm 4.1.1) Yolda WebSocket'ları kabul eden 3000 numaralı bağlantı noktasında çalışan uygulama /api/ws

Yukarıda @Basj tarafından belirtildiği gibi, a2enmod proxy ve ws_tunnel'ın etkinleştirildiğinden emin olun.

Bu, sorunumu çözen Apache yapılandırma dosyasının ekran görüntüsü:

Apache yapılandırması

İlgili kısım metin olarak:

<VirtualHost *:80>
  ServerName *******
  ServerAlias *******
  ProxyPass / http://localhost:3000/
  ProxyPassReverse / http://localhost:3000/

  <Location "/api/ws">
      ProxyPass "ws://localhost:3000/api/ws"
  </Location>
</VirtualHost>

Umarım yardımcı olur.


Uygulamamı varsayılan yerine tercih edilen bir URL ile kurmakta sorun yaşıyorum, bana yardımcı olur musunuz? (Bir vernik önbellek sunucusunun üstünde oturuyorum)
Josh

6
Ekran görüntüsü yerine kopyalayıp yapıştırabilir misiniz? Şimdiden teşekkür ederim, okunabilirliği artıracaktır.
Basj

4

Statik, dinlenme ve web soket içeriğini çalıştıran bir yay uygulaması için aşağıdakileri yaptınız.

Apache, aşağıdaki URI'ler için Proxy ve SSL Endpoint olarak kullanılır:

  • / app → statik içerik
  • / api → REST API
  • / api / ws → websocket

Apache yapılandırması

<VirtualHost *:80>
    ServerName xxx.xxx.xxx    

    ProxyRequests Off
    ProxyVia Off
    ProxyPreserveHost On

    <Proxy *>
         Require all granted
    </Proxy>

    RewriteEngine On

    # websocket 
    RewriteCond %{HTTP:Upgrade}         =websocket                      [NC]
    RewriteRule ^/api/ws/(.*)           ws://localhost:8080/api/ws/$1   [P,L]

    # rest
    ProxyPass /api http://localhost:8080/api
    ProxyPassReverse /api http://localhost:8080/api

    # static content    
    ProxyPass /app http://localhost:8080/app
    ProxyPassReverse /app http://localhost:8080/app 
</VirtualHost>

SSL yapılandırması için aynı vHost yapılandırmasını kullanıyorum, proxy ile ilgili hiçbir şeyi değiştirmeye gerek yok.

Yay konfigürasyonu

server.use-forward-headers: true

Konumları ayırmak için bir Konum etiketi kullanın, yani: <Location / app> ProxyPass localhost: 8080 / app ProxyPassReverse localhost: 8080 / app </Location>
CrazyMerlin

2

Ana yanıta ek olarak: Aynı sunucuda web soketlerini kullanan birden fazla hizmetiniz varsa, bunu özel bir yol (*) kullanarak bunları ayırmak için yapmak isteyebilirsiniz :

Düğüm sunucusu:

var io = require('socket.io')({ path: '/ws_website1'}).listen(server);

İstemci HTML'si:

<script src="/ws_website1/socket.io.js"></script>
...
<script>
var socket = io('', { path: '/ws_website1' });
...

Apache yapılandırması:

RewriteEngine On

RewriteRule ^/website1(.*)$ http://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule ^(.*)$ ws://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteRule ^(.*)$ http://localhost:3001$1 [P,L]

(*) Not: Varsayılanı kullanmak RewriteCond %{REQUEST_URI} ^/socket.iobir web sitesine özgü olmaz ve websockets istekleri farklı web siteleri arasında karıştırılır!


2

Ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html için mükemmel çözüm için bu bağlantıyı kullanın

Sadece aşağıdaki adımı yapmanız gerekir ..

Git /etc/apache2/mods-available

Aşama 1

mode proxy_wstunnel.loadAşağıdaki komutu kullanarak etkinleştirin

$a2enmod proxy_wstunnel.load

Adım 2

Git /etc/apache2/sites-available

ve sanal konak içindeki .conf dosyanıza aşağıdaki satırı ekleyin

ProxyPass "/ws2/"  "ws://localhost:8080/"

ProxyPass "/wss2/" "wss://localhost:8080/"

Not: 8080, tomcat'in çalıştığı bağlantı noktanız anlamına gelir, çünkü wsWar dosyamızın tomcat'e yerleştirildiği ve tomcat'in apache'ye hizmet ettiği yere bağlanmak istiyoruz ws. teşekkür ederim

Yapılandırmam

ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid=4 =Connected

Üzgünüm gerçekten anlamadım (özellikle son cümlenizi). Cevabın biçimini iyileştirebilir ve söylediklerinizi bilmeyen insanlar için ayrıntılar ekleyebilir misiniz?
Basj

Tomcat @ArvindMadhukar nedir?
Basj

1

"Sorgulama" aktarımı için.

Apaçi tarafı:

<VirtualHost *:80>
    ServerName mysite.com
    DocumentRoot /my/path


    ProxyRequests Off

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    ProxyPass /my-connect-3001 http://127.0.0.1:3001/socket.io
    ProxyPassReverse /my-connect-3001 http://127.0.0.1:3001/socket.io   
</VirtualHost>

İstemci tarafı:

var my_socket = new io.Manager(null, {
    host: 'mysite.com',
    path: '/my-connect-3001'
    transports: ['polling'],
}).socket('/');

1

YAPMAK:

  1. Apache 2.4'ün kurulu olması (2.2 ile çalışmaz) a2enmod proxyvea2enmod proxy_wstunnel.load

  2. Bunu Apache yapılandırmasında
    yapın, dosyanıza iki satır ekleyin, burada 8080 tomcat çalışan bağlantı noktanızdır

    <VirtualHost *:80>
    ProxyPass "/ws2/" "ws://localhost:8080/" 
    ProxyPass "/wss2/" "wss://localhost:8080/"
    
    </VirtualHost *:80>
    
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.