Get 20% off web development packages
Deployment & DevOps: Laravel Production Deployment Mastery
Deployment & DevOps: Laravel Production Deployment Mastery
Expert Guide by Alaa Amer – Professional Web Developer & Applications Designer
Master Laravel deployment and DevOps practices for production environments. Learn CI/CD, containerization, monitoring, scaling strategies, and enterprise-level infrastructure management.
Docker Compose for Production:
# docker-compose.prod.yml
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
target: production
image: laravel-app:latest
restart: unless-stopped
environment:
- APP_ENV=production
- APP_DEBUG=false
volumes:
- ./storage:/var/www/html/storage
- ./bootstrap/cache:/var/www/html/bootstrap/cache
networks:
- laravel-network
depends_on:
- database
- redis
deploy:
replicas: 3
resources:
limits:
cpus: "1"
memory: 512M
reservations:
cpus: "0.5"
memory: 256M
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/ssl:/etc/ssl/certs
- ./storage/app/public:/var/www/html/storage/app/public
networks:
- laravel-network
depends_on:
- app
database:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
volumes:
- db-data:/var/lib/mysql
- ./docker/mysql/my.cnf:/etc/mysql/conf.d/custom.cnf
networks:
- laravel-network
command: --innodb-buffer-pool-size=1G --innodb-log-file-size=256M
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data
- ./docker/redis/redis.conf:/etc/redis/redis.conf
networks:
- laravel-network
command: redis-server /etc/redis/redis.conf
queue-worker:
build:
context: .
dockerfile: Dockerfile
target: production
restart: unless-stopped
command: php artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
volumes:
- ./storage:/var/www/html/storage
networks:
- laravel-network
depends_on:
- database
- redis
deploy:
replicas: 3
scheduler:
build:
context: .
dockerfile: Dockerfile
target: production
restart: unless-stopped
command: php artisan schedule:work
volumes:
- ./storage:/var/www/html/storage
networks:
- laravel-network
depends_on:
- database
- redis
volumes:
db-data:
redis-data:
networks:
laravel-network:
driver: bridge
4️⃣ Monitoring & Observability
Application Monitoring Setup:
<?php
// app/Http/Middleware/ApplicationMonitoring.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\{Log, Cache, DB};
use Prometheus\CollectorRegistry;
use Prometheus\Storage\Redis;
class ApplicationMonitoring
{
protected $registry;
public function __construct()
{
$this->registry = new CollectorRegistry(new Redis());
}
public function handle(Request $request, Closure $next)
{
$startTime = microtime(true);
$response = $next($request);
$duration = microtime(true) - $startTime;
// Record metrics
$this->recordMetrics($request, $response, $duration);
return $response;
}
protected function recordMetrics(Request $request, $response, float $duration): void
{
// HTTP request duration
$histogram = $this->registry->getOrRegisterHistogram(
'laravel_app',
'http_request_duration_seconds',
'HTTP request duration in seconds',
['method', 'route', 'status_code'],
[0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
);
$histogram->observe(
$duration,
[
$request->method(),
$request->route()?->getName() ?? 'unknown',
(string) $response->getStatusCode()
]
);
// HTTP request count
$counter = $this->registry->getOrRegisterCounter(
'laravel_app',
'http_requests_total',
'Total number of HTTP requests',
['method', 'status_code']
);
$counter->inc([
$request->method(),
(string) $response->getStatusCode()
]);
// Database query count
if (DB::getQueryLog()) {
$queryGauge = $this->registry->getOrRegisterGauge(
'laravel_app',
'database_queries_per_request',
'Number of database queries per request'
);
$queryGauge->set(count(DB::getQueryLog()));
}
// Memory usage
$memoryGauge = $this->registry->getOrRegisterGauge(
'laravel_app',
'memory_usage_bytes',
'Memory usage in bytes'
);
$memoryGauge->set(memory_get_peak_usage(true));
}
}
// app/Console/Commands/MonitorSystem.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\{DB, Cache, Queue};
class MonitorSystem extends Command
{
protected $signature = 'monitor:system';
protected $description = 'Monitor system health and send alerts';
public function handle(): void
{
$this->info('Running system monitoring...');
$checks = [
'database' => $this->checkDatabase(),
'cache' => $this->checkCache(),
'queue' => $this->checkQueue(),
'storage' => $this->checkStorage(),
'memory' => $this->checkMemory(),
'logs' => $this->checkLogs()
];
$failures = array_filter($checks, fn($status) => !$status);
if (!empty($failures)) {
$this->sendAlert($failures);
$this->error('System health check failed: ' . implode(', ', array_keys($failures)));
} else {
$this->info('All system checks passed');
}
$this->recordHealthMetrics($checks);
}
protected function checkDatabase(): bool
{
try {
DB::select('SELECT 1');
// Check slow queries
$slowQueries = DB::select("
SELECT COUNT(*) as slow_count
FROM information_schema.processlist
WHERE command != 'Sleep' AND time > 30
");
return $slowQueries[0]->slow_count < 5;
} catch (\Exception $e) {
Log::error('Database health check failed', ['error' => $e->getMessage()]);
return false;
}
}
protected function checkCache(): bool
{
try {
$testKey = 'health_check_' . time();
Cache::put($testKey, 'test', 60);
$result = Cache::get($testKey);
Cache::forget($testKey);
return $result === 'test';
} catch (\Exception $e) {
Log::error('Cache health check failed', ['error' => $e->getMessage()]);
return false;
}
}
protected function checkQueue(): bool
{
try {
// Check queue sizes
$queueSizes = [
'default' => Queue::size('default'),
'high' => Queue::size('high'),
'emails' => Queue::size('emails')
];
// Alert if any queue has too many jobs
return !collect($queueSizes)->contains(fn($size) => $size > 1000);
} catch (\Exception $e) {
Log::error('Queue health check failed', ['error' => $e->getMessage()]);
return false;
}
}
protected function checkStorage(): bool
{
$storagePath = storage_path();
$freeSpace = disk_free_space($storagePath);
$totalSpace = disk_total_space($storagePath);
$usagePercent = (($totalSpace - $freeSpace) / $totalSpace) * 100;
return $usagePercent < 90; // Alert if usage > 90%
}
protected function checkMemory(): bool
{
$memoryUsage = memory_get_usage(true);
$memoryLimit = $this->parseMemoryLimit(ini_get('memory_limit'));
$usagePercent = ($memoryUsage / $memoryLimit) * 100;
return $usagePercent < 90;
}
protected function checkLogs(): bool
{
$logPath = storage_path('logs/laravel.log');
if (!file_exists($logPath)) {
return true;
}
// Check for recent errors
$recentErrors = shell_exec("grep -c 'ERROR' $logPath | tail -1000");
return intval($recentErrors) < 50; // Alert if > 50 errors in last 1000 lines
}
protected function parseMemoryLimit(string $limit): int
{
$limit = trim($limit);
$last = strtolower($limit[strlen($limit) - 1]);
$limit = (int) $limit;
switch ($last) {
case 'g': $limit *= 1024 * 1024 * 1024; break;
case 'm': $limit *= 1024 * 1024; break;
case 'k': $limit *= 1024; break;
}
return $limit;
}
protected function sendAlert(array $failures): void
{
// Send to monitoring service (Slack, PagerDuty, etc.)
Log::critical('System health check failures detected', $failures);
// You could integrate with external services here
// Notification::route('slack', '#alerts')->notify(new SystemHealthAlert($failures));
}
protected function recordHealthMetrics(array $checks): void
{
foreach ($checks as $service => $status) {
Cache::put("health_check:{$service}", $status ? 1 : 0, 300);
}
}
}
Grafana Dashboard Configuration:
{
"dashboard": {
"title": "Laravel Application Metrics",
"panels": [
{
"title": "Request Rate",
"type": "graph",
"targets": [
{
"expr": "rate(laravel_app_http_requests_total[5m])",
"legendFormat": "{{method}} {{status_code}}"
}
]
},
{
"title": "Response Time",
"type": "graph",
"targets": [
{
"expr": "histogram_quantile(0.95, rate(laravel_app_http_request_duration_seconds_bucket[5m]))",
"legendFormat": "95th percentile"
},
{
"expr": "histogram_quantile(0.50, rate(laravel_app_http_request_duration_seconds_bucket[5m]))",
"legendFormat": "50th percentile"
}
]
},
{
"title": "Database Queries",
"type": "graph",
"targets": [
{
"expr": "avg(laravel_app_database_queries_per_request)",
"legendFormat": "Avg queries per request"
}
]
},
{
"title": "Memory Usage",
"type": "graph",
"targets": [
{
"expr": "laravel_app_memory_usage_bytes",
"legendFormat": "Memory usage"
}
]
}
]
}
}
Production Deployment Checklist
✅ Security Configuration
- SSL certificates installed
- Security headers configured
- Firewall rules applied
- Database credentials secured
✅ Performance Optimization
- Opcache enabled
- Asset compression configured
- CDN integration completed
- Database indexes optimized
✅ Monitoring Setup
- Application monitoring configured
- Error tracking enabled
- Log aggregation implemented
- Alert notifications configured
✅ Backup Strategy
- Database backup automated
- File backup configured
- Backup restoration tested
- Offsite backup storage
✅ High Availability
- Load balancer configured
- Multiple application instances
- Database replication setup
- Queue workers running
📩 Need help with Laravel deployment?
Article Category
Deployment & DevOps: Laravel Production Deployment Mastery
Master Laravel deployment strategies, CI/CD pipelines, Docker containerization, server management, monitoring, and enterprise-level DevOps practices.
Consultation & Communication
Direct communication via WhatsApp or phone to understand your project needs precisely.
Planning & Scheduling
Creating clear work plan with specific timeline for each project phase.
Development & Coding
Building projects with latest technologies ensuring high performance and security.
Testing & Delivery
Comprehensive testing and thorough review before final project delivery.
Services Related to This Article
All ServicesWant to apply this article to your project?
If this topic is relevant to your current project, you can jump to one of the services above or browse the services page to choose the most suitable solution.