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.