📑
laravel12 + vite(inertia.js他) 環境下におけるmixed content
<!-- ページ自体は https://example.com なのに -->
<script src="http://example.com/script.js"></script>
<img src="http://example.com/image.jpg" />
これ。この状況はhttps proxy下でlaravelを包んだとき、とくにviteの環境で簡単に発生する。たとえばdev.test.catatsumuri.org
でやってみるなら
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName dev.test.catatsumuri.org
ServerAdmin webmaster@localhost
# リバースプロキシ設定(Laravelの開発サーバへ)
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/dev.test.catatsumuri.org/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/dev.test.catatsumuri.org/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
こういう状況でartisan serve
されてると
こんな感じになる。
これのややこしいのはlaravel側ではエラーにならないのでブラウザーの開発ツール的なのを起動しないと何がおきてるのかよくわかり辛いということだ(まっしろになってる典型的なやつ)
解決法1: 強制https
これはapp/Providers/AppServiceProvider.phpに以下の設定を行う
app/Providers/AppServiceProvider.php
@@ -20,5 +20,6 @@ public function register(): void
public function boot(): void
{
//
+ \URL::forceScheme('https');
}
}
これは問答無用でhttpsにしてしまう方法であり、まあ使えなくはないが非常にローテクな感じがある。このままだと当然ローカル開発も全てhttpsになるし、このファイルに関しては大抵commit対象になるはずなので非常に面倒くさいことになるはずだ。ifでグルグル分岐するとかいうので回避できなくもないかもしれないが、いずれにせよ非推奨ではある。しかし、簡単な手法なので最初に一度試してみる価値はあるかもしれない。
解決法2: URLを決め打ちする
これはproduction環境では非常に有効な手法であるし、むしろそのようにしておきたい。これに関しては
.env
APP_URL=https://dev.test.catatsumuri.org
だけではだめで
.env
ASSET_URL=https://dev.test.catatsumuri.org
も併せて指定する必要がある。この後
npm run build
することでassetsのurlも固定される。
解決法3: trustedProxyする
bootstrap/app.php
@@ -6,6 +6,7 @@
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
+use Illuminate\Http\Request;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
@@ -14,6 +15,15 @@
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
+ $middleware->trustProxies(
+ at: '*', // または ['127.0.0.1'] など具体的なIP
+ headers: Request::HEADER_X_FORWARDED_FOR |
+ Request::HEADER_X_FORWARDED_HOST |
+ Request::HEADER_X_FORWARDED_PORT |
+ Request::HEADER_X_FORWARDED_PROTO |
+ Request::HEADER_X_FORWARDED_AWS_ELB
+ );
+
$middleware->encryptCookies(except: ['appearance', 'sidebar_state']);
こんな感じでヘッダを見て通すというのを書く。apache2であれば
<VirtualHost *:443>
ServerName dev.test.catatsumuri.org
ServerAdmin webmaster@localhost
# リバースプロキシ設定(Laravelの開発サーバへ)
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
RequestHeader set X-Forwarded-Proto "https" # これと
RequestHeader set X-Forwarded-Port "443" # これ
# ...
というのを書いておけばいい。環境によっては便利だがサーバー設定が必要なこともあるし、これもコードが動いてしまう。productionでは2の方法で完全に解決できるのでそっちがおすすめ。
Discussion