WebSockets 및 Apache 프록시 : mod_proxy_wstunnel을 구성하는 방법?


99

나는 가지고있다 :

  1. Apache (v2.4) 내 서버의 포트 80에서 www.domain1.com 와, mod_proxy를 하고 mod_proxy_wstunnel이 가능

  2. node.js + socket.io 동일한 서버의 포트 3001에서.

여기에 설명 된 방법www.domain2.com 덕분에 액세스 (포트 80 사용)가 2로 리디렉션됩니다 . Apache 구성에서 이것을 설정했습니다.

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

그것은 websocket 부분을 제외하고 모든 것을 위해 작동합니다 : ws://...프록시에 의해 전송되어야하는 것처럼 전송되지 않습니다.

의 페이지에 액세스하면 www.domain2.com다음을 갖게됩니다.

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

질문 : Apache 프록시를 WebSocket으로 만드는 방법은 무엇입니까?

답변:


161

나는 이 주제 덕분에 마침내 그것을 할 수 있었다 .

할 것:

1) Apache 2.4를 설치하고 (2.2에서는 작동하지 않음) 다음을 수행합니다.

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2) nodejs포트 3001에서 실행 중

3) Apache 구성에서 수행하십시오.

<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>

참고 : 웹 소켓을 사용하는 동일한 서버에 둘 이상의 서비스가있는 경우 이를 분리하기 위해이 작업수행 할 수 있습니다.


FWIW, CentOS 7.1의 Apache 2.4에는 이 버그가 있으므로 재 작성은 ws : // 프로토콜을 인식하지 못하며 하위 요청을 보내기 전에 도메인 앞에 추가합니다. [P] roxy 플래그를 [R] edirect로 변경하여 자신을 테스트 할 수 있습니다.
Andor

3
이 작업을 수행 할 때 ws : // 경로에 대해 여전히 502 개의 잘못된 게이트웨이가 있습니다. Ubuntu 14.04에서 Apache 2.4 실행
Alex Muro

1
이는 모든 HTTP 트래픽도 전달되기 때문에 작동하지만 소켓 트래픽 만 전달하려는 경우 Socket.io는 HTTP 폴링 요청으로 통신을 시작합니다. 여기에 더 많은 정보가 있습니다 .
Erik Koopmans

4
443 wss에서 ws로 전달하는 방법은 무엇입니까? rewritecond가 변경됩니까?
Hernán Eche

1
조건 RewriteCond %{QUERY_STRING} transport=websocket [NC]이 제대로 작동하지 않았습니다. RewriteCond %{HTTP:Upgrade} =websocket [NC]대신 사용을 제안합니다 .
Martin

99

URL로 필터링하는 대신 HTTP 헤더로 필터링 할 수도 있습니다. 이 구성은 socket.io를 사용하지 않는 경우에도 웹 소켓을 사용하는 모든 웹 응용 프로그램에서 작동합니다.

<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>

이것은 나를 위해 잘 작동하지만 하위 경로를 프록시하고 있으며 정규식이 하위 문자열을 찾고 있기 때문에 ^ 앵커를 추가하는 것이 중요하다는 것을 알았습니다. 예 : RewriteRule ^ [^ /] * / foo /(.*) http : // $ {FOO_HOST} / $ 1 [P, L] (그렇지 않으면 / bar / foo도 / foo와 같은 위치로 이동합니다)
Steve 릴리

이 구성은 alibaba 클라우드에서 가장 잘 작동합니다. 또한, 오류 그물을 해결합니다 :: ERR_RESPONSE_HEADERS_TRUNCATED '희망의 사람이 유용하게 찾을 수 있습니다.
마이크 Musni에게

SignalR을 사용하면 이것이 저에게 가장 효과적이라고 말할 수 있습니다. +1 감사합니다
Vojtěch Mráz

18

유용 할 수 있습니다. 모든 쿼리는 ws를 통해 노드로 전송됩니다.

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

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

감사합니다 @Sergey. 이것은 모든 것을 문서 루트로 라우팅하는 대신 ws에서 참조하는 직접 경로 만 사용할 때 도움이되었습니다. 나는 다른 사람들의 이익을 위해 아래 답변에서 내가 한 일을 보여주었습니다.
Anwaarullah 2015 년

이 답변은 간단한 웹 소켓 (socket.io 없음)에서 작동하므로 더 나은 답변입니다
Tomas

대박! 이것은 다른 재 작성 및 프록시 시도가 내 문제를 해결하지 못하는 동안 나를 위해 즉시 작동했습니다.
Stephan

감사합니다!! 완벽한 기본 사용 사례, 단순한 웹 소켓을 사용하여 WS : //
안토니아 블레어

17

Socket.IO 1.0 (2014 년 5 월)부터 모든 연결은 HTTP 폴링 요청으로 시작됩니다 (자세한 내용은 여기 ). 즉, WebSocket 트래픽을 전달하는 것 외에도 transport=pollingHTTP 요청 을 전달해야 합니다.

아래 솔루션은 다른 트래픽을 리디렉션하지 않고 모든 소켓 트래픽을 올바르게 리디렉션해야합니다.

  1. 다음 Apache2 모드를 활성화합니다.

    sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
  2. * .conf 파일 (예 :)에서이 설정을 사용하십시오 /etc/apache2/sites-available/mysite.com.conf. 각 부분에 대한 설명을 포함했습니다.

    <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. /node편리한 트래픽 라우팅을위한 추가 섹션을 포함했습니다. 여기를 참조 하십시오. . 자세한 를 .


1
이것은 나를 위해 완벽하게 작동합니다. 요청이 루트가 아닌 URL로 들어오는 경우 다음과 같이 할 수 있습니다.RewriteRule /path/(.*)
Rob Gwynn-Jones

8

이 답변의 도움으로 마침내이 Apache2 사이트 구성을 사용하여 Ubuntu Mate 및 Apache2가 작동하는 Raspberry Pi에서 실행되는 Node-RED에 대한 역방향 프록시를 얻었습니다.

<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>

또한 다음과 같은 모듈을 활성화해야했습니다.

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel

7

나를 위해 아래 (굵은 줄)와 같이 httpd.conf에 한 줄만 추가하면 작동합니다 .


<VirtualHost *:80>
    ServerName: xxxxx

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

CentOS에서 Apache 버전은 2.4.6입니다.


5

내 설정 :

  • Apache 2.4.10 (Debian에서 실행)
  • Node.js (버전 4.1.1) 경로에서 WebSocket을 허용하는 포트 3000에서 실행되는 앱 /api/ws

@Basj가 위에서 언급했듯이 a2enmod 프록시와 ws_tunnel이 활성화되어 있는지 확인하십시오.

이것은 내 문제를 해결 한 Apache 구성 파일의 스크린 샷입니다.

Apache 구성

텍스트로 관련 부분 :

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

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

도움이 되었기를 바랍니다.


기본 URL이 아닌 선호하는 URL로 앱을 설정하는 데 문제가 있습니다. 도와 주시겠습니까? (나는 니스 캐시 서버 위에 앉아있다)
Josh

6
스크린 샷 대신 복사 / 붙여 넣기를 할 수 있습니까? 미리 감사드립니다. 가독성이 향상됩니다.
Basj

3

정적, 휴식 및 웹 소켓 콘텐츠를 실행하는 스프링 애플리케이션에 대해 다음을 수행했습니다.

Apache는 다음 URI에 대해 프록시 및 SSL 끝점으로 사용됩니다.

  • / app → 정적 콘텐츠
  • / api → REST API
  • / api / ws → 웹 소켓

Apache 구성

<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 구성에 동일한 vHost 구성을 사용하므로 관련 프록시를 변경할 필요가 없습니다.

봄 구성

server.use-forward-headers: true

위치 태그를 사용하여 위치를 구분하십시오. 예 : <Location / app> ProxyPass localhost : 8080 / app ProxyPassReverse localhost : 8080 / app </ Location>
CrazyMerlin

2

ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html에 대한 perfact 솔루션에 대한 사용자이 링크

아래 단계 만하시면됩니다 ..

이동 /etc/apache2/mods-available

1 단계

mode proxy_wstunnel.load아래 명령을 사용하여 활성화

$a2enmod proxy_wstunnel.load

2 단계

이동 /etc/apache2/sites-available

가상 호스트 내부의 .conf 파일에 아래 줄을 추가하십시오.

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

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

참고 : 8080은 wstomcat과 tomcat에 저장된 War 파일이 아파치를 제공 하는 위치 에 연결하기를 원하기 때문에 tomcat 실행 포트를 의미합니다 ws. 감사합니다

내 구성

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

정말 이해가 안 돼서 죄송합니다 (특히 마지막 문장). 답변의 형식을 개선하고 언급 한 내용을 모두 모르는 사람들을 위해 세부 정보를 추가 할 수 있습니까?
Basj

Tomcat @ArvindMadhukar는 무엇입니까?
Basj

1

"폴링"전송 용.

Apache 측 :

<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>

고객 입장에서:

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

1

기본 답변 외에도 웹 소켓을 사용하는 동일한 서버에 둘 이상의 서비스가있는 경우 사용자 지정 경로 (*)를 사용하여이를 분리하기 위해 이렇게 할 수 있습니다 .

노드 서버 :

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

클라이언트 HTML :

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

Apache 구성 :

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]

(*) 참고 : 기본값을 사용하는 RewriteCond %{REQUEST_URI} ^/socket.io것은 웹 사이트에 국한되지 않으며 웹 소켓 요청은 서로 다른 웹 사이트간에 혼합됩니다!


0

할 것:

  1. 설치 한 아파치 2.4 (2.2 일을하지 않습니다), a2enmod proxya2enmod proxy_wstunnel.load

  2. Apache 구성에서 이것을 수행
    하십시오 파일에 두 줄을 추가하십시오. 여기서 8080은 Tomcat 실행 포트입니다.

    <VirtualHost *:80>
    ProxyPass "/ws2/" "ws://localhost:8080/" 
    ProxyPass "/wss2/" "wss://localhost:8080/"
    
    </VirtualHost *:80>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.