22

HTTPS 経由でのみアクセスできる Apache を実行しています。同じマシンで実行される追加のサーバー アプリケーションから Websocket を提供したいのですが、クライアントが 443 以外のポートでサーバーに接続することはできないため、これらの Websocket 接続は Apache を介してプロキシする必要があります。

これで、mod_proxy をインストールし、次のように構成しました。

SSLProxyEngine on
ProxyPass /ws https://127.0.0.1:9001

ただし、これは機能しません。ブラウザーでhttps://server/wsに接続できるようになりましたが、Apache が Websocket ヘッダーの一部を飲み込んでいるように見えるため、実際の Websocket 接続は機能しません。

Apache サーバーを介して websocket 接続をトンネリングするにはどうすればよいですか?

4

2 に答える 2

29

私はそれが働いている。

シナリオ

-------------       ----------------       ----------
| Browser   |<----->| Apache httpd |<----->| Tomcat |
|           |  SSL  |    2.4.9     |  SSL  | 7.0.52 |
-------------       ----------------       ----------

Apache httpd を介したブラウザー WebSocket、Tomcat の Web アプリへのリバース プロキシ。すべて SSL フロントツーバック。

各パーツの構成は次のとおりです。

ブラウザ クライアント

url: の末尾の「/」に注意してくださいwss://host/app/ws/。正しい wss ProxyPass ディレクティブ (Apache 構成セクションのさらに下に表示) を一致させ、 への 301 リダイレクトを防止する必要がありましたhttps://host/app/ws。つまり、バックエンドの wss スキームではなく、https スキームを使用してリダイレクトしていました。

テストページ
<!doctype html>
<body>

<script type="text/javascript">
    var connection = new WebSocket("wss://host/app/ws/");

    connection.onopen = function () {
        console.log("connected");
    };

    connection.onclose = function () {
        console.log("onclose");
    };

    connection.onerror = function (error) {
        console.log(error);
    };
</script>

</body>
</html>

アパッチ httpd

私は Apache httpd 2.4.9 を使用しています。これはすぐにmod_proxy_wstunnelを提供します。ただし、提供されているmod_proxy_wstunnel.soは、 wss:// スキームを使用する場合、SSL をサポートしていません。バックエンド (Tomcat) に平文で接続しようとすることになり、SSL ハンドシェイクに失敗します。ここでバグを参照してください。そのため、バグ レポートで提案されている修正に従って、mod_proxy_wstunnel.cに自分でパッチを適用する必要があります。3行の簡単な変更です。

Suggested correction,
314a315
>     int is_ssl = 0;
320a322
>         is_ssl = 1;
344c346
<     backend->is_ssl = 0;
---
>     backend->is_ssl = is_ssl;

次に、モジュールを再構築し、新しいmod_proxy_wstunnel.soを古いものに置き換えます。

Apache httpd のビルド

必要なモジュールをビルドするために使用した (2.4.9) コマンドを次に示します。それらすべてが必要なわけではないかもしれません。

./configure --prefix=/usr/local/apache --with-included-apr --enable-alias=shared
--enable-authz_host=shared --enable-authz_user=shared 
--enable-deflate=shared --enable-negotiation=shared 
--enable-proxy=shared --enable-ssl=shared --enable-reqtimeout=shared
--enable-status=shared --enable-auth_basic=shared
--enable-dir=shared --enable-authn_file=shared
--enable-autoindex=shared --enable-env=shared --enable-php5=shared
--enable-authz_default=shared --enable-cgi=shared
--enable-setenvif=shared --enable-authz_groupfile=shared
--enable-mime=shared --enable-proxy_http=shared
--enable-proxy_wstunnel=shared

最後のスイッチに注意してください--enable-proxy_wstunnel=shared 。最初は、--enable-proxy-wstunnel=sharedうまくビルドできたように見えたが、結果の .so ファイルを使用すると最終的には機能しませんでした。違いを見ます?"proxy_wstunnel"ダッシュではなくアンダースコアを使用するようにしてください。

Apache httpd 構成

httpd.conf
...
LoadModule proxy_module modules/mod_proxy.so
...
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
...
LoadModule ssl_module modules/mod_ssl.so
...
Include conf/extra/httpd-ssl.conf
...
LogLevel debug
ProxyRequests off

# Note, this is the preferred ProxyPass configuration, and *should* be equivalent
# to the same inline version below, but it does NOT WORK!
#<Location /app/ws/>
#        ProxyPass wss://localhost:8443/app/ws
#        ProxyPassReverse wss://localhost:8443/app/ws
#</Location>
#<Location /app/>
#        ProxyPass https://localhost:8443/app/
#        ProxyPassReverse https://localhost:8443/app/
#</Location>

# NOTE: Pay strict attention to the slashes "/" or lack thereof!
# WebSocket url endpoint
ProxyPass /app/ws/ wss://localhost:8443/app/ws
ProxyPassReverse /app/ws/ wss://localhost:8443/app/ws

# Everything else
ProxyPass /app/ https://localhost:8443/app/
ProxyPassReverse /app/ https://localhost:8443/app/

上記の構成で私のメモが表示されなかった場合は、もう一度ここに示します。スラッシュ「/」またはその欠如に細心の注意を払ってください!

また、Apache ログに wss 接続が作成されてから閉じられたというデバッグ ログ ステートメントが表示されている場合は、私が行ったように mod_reqtimeout が有効になっている可能性があるため、ロードされていないことを確認してください。

#LoadModule reqtimeout_module modules/mod_reqtimeout.so

トムキャット

HTTP コネクタが正しく設定されていると仮定すると、Tomcat で設定することはあまりありません。デバッグを支援するために、次のような を作成すると便利であることがわかりました$CATALINA_HOME/bin/setenv.sh

setenv.sh
CATALINA_OPTS=$CATALINA_OPTS" -Djavax.net.debug=all -Djavax.net.debug=ssl:handshake:verbose"

これにより、変更した mod_proxy_wstunnel.so が wss:// に対して機能しているかどうかを確認できました。機能していない場合、catalina.out ログ ファイルには次のように表示されます。

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
http-nio-8443-exec-1, SEND TLSv1 ALERT:  fatal, description = internal_error
http-nio-8443-exec-1, WRITE: TLSv1 Alert, length = 2
http-nio-8443-exec-1, called closeOutbound()
http-nio-8443-exec-1, closeOutboundInternal()

最終的な考え

私は Apache httpd 2.4.9 を使用していますが、 mod_proxy_wstunnel のバックポートをバージョン 2.2.x に適用できる場所を見てきました。上記の私のメモがそれらの古いバージョンに適用できることを願っています。

于 2014-04-04T21:58:28.900 に答える
1

Apache に SSL 接続を終了させたくない (そして暗号化されていない WebSocket トラフィックを転送させたくない) が、最終的なターゲット WebSocket サーバーで SSL を終了させ、Apache に着信する WebSocket トラフィックでWSS を排他的に使用したい場合は、 mod_proxy_connectを使用できます。生のトラフィックを介して接続するだけです。わからない。それがうまくいくなら私も興味があります。

上記が成り立たない場合、詳細は次のとおりです。

いずれにせよ、Apache を使用すると、同時に提供される WebSocket 接続の数に関するスケーラビリティが大幅に制限されます。これは、すべての WS 接続が Apache で 1 つのプロセス/スレッドを消費するためです。

于 2012-07-13T10:40:45.127 に答える