ITSkillsCenter
Blog

Laravel déploiement production : guide pratique 2026

13 دقائق للقراءة

Lecture : 13 minutes · Niveau : intermédiaire-avancé · Mise à jour : avril 2026

Faire tourner Laravel en local est facile. Le faire tourner en production fiable, performant, monitoré, sauvegardé et déployable sans downtime demande des choix précis et de la discipline opérationnelle. Ce guide rassemble les pratiques opérationnelles éprouvées pour des PME qui veulent livrer du Laravel sérieux en 2026.

Voir aussi → Laravel pour PME : guide backend PHP moderne.


Sommaire

  1. Choix d’hébergement
  2. Laravel Forge : le standard managé
  3. VPS auto-hébergé
  4. Docker et conteneurisation
  5. Configuration production
  6. Queue workers en production
  7. Scheduling et cron
  8. Déploiement zéro downtime
  9. Monitoring et logs
  10. Sauvegardes et reprise
  11. FAQ

1. Choix d’hébergement

Cinq options selon contexte PME.

Mutualisé : démarrage à très bas coût, mais limites importantes (pas de queue worker dédié, pas de Redis, scheduling parfois bidouillé). Acceptable pour petites apps simples, à éviter pour du sérieux.

VPS auto-géré (Hetzner, OVH, Scaleway, hébergeurs ouest-africains) : contrôle total, prix maîtrisé, gestion technique à assumer. Compétence sysadmin nécessaire ou prestataire.

Laravel Forge (forge.laravel.com) : service officiel Laravel pour gérer des serveurs VPS. Provisioning automatique, déploiement Git, SSL automatique. Excellent rapport simplicité/prix.

PaaS (Railway, Render, Fly.io) : déploiement git push, scaling automatique. Plus cher au scale, parfait pour MVPs ou projets sans besoin de personnalisation.

Laravel Vapor : serverless AWS Lambda. Performance, mais infrastructure complexe et coûts variables.

Recommandation par profil

  • MVP / startup : Forge sur Hetzner, ou Railway/Render
  • PME établie : Forge sur Hetzner / OVH, ou VPS auto-géré
  • Croissance avec ambition : Forge multi-serveurs ou Vapor selon stratégie

2. Laravel Forge : le standard managé

Forge est devenu le standard pour beaucoup d’équipes Laravel. Il automatise ce qui prend des heures sur un VPS vierge.

Ce que Forge fait

  • Provisioning du VPS (Nginx, PHP-FPM, MySQL/PostgreSQL, Redis, Node)
  • Configuration sécurité (firewall, fail2ban, SSH par clé)
  • Déploiement Git (push to deploy)
  • HTTPS automatique avec Let’s Encrypt
  • Queue workers managés via Supervisor
  • Scheduling via cron Forge
  • Backups automatisés vers S3/spaces
  • Monitoring serveur basique
  • Multiple sites par serveur

Workflow type

  1. Créer compte Forge, connecter provider cloud (DigitalOcean, AWS, Linode, Hetzner, Vultr, etc.)
  2. Provisionner un nouveau serveur en quelques minutes
  3. Créer un site sur le serveur en pointant un dépôt Git
  4. Configurer les variables d’environnement
  5. Déployer
# Script de déploiement type généré par Forge
cd /home/forge/exemple.com
git pull origin main
$FORGE_COMPOSER install --no-dev --no-interaction --prefer-dist --optimize-autoloader
$FORGE_PHP artisan migrate --force
$FORGE_PHP artisan config:cache
$FORGE_PHP artisan route:cache
$FORGE_PHP artisan view:cache
$FORGE_PHP artisan queue:restart

Quick deployments

Forge propose le « Quick Deploy » : chaque push sur la branche choisie déclenche un déploiement automatique. Combiné à des tests CI passants, ça simplifie énormément le workflow.

Limites

  • Pas de support pour scénarios très complexes (sharding, multi-region, microservices)
  • Forge gère un serveur à la fois ; pour cluster, plus de configuration manuelle

3. VPS auto-hébergé

Pour qui veut le contrôle total ou éviter le coût Forge.

Stack type

Internet
   ↓
Caddy ou Nginx (HTTPS Let's Encrypt)
   ↓
PHP-FPM 8.3+
   ↓
Laravel app
   ↓
MySQL/PostgreSQL + Redis

Installation Ubuntu 24.04 LTS

# Mises à jour
sudo apt update && sudo apt upgrade -y

# PHP 8.3 + extensions Laravel
sudo apt install php8.3 php8.3-fpm php8.3-cli php8.3-mbstring php8.3-xml \
    php8.3-mysql php8.3-pgsql php8.3-curl php8.3-zip php8.3-bcmath \
    php8.3-redis php8.3-intl php8.3-gd php8.3-imagick

# Composer
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

# Nginx
sudo apt install nginx

# MySQL ou PostgreSQL
sudo apt install mysql-server   # ou postgresql

# Redis
sudo apt install redis-server

# Node (pour Vite)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs

Configuration Nginx

server {
    listen 443 ssl http2;
    server_name app.exemple.com;
    root /var/www/app/public;
    index index.php;

    ssl_certificate /etc/letsencrypt/live/app.exemple.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.exemple.com/privkey.pem;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Sécurité

  • Firewall UFW : autoriser 22 (SSH), 80, 443 seulement
  • SSH par clé uniquement, pas de password (voir Linux hardening)
  • fail2ban pour le brute-force
  • Mises à jour de sécurité automatiques

4. Docker et conteneurisation

Pour des déploiements modernes ou scaling Kubernetes/Swarm.

# Multi-stage build
FROM composer:2 AS composer
WORKDIR /app
COPY composer.* ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist

FROM node:20-alpine AS node
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM php:8.3-fpm-alpine
WORKDIR /var/www
RUN apk add --no-cache \
    libzip-dev libpng-dev nginx supervisor \
    && docker-php-ext-install pdo_mysql zip bcmath gd opcache

COPY --from=composer /app/vendor /var/www/vendor
COPY . /var/www
COPY --from=node /app/public/build /var/www/public/build

RUN composer dump-autoload --optimize \
    && php artisan config:cache \
    && php artisan route:cache \
    && php artisan view:cache

COPY docker/nginx.conf /etc/nginx/http.d/default.conf
COPY docker/supervisord.conf /etc/supervisor/conf.d/

EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

Voir Docker en production pour PME pour les principes généraux.

Compose pour orchestration

services:
  app:
    image: ghcr.io/ma-pme/app:latest
    restart: unless-stopped
    environment:
      APP_ENV: production
      DB_HOST: db
    depends_on:
      db: { condition: service_healthy }
      redis: { condition: service_started }

  db:
    image: mysql:8
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: app
    volumes:
      - db-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping"]

  redis:
    image: redis:7-alpine

  queue:
    image: ghcr.io/ma-pme/app:latest
    restart: unless-stopped
    command: php artisan queue:work --tries=3
    depends_on:
      - app

volumes:
  db-data:

5. Configuration production

.env production

APP_ENV=production
APP_DEBUG=false
APP_URL=https://app.exemple.com

LOG_CHANNEL=stack
LOG_LEVEL=warning

DB_CONNECTION=mysql
DB_HOST=...
DB_DATABASE=...

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

MAIL_MAILER=smtp
SENTRY_LARAVEL_DSN=https://...

Optimisations obligatoires en prod

composer install --no-dev --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

Cache des configs/routes/vues = boot beaucoup plus rapide.

OPcache

; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0   ; en prod, recharger explicitement après deploy
opcache.preload=/var/www/preload.php   ; PHP 7.4+, pré-charge code

validate_timestamps=0 empêche PHP de re-vérifier les fichiers modifiés à chaque requête. Lors d’un déploiement, redémarrer PHP-FPM ou utiliser opcache_reset().

JIT (PHP 8.x)

opcache.jit_buffer_size=100M
opcache.jit=tracing

Améliore les performances CPU-bound (calculs, parsing complexe). Pour des apps web standard, gain modeste mais positif.


6. Queue workers en production

Lancer un worker

php artisan queue:work --tries=3 --timeout=90

Mais pas en CLI directement : il doit être un service supervisé.

Avec Supervisor (Linux)

/etc/supervisor/conf.d/laravel-worker.conf :

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/log/laravel-worker.log
stopwaitsecs=3600
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*

Avec systemd

Voir systemd services tutoriel pour la config détaillée.

Restart après déploiement

Dans le script de déploiement :

php artisan queue:restart

Signale aux workers de se terminer après leur job actuel et redémarrer (avec le nouveau code).

Horizon pour Redis

laravel/horizon fournit une UI pour superviser les queues Redis. Très précieux dès qu’il y a plusieurs queues, plusieurs types de jobs, ou besoin de visualiser le throughput.


7. Scheduling et cron

Une seule entrée cron sur le serveur :

* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1

Laravel exécute toutes les tâches définies dans app/Console/Kernel.php (ou routes/console.php en Laravel 11+).

$schedule->command('clients:relancer')->dailyAt('09:00')->withoutOverlapping();
$schedule->job(new GenererRapportMensuel)->monthlyOn(1, '02:00');
$schedule->call(fn () => Cache::flush())->everyFifteenMinutes();
$schedule->command('backup:run')->dailyAt('03:00')->onOneServer();

Bonnes pratiques

  • withoutOverlapping() : empêche deux exécutions parallèles de la même tâche
  • onOneServer() : utile sur cluster, ne lance la tâche que sur un serveur
  • runInBackground() : pour des tâches longues qui ne doivent pas bloquer le scheduler
  • emailOutputTo('admin@...') : envoie le résultat par email

8. Déploiement zéro downtime

Stratégie sans framework dédié

Forge fait du « zero downtime » via symlinks :
1. Cloner le code dans un nouveau dossier releases/timestamp/
2. Installer dépendances, lancer migrations
3. Switcher le symlink current vers le nouveau dossier
4. Recharger PHP-FPM

# Pseudo-code
TIMESTAMP=$(date +%s)
RELEASE_DIR=/var/www/releases/$TIMESTAMP

git clone --depth 1 origin/main $RELEASE_DIR
cd $RELEASE_DIR
composer install --no-dev --optimize-autoloader
php artisan config:cache route:cache view:cache event:cache

# Symlink atomique
ln -sfn $RELEASE_DIR /var/www/current

# Reload PHP-FPM
sudo systemctl reload php8.3-fpm
php artisan queue:restart

Outils

  • Forge : intégré
  • Envoyer (envoyer.io) : déploiement zero-downtime made by Laravel
  • Deployer (deployer.org) : open-source, équivalent Capistrano
  • Custom : avec scripts bash + GitHub Actions

Migrations production

Migrations bloquantes (ALTER sur grosse table, ajout NOT NULL, drop colonne utilisée) doivent être décomposées :

  1. Déploiement A : ajouter colonne nullable
  2. Backfill via job
  3. Déploiement B : code utilise nouvelle colonne, ancienne ignorée
  4. Migration : ajouter contrainte NOT NULL
  5. Déploiement C : drop ancienne colonne

9. Monitoring et logs

Sentry pour les erreurs

composer require sentry/sentry-laravel
php artisan sentry:publish --dsn=https://...

Capture toutes les exceptions non gérées avec stack trace, contexte utilisateur, breadcrumbs. Tier gratuit suffit pour démarrer.

Logs centralisés

Pour plus d’un serveur : Loki (avec Promtail), ELK, ou des services managés (Datadog, Logtail, Papertrail).

// config/logging.php : channel pour Logtail
'logtail' => [
    'driver' => 'monolog',
    'handler' => Logtail\Monolog\LogtailHandler::class,
    'with' => ['sourceToken' => env('LOGTAIL_SOURCE_TOKEN')],
],

Métriques

spatie/laravel-prometheus ou exporters custom pour métriques Prometheus. Combiné à Grafana, dashboard temps réel.

Health checks

Endpoint /health qui vérifie DB, Redis, queues. Utilisé par load balancers et monitoring externe.

Route::get('/health', function () {
    DB::connection()->getPdo();
    Cache::get('health-check');
    return ['status' => 'ok', 'time' => now()];
});

10. Sauvegardes et reprise

Spatie Laravel Backup

composer require spatie/laravel-backup
php artisan vendor:publish --provider="Spatie\Backup\BackupServiceProvider"

Configurer dans config/backup.php : chemins à backuper, destinations (S3, FTP, local).

// Schedule
$schedule->command('backup:clean')->daily()->at('01:00');
$schedule->command('backup:run')->daily()->at('01:30');

Backups quotidiens automatisés, rotation, notifications en cas d’échec.

Tester les restaurations

Un backup non testé n’est pas un backup. Au moins une fois par trimestre :
– Restaurer le backup le plus récent dans un environnement isolé
– Vérifier l’intégrité des données
– Documenter le processus de restauration

Voir Sauvegarde 3-2-1 PME africaine pour la stratégie générale applicable à toute application Laravel en production.


11. FAQ

Forge ou VPS auto-géré ?

Forge si l’équipe veut se concentrer sur le code et accepte un coût mensuel raisonnable. VPS auto-géré si compétence sysadmin présente et volonté de contrôle total. Pour la majorité des PME : Forge sur Hetzner offre le meilleur compromis.

Comment déployer sans interruption ?

Forge ou Envoyer pour faire ça en 2 clics. En self-hosted : symlinks atomiques + reload PHP-FPM + queue:restart. Voir section dédiée.

Octane vaut-il la peine ?

Pour des applications avec trafic significatif et besoins de performance : oui. Pour des back-offices internes ou trafic modéré : pas indispensable. Vérifier la compatibilité avec ses dépendances avant de se lancer.

Logs en production : que conserver ?

Logs applicatifs au niveau warning+ (level=warning), erreurs dans Sentry, logs d’accès web (Nginx). Conservation : 30-90 jours selon volume et obligations légales.

Comment mesurer la performance Laravel en prod ?

Sentry Performance, Laravel Pulse (officiel récent), New Relic, Datadog APM. Profiling occasionnel avec Telescope en preprod. Métriques clés : p95/p99 par route, taux d’erreur, queue throughput.

Combien de queue workers ?

Démarrer avec 2-4 workers. Augmenter si la queue s’accumule. Surveiller via Horizon ou logs queue. Pour des apps avec beaucoup de jobs : queues nommées par priorité et workers dédiés par priorité.

Migrations bloquantes : comment les éviter ?

Décomposer en étapes compatibles : ajout colonne nullable → backfill → contrainte NOT NULL. Sur PostgreSQL, utiliser CREATE INDEX CONCURRENTLY. Tester les migrations sur copie de la prod avant le go-live.


Articles liés (cluster Laravel)


Article mis à jour le 25 avril 2026. Pour signaler une erreur ou suggérer une amélioration, écrivez-nous.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité