WebSocketsとApacheプロキシ:mod_proxy_wstunnelの構成方法


98

私が持っています :

  1. Apache(v2.4)mod_proxymod_proxy_wstunnelを有効にwww.domain1.comして、のサーバーのポート80で

  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にする方法は?

回答:


160

このトピックスのおかげで、ようやくなんとかそれを行うことができました。

TODO:

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>

注:WebSocketをを使用して、同じサーバー上で複数のサービスを持っている場合は、あなたがしたい場合があり、これを行うそれらを分離します。


FWIW、CentOS 7.1のApache 2.4にはこのバグがあるため、書き換えはws://プロトコルを認識せず、サブリクエストを送信する前にドメインを付加します。[P] roxyフラグを[R] edirectに変更することで、自分でテストできます。
Andor 2015

3
これを行うと、ws://ルートに502の不正なゲートウェイが引き続き表示されます。Ubuntu 14.04でのApache 2.4の実行
Alex Muro

1
これはすべてのHTTPトラフィックも転送されるため機能しますが、ソケットトラフィックのみを転送する場合は、Socket.ioがHTTPポーリングリクエストで通信を開始することに注意してください。詳細はこちら
Erik Koopmans 2017年

4
443 wssからwsに転送する方法は?rewritecondは変更されますか?
エルナンEche

1
状態RewriteCond %{QUERY_STRING} transport=websocket [NC]が正しく機能しませんでした。RewriteCond %{HTTP:Upgrade} =websocket [NC]代わりに使用することを提案しています。
マーティン

99

URLでフィルタリングする代わりに、HTTPヘッダーでフィルタリングすることもできます。この構成は、socket.ioを使用していない場合でも、websocketを使用するすべてのWebアプリケーションで機能します。

<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と同じ場所に送られます)
スティーブリリー

この構成はalibabaクラウドで最適に機能します。また、「ホープ誰かが、これは便利エラーネット:: ERR_RESPONSE_HEADERS_TRUNCATEDを修正します。
マイクMusni

SignalRを使用して、私が言うことができ、これは私のために+1のおかげで最高の働いていた
Vojtěchムラーズ

18

役に立つかもしれません。すべてのクエリがws経由でノードに送信されます

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

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

@Sergeyに感謝します。これは、すべてをドキュメントルートにルーティングするのではなく、wsによって参照されるダイレクトパスのみを使用するときに役立ちました。他の人のために、以下の回答で私がやったことを示しました。
Anwaarullah

この答えは単純なWebソケット(socket.ioなし)で機能するので、私にとってはこれがより良い答えです
Tomas

驚くばかり!これはすぐにうまくいきましたが、他の書き換えやプロキシの試行では問題が解決しませんでした。
ステファン

ありがとうございました!!基本的な使用例に最適、ws://を使用した単純なWebソケット
Antonia Blair

16

Socket.IO 1.0(2014年5月)以降、すべての接続はHTTPポーリングリクエストで始まります(詳細はこちら)。つまり、WebSocketトラフィックの転送に加えて、transport=pollingHTTPリクエストを転送する必要があります。

以下のソリューションでは、他のトラフィックをリダイレクトせずに、すべてのソケットトラフィックを正しくリダイレ​​クトする必要があります。

  1. 以下のApache2 modsを有効にします。

    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
これは私にとっては完璧に機能します。注あなたの要求がroot以外のURLにして来ている場合は、例えば行うことができますRewriteRule /path/(.*)
ロブ・グウィン・ジョーンズ

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に1行だけ追加すると機能します(太線)。


<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で実行)
  • パスでWebSocketを受け入れるポート3000で実行されているNode.js(バージョン4.1.1)アプリ /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を使用してアプリを設定する際に問題が発生しました。手伝っていただけませんか?(私はワニスキャッシュサーバーの上に座っています)
Josh

6
スクリーンショットの代わりにコピー/貼り付けできますか?よろしくお願いします。読みやすさが向上します。
Basj

3

static、rest、およびwebsocketコンテンツを実行するSpringアプリケーションについて、次のことを行いました。

Apacheは、次のURIのプロキシおよびSSLエンドポイントとして使用されます。

  • / app→静的コンテンツ
  • / api→REST API
  • / api / ws→websocket

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のパフォーマンスソリューションのこのリンクを使用します

以下の手順を実行する必要があります。

に行く /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はws、tomcatおよびtomcatに配置されたWarファイルがapacheを提供する場所に接続するため、tomcat実行ポートを意味しますws。ありがとうございました

私の構成

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

すみません、よくわかりません(特に最後の文)。回答のフォーマットを改善し、あなたが言っていることすべてを知らない人のために詳細を追加できますか?
Basj

Tomcat @ArvindMadhukarとは何ですか?
Basj 2018

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

主な答えに加えて、WebSocketを使用する同じサーバー上に複数のサービスがある場合は、カスタムパス(*)を使用して、サービスを分離することができます。

ノードサーバー:

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.ioWebサイトに固有のものではなく、WebSocketリクエストは異なるWebサイト間で混同されます!


0

TODO:

  1. 持っているのApache 2.4にインストール(2.2では動作しません)、a2enmod proxyおよびa2enmod proxy_wstunnel.load

  2. Apache構成でこれを行うには
    、ファイルに2行を追加します。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.