Armoris日記 NGINX-Proxy WebSocket編

このブログは、元N高生株式会社Armorisの社員が書いています。

あるもりすぶろぐの内容は個人の意見です。

NGINX ProxyとWebSocketのお話

先日社内システムのNGINX Proxyで設定を変更した際、WebSocket通信で問題が発生しました。今回は問題解決のために行ったこと、解決方法について取り上げます。

NGINXに加えた変更について

これまでNGINX Proxyでの認証にはNGINX標準の機能を利用したBasic Authを利用していましたが、セキュリティ上の問題などから外部モジュールを利用したDigest Authに変更しています。
変更時の作業についてはいずれArmoris日記としてまとめたいと思います。

発生した問題

NGINXの設定を変更後Proxyしている特定のサービスにアクセスすると、「数分ですぐに認証ダイアログが再表示される」「特定の通信がエラーで失敗する」といった不具合が確認されました。
実際に通信時のログなどを確認し、どうやら通信が失敗するのはXHRのリクエストだという事がわかりました。 f:id:Armoris:20210914185409j:plain また、エラーが発生しているのはMattermostとの通信で、このサービスは大量のWebSocket通信を行うことから、WebSocketをProxyさせることで問題が起きているのではないかと考えました。(以前Mattermostを構築した際にも挙動がおかしい原因としてWebSocketの問題があった)

解決策1タイムアウトまでの時間を伸ばす

まず初めに解決策として考えたのはNGINXで導入しているDigest Authモジュールでタイムアウトまでの時間を設定することです。

タイムアウトまでの時間はreadmeを確認するとデフォルトで1分になっています。
そこでauth_digest_timeoutを数時間単位で設定しましたが、この方法では今回の問題は解決できませんでした。

解決策2NGINXにWebSocket用の設定を追記

次の解決策としてNGINXの公式リファレンスにある NGINX as a WebSocket Proxy を参考にproxy_http_versionのパラメータを明示的に設定することです。このパラメータを追加すると、NGINXが通信をWebSocketと認識して通信エラーが発生しなくなります。

実際に設定ファイルには以下の1行を追記しました。

proxy_http_version 1.1;

結果はたったこれだけで発生していた問題が解決しました。
この設定を行ってからは通信エラーが発生することなく安定して動いています。

最後に

今回問題があったのはWebSocket通信の部分ですが、これに気づけないとなかなか問題解決に至るのは難しいと思います。また、今回問題があったのはWebSocket通信を頻繁に行うサービスだったと言うこともポイントになっていると思います。
実際に今回のような問題が発生した際に速やかに原因を特定し、解決するためにも運用しているサービスの特徴を把握しておくことは重要だと感じました。