MLIT環境 FW配下アクセス問題の調査
問題の概要
MLIT環境(mlit-eng-ai.hy-create.com)でFW(ファイアウォール/プロキシ)配下からアクセスした場合、チャットが正常に表示されない。
症状
- 症状A(r.minoda型): チャット送信後、
JSON.parse: unexpected character at line 1 column 1エラー。ページ自体は読み込める - 症状B(yu.asano型): ページがOpen WebUIスプラッシュ画面("OI")で停止し、アプリが初期化できない
- 別環境(FW外)からは正常に動作する
- Metro環境(metro-ai.labs.basisconsulting.co.jp)は正常
環境
| 項目 | Metro | MLIT |
|---|---|---|
| ドメイン | metro-ai.labs.basisconsulting.co.jp | mlit-eng-ai.hy-create.com |
| AWS Account | 534036492497 | 745651872545 |
| Profile | h.imura | hy-imura |
| FW有無 | なし | あり(問題発生) |
調査方法
ALBアクセスログの有効化
CoreInfraStackにS3バケットとALBアクセスログ設定を追加し、両環境にデプロイ。
- S3バケット:
{prefix}-v2-alb-logs - ログパス:
alb-logs/{prefix}/AWSLogs/{account}/elasticloadbalancing/ap-northeast-1/YYYY/MM/DD/
# ログ取得コマンド
aws s3 cp s3://mlit-ai-v2-alb-logs/alb-logs/mlit-ai/AWSLogs/745651872545/elasticloadbalancing/ap-northeast-1/$(date +%Y/%m/%d)/ ./logs/ --recursive --profile hy-imura
# 特定IPのログを抽出
gunzip -c logs/*.gz | grep "203.180.239.93" | sort -k2
# WebSocket 101を検索
gunzip -c logs/*.gz | grep "^wss " | sort -k2
# chat/completionsのレスポンスサイズを確認
gunzip -c logs/*.gz | grep "chat/completions" | awk '{print $2, $9"/"$10, $11"B(recv)", $12"B(sent)"}'
調査結果
2026-01-27 r.minoda (IP: 203.180.239.93, FW内, Firefox/macOS)
chat/completionsリクエスト
| JST時刻 | ステータス | レスポンスサイズ | 処理時間 | 判定 |
|---|---|---|---|---|
| 14:14:42 | 200/200 | 14,231B | 0.166s | 正常 |
| 14:16:04 | 200/200 | 11,343B | 0.181s | 正常 |
| 14:43:00 | 200/200 | 246B | 0.108s | 異常 |
| 14:43:31 | 200/200 | 9,818B | 0.167s | 正常 |
| 15:25:16 | 200/200 | 10,463B | 0.551s | 正常 |
| 15:25:35 | 200/200 | 13,093B | 0.168s | 正常 |
WebSocket接続 (wss 101)
| JST時刻 | ステータス | 送信 | 受信 |
|---|---|---|---|
| 14:14:05 | 101/101 | 359B | 6,505B |
| 14:14:06 | 101/101 | 359B | 7,235B |
| 14:14:18 | 101/101 | 359B | 6,781B |
| 14:43:21 | 101/101 | 2,667B | 6,779B |
15:25セッションではWebSocket接続のログなし(接続中でログ未出力 or 接続失敗)。
異常リクエスト
15:25:08 460/- 0B GET /api/v1/models/model/profile/image?id=undefined
15:26:04 460/- 0B GET /api/v1/models/model/profile/image?id=undefined
- 460: ALBが応答する前にクライアント切断
id=undefined: フロントエンドがモデルIDを正しく渡せていない
詳細タイムライン(14:42-14:44 JST)
14:42:48 ページ操作開始(tools, functions, chats取得)
14:42:56 チャット削除
14:43:00 chat/completions → 200 - 246B ★異常(Agenticサーバーに未到達)
14:43:00 get_all_models() 呼び出し
14:43:05 chat/completed → 200(完了通知)
14:43:09 チャット閲覧
14:43:15 チャット削除 → ページ遷移
14:43:20 Ollama接続エラー(host.docker.internal:11434 - 想定内)
14:43:21 WebSocket wss 101 再接続
14:43:21 ページ再読込(GET /)
14:43:27 chat/completions → 200 - 9,818B(正常)
14:43:27 Agentic POST /v1/chat/completions → 200
14:43:29 Agentic Anthropic API → 200
注目点: 14:43:00のchat/completionsは246Bで即座に返却され、Agenticサーバーに到達していない。Open WebUI内部でエラー応答を返している。
2026-01-27 yu.asano (IP: 155.190.49.69, FW内, Edge/Windows)
症状
Open WebUIのスプラッシュ画面("OI"ロゴ)で停止し、アプリケーションが初期化できない。チャット画面に到達できず。
タイムライン
15:54:01 GET / → 302(Cognito認証リダイレクト)
15:54:09 OAuth callback → 302(認証成功)
15:54:10 GET / → 200(ページHTML取得)
15:54:12-17 静的ファイル(loader.js, custom.css, splash.png)→ 全て200
15:54:13-15:55 SvelteKit JSチャンク約150個 → 全て200
15:55:23 _app/version.json → 200
15:55:25 /api/config → 200 (571B)
15:55:26 /manifest.json → 200
15:55:52 /api/version → 200 (207B)
15:56:16 version.json polling → 200
15:57:20 version.json polling → 200
15:58:18 version.json polling → 200
15:59:22 WebSocket wss → 101/101(接続成功)
重要な不在
- chat/completions = 0件(チャット画面に到達できなかった)
- /api/v1/ 系API = 0件(アプリ初期化後のAPI呼び出しなし)
- ページHTML・JSチャンクは全て200で返されているが、SvelteKitアプリが起動しない
プロトコルの差異
| 項目 | r.minoda | yu.asano |
|---|---|---|
| IP | 203.180.239.93 | 155.190.49.69 |
| プロトコル | h2(HTTP/2) | https(HTTP/1.1) |
| ブラウザ | Firefox/macOS | Edge/Windows |
| ページ読み込み | 成功 | 失敗(スプラッシュ停止) |
| chat/completions | 到達・一部破損 | 到達せず |
| WebSocket | 成功 | 成功 |
yu.asanoのFW環境ではHTTP/2がHTTP/1.1にダウングレードされている。これがページ初期化失敗の一因の可能性がある。
推定原因
ALBログ上は全リクエストが200で返されているため、FWが以下のいずれかを行っている:
- JSファイルの中身を破損 - 約150個のJSチャンクのうち1つでも壊れればSvelteKitは初期化に失敗する
- APIレスポンス(/api/config等)の改変 - アプリ初期化に必要なJSON応答が破損
- HTTP/2→HTTP/1.1ダウングレードによる副作用 - 多数の並列リクエストの処理順序やヘッダの変化
ユーザー別障害パターンの比較
| 項目 | r.minoda(症状A) | yu.asano(症状B) |
|---|---|---|
| FW経由IP | 203.180.239.93 | 155.190.49.69 |
| プロトコル | h2 (HTTP/2) | https (HTTP/1.1) |
| ブラウザ/OS | Firefox/macOS | Edge/Windows |
| ページ読み込み | 成功 | 失敗(スプラッシュ停止) |
| JSチャンク | 正常読み込み | ALB上200だが動作せず |
| chat/completions | ALB到達・FWで破損 | 未到達(ページ初期化失敗) |
| WebSocket | 成功(101) | 成功(101) |
| エラー内容 | JSON.parseエラー | アプリ起動しない |
同じFW配下でも、クライアント環境(ブラウザ/OS/プロトコル)により障害パターンが異なる。
結論: FW/プロキシがレスポンスを改変(破損)している
決定的な証拠
15:25 JSTセッションで、r.minodaがFW配下から2回チャットを送信し、両方ともJSON.parseエラーが発生した。 しかしALBログでは:
| JST時刻 | ステータス | レスポンスサイズ | 判定 |
|---|---|---|---|
| 15:25:16 | 200/200 | 10,463B | ALB側は正常 |
| 15:25:35 | 200/200 | 13,093B | ALB側は正常 |
ALB → バックエンド間は完全に正常(200/200、正常なレスポンスサイズ)にもかかわらず、ブラウザでJSON.parseエラーが発生している。
ブラウザ ←→ FW/Proxy ←→ ALB ←→ Open WebUI ←→ Agentic ←→ Anthropic API
↑
ここでレスポンスが改変されている
(ALBログには正常な応答が記録されているが、
ブラウザに届く前にFWが内容を変えている)
これはFW/プロキシがALBからのレスポンスを改変していることの確定的な証拠である。
「切断」ではなく「改変/破損」
FWは接続を切断(ブロック)しているのではない。 レスポンスはブラウザに届いているが、中身が壊れている。
- エラーは
JSON.parse: unexpected character at line 1 column 1= レスポンスの最初の1文字目から既にJSON形式でない - 接続切断であれば、ネットワークエラーやタイムアウトエラーになるはず
- 実際にはレスポンスを受信した上でパースに失敗しているため、FWがレスポンスボディを書き換えていると判断できる
FWが行っていると推定される動作
- SSEストリームのバッファリング:
text/event-streamレスポンスをバッファして一括送信→フォーマット破損 - SSL/TLSインスペクション: HTTPS通信を復号・再暗号化する際にレスポンスボディを改変
- コンテンツフィルタリング: レスポンスにスクリプトやヘッダを注入
- Content-Encodingの不整合: 圧縮/展開処理でデータ破損
2種類の障害パターン
FW配下からのアクセスで、クライアント環境により異なる障害が発生:
- 症状A(r.minoda型): ページは読み込めるが、SSEレスポンス(chat/completions)がFWにより破損。JSON.parseエラー
- 症状B(yu.asano型): ページ自体が初期化できない。JSチャンクまたはAPIレスポンスがFWにより破損し、SvelteKitアプリが起動しない
HTTP/2で接続できるr.minodaはページ初期化に成功するが、HTTP/1.1にダウングレードされるyu.asanoはページ初期化自体に失敗している。
その他の確認事項
- WebSocket (101 Switching Protocols) はFW経由でも成功する - FWはWebSocketをブロックしていない(両ユーザーとも)
- Agenticサーバー→Anthropic APIも正常 - バックエンドに到達したリクエストは全て成功
- Metro環境は完全に正常 - 27件のWebSocket 101、全chat/completions正常
- 14:43:00の246B応答: Open WebUI内部でAgenticに転送せず即座にエラー応答を返したケースも1件あり(27分間空白後の初回リクエスト)
- HTTP/2 vs HTTP/1.1: FWがHTTP/2→HTTP/1.1にダウングレードするケースがあり、これが障害の深刻度に影響
追加確認事項
ブラウザDevToolsでの確認(FWの改変内容の特定)
FW配下からアクセスし、ブラウザのDevTools > Networkタブで以下を確認すると、FWが具体的に何をしているかが判明する:
r.minoda(症状A: SSE破損)向け
chat/completionsリクエストの Response タブ(先頭数行)- 何が返ってきているか- Response Headers(特に
Content-Type,Transfer-Encoding,Content-Encoding)- FWが書き換えていないか - FWが追加したヘッダの有無(
Via,X-Forwarded-For等)
yu.asano(症状B: ページ初期化失敗)向け
- Console タブのエラーメッセージ(JavaScriptエラーがあるはず)
- Network タブで各JSチャンクの Response ボディが正しいJavaScriptか確認
/api/configのレスポンスボディが正しいJSONか確認- Response Headers でFWが
Content-Encodingを書き換えていないか確認
参考: Metro環境との構成差異
CDKコード・ECS設定は共通(EnvironmentConfigの値のみ異なる)。
インフラレベルの差異はなく、ネットワーク経路(FWの有無)のみが異なる。
対策案
A. サーバー側対策(実装済み / 実装可能)
→ 詳細は sse-streaming-fix.md
| 対策 | 状態 | 効果 |
|---|---|---|
レスポンスヘッダー強化(X-Accel-Buffering: no 等) |
実装済み | FW/Proxyのバッファリング抑制 |
| チャンクサイズ制御(50文字分割) | 実装済み | バッファリング時の影響を最小化 |
| Keep-alive間隔短縮(5秒→1秒) | 実装済み | 接続維持の安定化 |
| SSEイベントID追加 | 実装済み | 順序保証 |
B. FW側対策(FW管理者への依頼が必要)
text/event-streamレスポンスのバッファリング無効化mlit-eng-ai.hy-create.comをSSLインスペクション除外対象に追加- WebSocket/SSE接続のアイドルタイムアウトを300秒以上に設定
text/event-streamをWAF検査対象から除外
C. アプリケーション側の回避策
| 方法 | 概要 | リスク |
|---|---|---|
| WebSocket無効化 | ENABLE_WEBSOCKET_SUPPORT=false |
Open WebUI公式は非推奨 |
| SSE → Polling切替 | Open WebUIの設定で切替可能であれば | リアルタイム性低下 |
| レスポンスの非ストリーミング化 | ストリーミングをOFFにする | UX低下(一括表示) |
関連ドキュメント
- sse-streaming-fix.md - SSEストリーミング修正の詳細
- ../DEPLOY_METRO.md - Metro環境デプロイガイド
- ../DEPLOY.MLIT.md - MLIT環境デプロイガイド
調査日
- 2026-01-27(r.minoda、yu.asano のALBログ分析)
- 2026-01-28(yu.asano の分析結果追記)