FilamentPHPを使っていて、本番環境のみファイルアップロードが401エラーになる現象に遭遇したため、備忘録として原因と対策を記事に書き残しておきます。
発生していた問題
本番環境(Nginxリバースプロキシ + Docker構成など)において、Filamentのファイルアップロード(Livewireの一時URL発行)を実行すると、ブラウザ上ではHTTPSでリクエストしているにもかかわらず、401 Unauthorized が返される。※ローカル環境(HTTP)では問題なく動作する。
原因:署名付きURLの「検証失敗」
Filament(Livewire)のアップロード機能は、セキュリティのために「署名付きURL(Signed URL)」を利用します。この署名は、以下の要素を組み合わせて生成されます。
- プロトコル(http / https)
- ホスト名(ドメイン)
- パス
- 有効期限
なぜ401になるのか?
リバースプロキシ構成では、ブラウザ ↔ Nginx 間は HTTPS ですが、Nginx ↔ PHP(Docker) 間は HTTP で通信されることが一般的です。
このとき、Laravel側でプロキシの信頼設定が正しく行われていないと、Laravelは Nginx が送ってくれる X-Forwarded-Proto: https というヘッダーを無視してしまいます。
結果として:
- ブラウザ側:
https://...の署名でリクエストを送る。 - Laravel側:自分へのアクセスを
http://...だと誤認し、HTTPベースで署名を再計算する。 - 判定:ハッシュ値が一致しないため、「署名改ざん」とみなされ 401エラー 。
となります。
解決策:TrustProxiesの設定
Laravel 11以降では、bootstrap/app.php にてプロキシを信頼する設定を追加します。
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware): void {
// すべてのプロキシを信頼し、X-Forwarded-* ヘッダーを有効化する
$middleware->trustProxies(at: '*');
})
この設定により、Laravelは「Nginxからの X-Forwarded-Proto ヘッダー」を正しく読み取り、自分へのアクセスが HTTPS であることを認識できるようになります。その結果、サーバー側で計算される署名がブラウザのものと一致し、正常にアップロードが可能になります。
まとめ
- 本番環境でだけ401が出るなら「署名(Signature)」の不一致を疑う。
- プロキシ環境下では、PHP側が「今HTTPSで通信している」と正しく認識できているかが重要。
TrustProxiesの設定を適切に行い、ヘッダーの信頼パスを通すことで解決する。
まずは、ブラウザの検証ツールを使ってどのようなステータスコードが返ってきているかをきちんと見ましょう。401エラーなら署名URLの不一致の可能性が高いです。
補足ポイント
AppServiceProviderでのURL::forceScheme('https')も併用すると、生成されるURLが確実にHTTPSになるためより安全。- Nginx側で
proxy_set_header X-Forwarded-Proto https;が設定されていることも前提条件となる。
参考
以下を参考にしていました。
コメントを投稿