非表示連発案件

さくらインターネット × Laravel 12:画像が出ない?Mixed Content の解決メモ

さくらインターネットに Laravel 12 をデプロイ後、画像が表示されない/JS・CSSが効かない……。原因は Mixed Content(http/https の混在)でした。AppServiceProvider と .htaccess、APP_URL の3点で解決する手順をまとめます。

この記事はこんな人におすすめ

  • さくらインターネット(スタンダード)に Laravel 12 を置いたら表示が崩れた

  • 画像が出ない/JSが動かない/CSSが反映されない といった症状に困っている

  • ブラウザのデベロッパーツールで Mixed Content 警告が出ている

参考:以前の「Node.js なしでのデプロイ手順」も併せてどうぞ
https://itbl.online/blogs/tags/laravel-no-hanashi-4318


先に結論(TL;DR)

Mixed Content は 「URL生成のスキーム(Laravel)」「実アクセスの経路(Webサーバ)」 の両方を整えると解消します。

  1. Laravel が生成する URL を https に固定AppServiceProvider

  2. HTTP で来たアクセスを Apache で 301 リダイレクト.htaccess

  3. .envAPP_URLhttps:// にする(メール・CLI での URL 乱れ防止)


症状の典型例と原因

  • 画像が表示されない / JS が動かない / CSS が反映されない
    → ページが https:// なのに、内部で http:// のリソースを参照していると Mixed Content でブロックされます。
    例:<img src="http://example.com/image.jpg">

この問題は レンタルサーバー特有ではありません
TLS をどこで終端するか(Webサーバ/CDN/LB)、および Laravel 側が URL をどう生成するか の組み合わせ次第で、どの環境でも起こり得ます。
ここでは さくらのスタンダード で実際に効いた手順を書きます。


手順①:URL 生成を https に固定(Laravel 側)

asset()route() が http を吐かないよう、AppServiceProvider で https を強制します。

// app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        //
    }

    public function boot(): void
    {
        // 本番環境では常に https で URL 生成
        if (app()->environment('production')) {
            URL::forceScheme('https'); // asset(), route() などが https になる
        }
    }
}

手順②:HTTP → HTTPS を 301 リダイレクト(Apache 側)

public/.htaccess に追記して、実アクセスを確実に https へ寄せます。

# public/.htaccess
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

役割の違い:

  • .htaccess実アクセス を https に統一する

  • forceScheme()Laravel が生成する URL を https に統一する
    どちらか一方だけだと、再発の余地が残ります。


手順③:.envAPP_URL を https に

リクエストがない文脈(キュー、バッチ、メール本文のリンク生成など)では APP_URL が使われます。

APP_ENV=production
APP_URL=https://あなたのドメイン

動作確認(診断ルート)

一時的にルートを生やすと切り分けがスムーズです。作業後に削除推奨。

// routes/web.php
Route::get('/diag', function (\Illuminate\Http\Request $r) {
    return [
        'scheme'   => $r->getScheme(),  // 期待: https
        'isSecure' => $r->isSecure(),   // 期待: true
        'url'      => url('/'),         // 期待: https://... が返る
    ];
});

実験メモ(VPS での比較)

切り分けのために ConoHa VPS を一時レンタルし、Docker Compose 一式を上げてテストしたところ、Mixed Content は再現せず
→ Laravel 自体の不具合ではなく、公開環境側の設定不足(URL生成&リダイレクト)が原因と判断できました。


よくある落とし穴(チェックリスト)

  • APP_URL が http のまま(メールや CLI 生成 URL が http に)

  • 外部リソース(画像/CDN/JS)が http 固定(参照先も https に統一)

  • HSTS 未導入(本番は Strict-Transport-Security の検討も可。戻せないので段階的に)

  • キャッシュが残っている(CDN やブラウザキャッシュで旧設定が見える)


他環境の場合は?

  • Nginx(VPS/Docker)で TLS 終端:Nginx 側で 80→443 を 301、Laravel は本記事と同様で OK。

  • CDN / ロードバランサで TLS 終端X-Forwarded-Proto を解釈する必要があるため、Laravel の Trusted Proxies 設定を有効に($proxies='*' or CIDR 指定)。
    さくらの共用(Apache 直結)では通常 不要 です。


まとめ

  • Mixed Content は 「URL 生成」「実アクセスの経路」 の両輪を揃えると解決。

  • さくら(スタンダード)では、forceScheme('https') + .htaccess の 301 + APP_URL=https://... で安定稼働しました。

  • 構成が変わる(CDN/LB 導入など)場合は Trusted Proxies も検討しましょう。

まおち
投稿者:まおち 投稿日:2025年8月23日
ITで飯を食っている。
日々何らかのエラーと戦っている。
しかし、レベルアップが遅い。
レベルアップが遅いのは勇者の特徴だと勘違いしている節がある。
無料アプリのご案内
無料アプリのご案内

投稿者一覧

# 関連記事