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
- Choix d’hébergement
- Laravel Forge : le standard managé
- VPS auto-hébergé
- Docker et conteneurisation
- Configuration production
- Queue workers en production
- Scheduling et cron
- Déploiement zéro downtime
- Monitoring et logs
- Sauvegardes et reprise
- 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
- Créer compte Forge, connecter provider cloud (DigitalOcean, AWS, Linode, Hetzner, Vultr, etc.)
- Provisionner un nouveau serveur en quelques minutes
- Créer un site sur le serveur en pointant un dépôt Git
- Configurer les variables d’environnement
- 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âcheonOneServer(): utile sur cluster, ne lance la tâche que sur un serveurrunInBackground(): pour des tâches longues qui ne doivent pas bloquer le scheduleremailOutputTo('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 :
- Déploiement A : ajouter colonne nullable
- Backfill via job
- Déploiement B : code utilise nouvelle colonne, ancienne ignorée
- Migration : ajouter contrainte NOT NULL
- 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)
- 👉 Laravel pour PME : guide backend PHP moderne (pillar)
- 👉 Laravel Eloquent ORM en pratique
- 👉 Laravel Filament : back-office rapide
Article mis à jour le 25 avril 2026. Pour signaler une erreur ou suggérer une amélioration, écrivez-nous.