Maîtriser le Mode Maintenance sous Laravel , Livewire et Inertia

Par Devinsto
Posté le 1 janvier 2026
Mis à jour le 3 novembre 2026
29 min de lecture
182 vues

Dans une application Laravel moderne utilisant Inertia.js et Vue.js, la gestion des erreurs et du mode maintenance peut être délicate.

Vous avez lancé un petit php artisan down pour mettre à jour votre application, et là, c'est le drame ? Au lieu de votre superbe page de maintenance personnalisée, vos visiteurs tombent sur un message tout moche "Service Unavailable" ou, pire, une page blanche ?

Pas de panique ! C'est un grand classique quand on utilise le combo Laravel 12 et Inertia.js. On dirait que ces deux-là ont parfois du mal à décider qui doit répondre en premier. Vous voulez savoir comment remettre de l'ordre dans tout ça ? C'est parti !

Dans ce guide, nous allons voir comment :

  • Comprendre pourquoi la page 503 ne s'affiche pas sur une stack Inertia.

  • Configurer l'ordre des middlewares pour éviter les conflits.

  • Personnaliser la page de maintenance pour qu'elle reste cohérente avec le design de votre app.

  • Gérer correctement le cycle de vie de la maintenance (up et down).

Prérequis : Pourquoi activer la maintenance ?

Avant de rentrer dans le code, rappelez-vous que le mode Maintenance (503) est indispensable pour la stabilité de votre application. Vous devez l'activer dans les situations suivantes :

  1. Migrations de base de données lourdes : Lorsque vous modifiez la structure de la base (ajout de colonnes, changement de type de données), il est crucial d'arrêter l'accès pour éviter que les utilisateurs interagissent avec des tables qui sont en train d'être modifiées, ce qui causerait des erreurs critiques.

  2. Mise à jour des dépendances (Composer) : Après un composer update ou composer install, il est préférable de couper l'accès le temps que les fichiers de cache (Bootstrap, Config, Views) se régénèrent.

  3. Maintenance du serveur : Si vous redémarrez le serveur ou la base de données, vous devez activer le mode maintenance pour empêcher toute tentative de connexion pendant que les services reprennent.

  4. Patchs de sécurité : Si vous devez corriger une faille critique, isolez votre site immédiatement en maintenance, appliquez le correctif, puis rétablissez le service.

En résumé : ne mettez jamais votre application en production en mode maintenance sans avoir une belle page 503 à afficher, sinon vos clients risquent de paniquer ou de penser que votre site a été piraté !


Le problème : Pourquoi ma page 503 ne s'affiche-t-elle pas ?

Ce problème vient très probablement de l'ordre d'exécution des middlewares dans votre fichier app/bootstrap/app.php.

Voici ce qui se passe en coulisses :

  1. Lorsque vous lancez php artisan down, Laravel active le middleware PreventRequestsDuringMaintenance.

  2. Ce middleware doit normalement servir une page HTML brute (votre fichier 503.blade.php).

  3. Cependant, dans une application Inertia, le middleware HandleInertiaRequests tente d'intercepter toutes les requêtes pour vérifier si c'est une requête AJAX (X-Inertia).

  4. Si HandleInertiaRequests est placé avant le middleware de maintenance, il va essayer d'intercepter la réponse, causant un conflit ou une page blanche, au lieu de laisser passer votre HTML simple.

La solution est donc de forcer Laravel à prioriser la maintenance sur Inertia.

Étape 1 : Publier les vues d'erreurs de Laravel

Assurez-vous que les fichiers de vues d'erreurs existent bien dans votre projet. Exécutez cette commande à la racine :

php artisan vendor:publish --tag=laravel-errors

Étape 2 : Configurer l'ordre des Middlewares (La correction cruciale)

C'est ici que se situe la solution. Ouvrez votre fichier .app/bootstrap/app.php

Deux corrections sont nécessaires : 1

  1. Importer la classe .PreventRequestsDuringMaintenance

  2. Placer ce middleware avant . HandleInertiaRequests

Voici la version corrigée de :app/bootstrap/app.php

<?php

declare(strict_types=1);

use App\Http\Middleware\HandleAppearance;
use App\Http\Middleware\HandleInertiaRequests;
use App\Http\Middleware\RoleMiddleware;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
use Illuminate\Http\Request;
// CORRECTION 1 : Importer le middleware de maintenance
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
use Inertia\Inertia;
use Symfony\Component\HttpKernel\Exception\HttpException;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->encryptCookies(except: ['appearance', 'sidebar_state']);
        $middleware->alias([
            'role' => RoleMiddleware::class,
        ]);

        $middleware->web(append: [
            // CORRECTION 2 : Ajouter le middleware de maintenance EN PREMIER
            // Cela assure qu'il coupe l'accès avant qu'Inertia n'essaie de traiter la requête
            PreventRequestsDuringMaintenance::class,
            HandleAppearance::class,
            HandleInertiaRequests::class,
            AddLinkHeadersForPreloadedAssets::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        // Intercepter toutes les exceptions HTTP pour les rendre avec Inertia
        $exceptions->render(function (HttpException $e, Request $request) {
            // Vérifier si la requête attend une réponse Inertia (XHR)
            $inertiaRequest = $request->headers->get('X-Inertia');

            // Si c'est une requête Inertia, renvoyer une réponse JSON avec le bon code d'erreur
            if ($inertiaRequest) {
                return response()->json([
                    'component' => 'Errors/Error',
                    'props' => [
                        'status' => $e->getStatusCode(),
                    ],
                    'url' => $request->url(),
                    'version' => config('inertia.version'),
                ], $e->getStatusCode());
            }

            // Sinon, renvoyer une réponse Inertia normale
            return Inertia::render('Errors/Error', [
                'status' => $e->getStatusCode(),
            ])->toResponse($request)->setStatusCode($e->getStatusCode());
        });

        // Gérer spécifiquement l'erreur 404
        $exceptions->render(function (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e, Request $request) {
            $inertiaRequest = $request->headers->get('X-Inertia');

            if ($inertiaRequest) {
                return response()->json([
                    'component' => 'Errors/Error',
                    'props' => [
                        'status' => 404,
                    ],
                    'url' => $request->url(),
                    'version' => config('inertia.version'),
                ], 404);
            }

            return Inertia::render('Errors/Error', [
                'status' => 404,
            ])->toResponse($request)->setStatusCode(404);
        });
    })->create();

Étape

Maintenant que le routeur fonctionne, vous pouvez créer votre propre design. Créez ou modifiez le fichier `resources/viewsresources/views/errors/503.blade.php.

Voici un exemple de conception (utilisé par exemple pour informer un client que son système est en maintenance) utilisant le thème de couleurs de votre application :

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Service en attente de mise à jour</title>
    <style>
        /* ... Insérez ici le CSS complet fourni dans votre prompt ... */
        :root {
            /* Mode Clair */
            --background: hsl(330 100% 98.4314%);
            --foreground: hsl(0, 0%, 0%);
            --card: hsl(0 0% 100%);
            --card-foreground: hsl(326.281 71.5976% 33.1373%);
            --primary: #dc127b;
            --primary-foreground: hsl(0 0% 100%);
            --secondary: #f7b540;
            --muted-foreground: hsl(329.0476 50% 50.5882%);
            --border: hsl(326.7857 100% 89.0196%);
            --font-sans: 'Poppins', sans-serif;
            --radius: 0.75rem;
            --shadow-md: 0px 3px 0px 0px hsl(330 70% 30% / 0.18), 0px 2px 4px -1px hsl(330 70% 30% / 0.18);
        }

        @media (prefers-color-scheme: dark) {
            :root {
                /* Mode Sombre */
                --background: hsl(280.8 58.1395% 8.4314%);
                --foreground: hsl(300 100% 85.098%);
                --card: hsl(280 45.2055% 14.3137%);
                --card-foreground: hsl(300 100% 85.098%);
                --primary: #ef1184;
                --primary-foreground: hsl(300 65.5172% 5.6863%);
                --secondary: hsl(288.5106 42.3423% 21.7647%);
                --muted-foreground: hsl(300 52.8736% 65.8824%);
                --border: hsl(281.4706 55.7377% 23.9216%);
                --font-sans: 'Quicksand', sans-serif;
                --shadow-md: 0px 3px 0px 0px hsl(300 80% 50% / 0.18), 0px 2px 4px -1px hsl(300 80% 50% / 0.18);
            }
        }

        body {
            background-color: var(--background);
            color: var(--foreground);
            font-family: var(--font-sans);
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            margin: 0;
            padding: 20px;
            box-sizing: border-box;
        }

        .card {
            max-width: 550px;
            width: 100%;
            background: var(--card);
            padding: 3.5rem 2.5rem;
            border-radius: var(--radius);
            border: 1px solid var(--border);
            box-shadow: var(--shadow-md);
            text-align: center;
        }

        h1 {
            font-family: 'Playfair Display', serif;
            color: var(--card-foreground);
            font-size: 2.25rem;
            margin-bottom: 1.5rem;
            line-height: 1.2;
        }

        p {
            color: var(--muted-foreground);
            line-height: 1.8;
            font-size: 1.1rem;
            margin-bottom: 2.5rem;
        }

        strong {
            color: var(--primary);
            font-weight: 600;
        }

        .notice {
            background: hsl(0 0% 0% / 0.04);
            padding: 1rem;
            border-radius: 0.5rem;
            font-size: 0.9rem;
            color: var(--muted-foreground);
            border-left: 3px solid var(--secondary);
        }

        @media (max-width: 480px) {
            .card { padding: 2rem 1.5rem; }
            h1 { font-size: 1.75rem; }
        }
    </style>
</head>
<body>

<div class="card">
    <h1>Service en attente de mise à jour</h1>
    
    <p>
        L'accès à la plateforme nécessite une <strong>actualisation administrative</strong>. 
        Pour garantir la continuité du service et retrouver l'intégralité des fonctionnalités, la régularisation de la situation est requise dès que possible.
    </p>

    <div class="notice">
        Le service sera rétabli de façon automatique.
    </div>
</div>

<script>
    // Détection automatique du Dark Mode pour le visiteur
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
        document.documentElement.classList.add('dark');
    }
</script>
</body>
</html>

Étape 4 : Activer le mode

Une fois les fichiers en place, nettoyez le cache pour être sûr que Laravel prend en compte les modifications de middlewares :

php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear

Puis, activez le mode maintenance en ciblant votre vue personnalisée :

php artisan down --render="errors::503"

Étape 5 : Désactiver la maintenance

Une fois vos mises à jour terminées :

php artisan up

Et voilà ! Votre page personnalisée s'affiche enfin correctement, sans aucune interférence.


FAQ : Vos questions sur le mode maintenance

Pourquoi utiliser Blade pour la maintenance et pas Vue.js ? C'est une question de sécurité ! En mode maintenance, le moteur d'Inertia et de Vue peut être coupé. Blade est du HTML pur, c'est le moyen le plus fiable de s'assurer que quelque chose s'affiche, quoi qu'il arrive.

Est-ce que je peux voir mon site pendant que les autres voient la maintenance ? Bien sûr ! Utilisez php artisan down --secret="mon-code-secret". Vous pourrez y accéder via votre-site.com/mon-code-secret.

Comment sortir du mode maintenance ? C'est la commande la plus satisfaisante : php artisan up. Et hop, tout le monde revient !


Conclusion

Maîtriser le mode maintenance sous Laravel et Inertia n'est pas qu'une question de commande, c'est une question d'organisation. En remettant le middleware PreventRequestsDuringMaintenance à sa place (la première !), vous évitez bien des maux de tête.

Alors, prêt à mettre à jour votre application avec style ?

Souhaitez-vous que je vous aide à créer le composant Vue.js correspondant pour gérer vos erreurs 404 et 500 de manière élégante ?

Ajouter un commentaire

Vous devez être connecté pour laisser un commentaire.

Avatar
Waffo lele rostand
il y a 10 mois

Maîtriser le mode maintenance sous Laravel et Inertia n'est pas qu'une question de commande, c'est une question d'organisation. En remettant le middleware PreventRequestsDuringMaintenance à sa place (la première !), vous évitez bien des maux de tête.