リバースプロキシを再起動すると、1つのセルフホストアプリですべてのセッションが無効になるのはなぜですか?

エヴァ・ウォン は テクニカルライター であり ZimaSpaceの常駐ティンカーでもあります。 生涯のオタクであり、 ホームラボとオープンソースソフトウェアに情熱を持っています。彼女は複雑な技術的概念をわかりやすく、 実践的なガイドに翻訳することを専門としています。エヴァはセルフホスティングは楽しくあるべきで、怖がるものではないと信じています。彼女のチュートリアルを通じて、コミュニティが ハードウェアのセットアップを解明する手助けをしています。初めてのNAS構築からDockerコンテナの習得まで。

リバースプロキシの再起動によってすべてのユーザーがログアウトされるのは、そのアプリケーションが使用するセッション状態も同時に変更、失失、または別の場所へルーティングされた場合だけです。

基本的なプロキシは通常、アプリケーションのセッションを管理するのではなくCookieを転送するため、プロキシだけを再起動しても、すべてのログインが無効になることはありません。実際の原因は、認証ゲートウェイの再起動、Cookie署名シークレットの再生成、インメモリセッションキャッシュ、バックエンドレプリカの変更、またはプロキシとともにアプリを再起動するComposeの依存関係である可能性があります。Cookie属性を変更したり、ユーザーに再ログインを強制したりする前に、セッションを発行して検証しているコンポーネントを特定してください。

プロキシとともに再起動したサービスを確認する

制御されたプロキシの再起動を1回行う前後で、リバースプロキシ、認証サービス、アプリケーション、キャッシュ、データベースについて、コンテナID、開始時刻、再起動回数、ヘルスイベント、ログを記録します。

Docker Composeでは、依存関係の再起動伝播が明示的に設定されている場合、依存サービスも再起動できます。公式の起動順序に関するガイダンスでは、プロキシの再起動と説明されたコマンドによって、認証コンテナやアプリケーションコンテナも置き換えまたは再起動される理由が説明されています。

新しい開始時刻になったのがプロキシだけなら、プロキシが管理する認証、ルーティング、Cookieに注目します。アプリ、キャッシュ、認証ゲートウェイも再起動している場合は、まずそれらのセッション永続化とシークレットを調べてください。

ログインCookieを発行した層を特定する

再起動する前に、Cookie名、ドメイン、パス、Secure、HttpOnly、SameSite、有効期限、そしてCookieを設定しているのがアプリケーションか認証ゲートウェイかを記録します。

MDNでは、Cookieのスコープと属性によって、ブラウザーがCookieを送信する場所が決まると説明されています。ただし、これらの属性から、どのバックエンドが値を検証するかを判断することはできません。

ログインリクエストと、再起動後の最初のリクエストのレスポンスヘッダーを比較します。Cookieがない場合はブラウザーのスコープに関する問題です。変更されていないCookieをサーバーが拒否する場合は、状態の消失、キーの変更、または別のバックエンドが原因である可能性があります。

認証ゲートウェイがセッションシークレットを再生成していないか確認する

認証ゲートウェイのシークレットの取得元、ファイルマウント、環境変数、コンテナの再作成、生成された設定を確認します。シークレット自体を公開せずに、再起動前後で値の取得元を比較してください。

Autheliaのドキュメントでは、セッションシークレットによって保存されたセッションデータが暗号化されると説明されています。そのため、シークレットが変更または失われると、以前に作成されたセッションをサービスが読み取れなくなります。

セッションシークレットは、コンテナの起動ごとに生成するのではなく、永続的なシークレットファイルまたは管理対象のシークレットストアに保存します。ローテーションは、文書化したログアウト期間を設けたうえで、計画的に行ってください。

インメモリセッションストアを除外する

アプリケーションがセッションをプロセスメモリ、ローカルキャッシュ、Redis、データベース、または署名付きクライアントCookieのどこに保存しているかを確認します。セッションストアのプロセス稼働時間と、ログアウトが発生した時刻を比較してください。

Djangoでは、キャッシュのみを使用するセッションバックエンドは、キャッシュの再起動や追い出しによってセッションデータを失う可能性があり、セッションデータが消えるとユーザーがログアウトされると警告しています。

プロキシスタックにキャッシュコンテナが含まれている場合、そのスタックを再起動すると、アプリケーションコンテナが稼働し続けていてもセッションが消去される可能性があります。ログイン状態の継続が重要な場合は、永続的なキャッシュ構成、またはデータベースを使用したフォールバックを採用してください。

再起動前後でアプリケーションの署名キーを比較する

アプリケーションのセッション署名キーまたは暗号化キーの取得元を調べ、そのキーが永続化されているか、想定したenvファイルから読み込まれているか、起動時に生成されていないかを確認します。

FlaskはSECRET_KEYでセッションCookieに署名します。そのため、このキーを置き換えると、ブラウザーがCookieを送信し続けていても、既存の署名付きCookieは無効になります。

無関係なアプリケーション間で1つのシークレットを共有して解決しようとしてはいけません。各アプリに安定した固有のシークレットを設定し、バックアップが必須の構成として保護し、イメージを再作成しても維持されることを確認してください。

スティッキーセッションとバックエンドレプリカの変更を確認する

バックエンドのレプリカ、それぞれのセッションストア、プロキシのロードバランシングポリシーを一覧化します。同じユーザーのリクエストが別のレプリカに到達してもログイン状態を維持できるかテストしてください。

Traefikのスティッキーセッション構成では、クライアントを1つのバックエンドに戻すようルーティングできます。しかし、レプリカが状態を共有しておらず、再起動によって選択されるエンドポイントが変わると、ユーザーはセッションを失う可能性があります。

スティッキーセッションは、ローカルなセッションストアが誤っていることを隠してしまう場合があります。複数のアプリレプリカをプロキシやバックエンドの置き換え後も稼働させる場合は、共有された永続的なセッション状態を優先してください。

安定した構成で1つのテストアカウントを使って再現する

構成のスナップショットを作成し、使い捨てのアカウントでログインしてセッション識別子を記録します。その後、プロキシだけを再起動し、他のコンポーネントを再起動する前に同じリクエストをテストしてください。

ZimaSpaceの記事「自宅ネットワーク外だけで発生するログインループ」では、パスに依存するログイン障害を扱っています。この記事では、再起動後にすでに有効なセッションが同時に無効化される問題に焦点を当てています。

プロキシだけを再起動してもセッションが維持され、認証サービスやアプリケーションを意図的に再起動した場合も安定したシークレットと永続的な状態が使用され、すべてのレプリカが同じ有効なログインを受け入れられれば、問題は解決しています。

よくある質問

リバースプロキシ自体がユーザーセッションを保存することはありますか?

認証ゲートウェイ、アクセスミドルウェア、またはスティッキーセッション機能を含む場合はあります。単純な転送プロキシは通常、アプリケーションのログインセッションを管理しません。

Redisを再起動すると必ずユーザーはログアウトされますか?

セッションがRedisだけに存在し、そのデータが永続化または復元されない場合に限られます。データベースベースのセッションや署名付きCookieを使用するアプリケーションでは、動作が異なります。

再起動によるログアウトを止めるためにCookieの有効期間を延ばすべきですか?

いいえ。Cookieの有効期間を延ばしても、署名キーが変更されたり、サーバー側のセッションレコードが消失したりすれば無効になります。まず永続化とシークレットの安定性を修正してください。

サポートとヒント

もっと読む

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.