9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel12】メンテナンスモード

Posted at

はじめに

Laravelのメンテナンスモードの挙動を確認した際のメモを備忘録として残します。

開発環境

  • Laravel12
  • PHP8.4

内容

  • メンテナンスモードのコマンド実行
php artisan down

スクリーンショット 2025-05-22 11.10.54.png

  • storage/framework/downというJSONファイルが作成される
{
    "except": [],
    "redirect": null,
    "retry": null,
    "refresh": null,
    "secret": null,
    "status": 503,
    "template": null
}
フィールド 意味
except メンテナンスモード中でも通常の処理を許可するルートの URI パターン一覧。
Laravel 標準の down コマンドでは設定できない。PreventRequestsDuringMaintenance ミドルウェアをオーバーライドし、その $except プロパティにパスを追加するとここに反映される。デフォルトは空配列。
redirect メンテナンス中の全リクエストをリダイレクトする先 URI。
php artisan down --redirect=/ のように指定すると、すべてのアクセスが /{} にリダイレクトされる。(artisan.page)
retry HTTP レスポンスヘッダ Retry-After にセットする秒数。〈例:--retry=60〉。ほとんどのブラウザは無視しますが、API クライアントなどには伝わるらしい。(Laravel)
refresh HTML レスポンスに Refresh ヘッダをセットし、指定秒後に自動リロードを指示。〈例:--refresh=15〉。(Laravel)
secret メンテバイパス用のトークン文字列。例として --secret="abc123" とすると、https://your-app/abc123 に一度アクセスすることでバイパスクッキーが発行され、以降通常モードで閲覧できる。(Laravel)
status HTTP ステータスコード。デフォルトは 503 ですが、--status=402 のように変更可能(あまり使われないらしい)。(artisan.page)
template プリレンダリング済みビュー名。〈例:--render="errors::503"〉を指定すると、そのビューを依存ロード前にキャッシュし、極限状態でも直接返す。値はビューの「名前」文字列。(Laravel)

PreventRequestsDuringMaintenanceの役割

  • アプリ全体のグローバルミドルウェアスタック

  • Laravel9 では app/Http/Kernel.php

  • Laravel11 以降はbootstrap/app.phpwithMiddleware()に登録

  • vendorの中のグローバルのところにある

vendor/laravel/framework/src/Illuminate/Foundation/Configuration/Middleware.php
    public function getGlobalMiddleware()
    {
        $middleware = $this->global ?: array_values(array_filter([
            \Illuminate\Http\Middleware\ValidatePathEncoding::class,
            \Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class,
            $this->trustHosts ? \Illuminate\Http\Middleware\TrustHosts::class : null,
            \Illuminate\Http\Middleware\TrustProxies::class,
            \Illuminate\Http\Middleware\HandleCors::class,
            \Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
            \Illuminate\Http\Middleware\ValidatePostSize::class,
            \Illuminate\Foundation\Http\Middleware\TrimStrings::class,
            \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        ]));
        ()
  • 中身を見てみるとこんな感じになっているみたい
### PreventRequestsDuringMaintenance クラスの

このミドルウェアは「アプリがメンテモード中か」を判定し、  
- 許可パス(`except`)か、  
- シークレットトークン/クッキーによるバイパスか  
…のいずれにも該当しなければ 503 応答を返す。

主な処理フロー(抜粋)

public function handle($request, Closure $next)
{
    // **(1) 除外パスチェック**
    if ($this->inExceptArray($request)) {
        return $next($request);
    }

    // **(2) メンテモード判定**
    if ($this->app->maintenanceMode()->active()) {
        $data = $this->app->maintenanceMode()->data();

        // **(3) シークレット URL バイパス**
        if (isset($data['secret']) && $request->path() === $data['secret']) {
            return $this->bypassResponse($data['secret']);
        }

        // **(4) バイパスクッキー許可**
        if ($this->hasValidBypassCookie($request, $data)) {
            return $next($request);
        }

        // **(5) リダイレクト/テンプレート応答**
        if (isset($data['redirect'])) {
            return redirect($data['redirect']);
        }
        if (isset($data['template'])) {
            return response($data['template'], $data['status'] ?? 503, $this->getHeaders($data));
        }

        // **(6) それ以外 → 503 例外**
        throw new HttpException($data['status'] ?? 503, 'Service Unavailable', null, $this->getHeaders($data));
    }

    // **(7) 通常モード → 通常処理へ**
    return $next($request);
}
  • リクエストの流れとしてはこんなイメージ?
┌── HTTP リクエスト受信
│
│─┬─ ミドルウェア起動順 ──┬─ PreventRequestsDuringMaintenance がヒット?
│  │                       │
│  │                       ├─ いいえ → 次のミドルウェアへ
│  │                       └─ はい →
│  │                           ├─ メンテ状態か?
│  │                           │   ├─ いいえ → 次へ
│  │                           │   └─ はい →
│  │                           │       ├─ except URI か?
│  │                           ├─ secret パラメータ or IP 許可か?
│  │                           └─ いずれも該当しない → 503 応答
│  │
│  └─…(他のミドルウェア/ルーティング処理)…
│
└── アプリケーション処理

注意点

  • 以下の書き方をすると、現在のグローバルミドルウェアスタックをまるごと上書きしてしまいここに記載ないミドルウェアが効かなくなるので注意
bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->use([
        // ここに列挙したものだけが新しいグローバルスタックになる
        TrustProxies::class,
        HandleCors::class,
    ]);
});

  • 追加で設定したい場合は以下の書き方をする
bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    // 既存の全ミドルウェアを保持したまま、末尾に追加
    $middleware->append(\App\Http\Middleware\CustomMiddleware::class);
});

  • 複数サーバでのメンテナンスモードするときは、.envでできるみたい

Laravelはデフォルトで、ファイルベースのシステムを使ってアプリケーションがメンテナンスモードかを判断します。つまり、メンテナンスモードを有効にするには、アプリケーションをホストしている各サーバ上でphp artisan downコマンドを実行する必要があります。
あるいは、Laravelはメンテナンスモードをキャッシュベースで処理する方法を提供しています。この方法では、ただ1つのサーバ上で、php artisan downコマンドを実行するだけです。この方法を使用するには、アプリケーションの.envファイルでメンテナンスモード変数を変更します。すべてのサーバからアクセス可能なキャッシュstoreを選択します。これにより、メンテナンスモードの状態が、すべてのサーバで一貫して維持されるようになります。

APP_MAINTENANCE_DRIVER=cache
APP_MAINTENANCE_STORE=database

ドキュメントより引用

まとめ

Laravelのメンテナンスモードの挙動を確認した際のメモです。

参考記事

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?