web-dev-qa-db-ja.com

Apacheによる安全なWebSocket接続のトンネリング

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接続をトンネリングするにはどうすればよいですか?

20
mstud

私はそれを働いています。

シナリオ

-------------       ----------------       ----------
| 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構成セクションでさらに下に表示)と一致させ、https://Host/app/wsへの301リダイレクトを防ぐ必要がありました。つまり、バックエンドの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>

Apache 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設定

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

上記の設定で私のメモが表示されなかった場合は、次のようになります:スラッシュ「/」またはその欠如に厳密に注意してください!

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

#LoadModule reqtimeout_module modules/mod_reqtimeout.so

トムキャット

HTTPコネクターが正しくセットアップされていると仮定すると、Tomcatで構成することはあまりありません。デバッグを支援するために、次のような$CATALINA_HOME/bin/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に適用できる場所を確認しました 。うまくいけば、上記の私のノートがそれらの古いバージョンに適用できることを願っています。

27
Tom Cawley

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

上記が当てはまらない場合は、以下に詳細を示します。

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

1
oberstet

これをインストールしようとしています https://github.com/kawasima/mod_proxy_websocket 。それが役に立てば幸い。

0
dlopezgonzalez