Laravel Production Deployment Checklist

Khimananda Oli 7 min read DevOps
Laravel Production Deployment Checklist

By Khimananda Oli | Last reviewed: August 2026

Deploying a framework without a structured verification process is the primary cause of post-release outages and performance regressions in PHP applications. This Laravel production deployment checklist consolidates fifteen years of infrastructure experience into actionable steps that prevent common failures related to permissions, caching, and queue management. Before you push your next release, use this guide to ensure your environment matches the rigorous standards required for business-critical workloads.

How do you prepare the server environment for a Laravel production deployment checklist?

The foundation of any stable application lies in the operating system and web server configuration. In my experience auditing deployments across Nepal and global clients, most "application bugs" are actually misconfigured infrastructure. Start by securing the base OS; follow a guide on securing a fresh VPS to disable root login, configure UFW, and set up fail2ban before installing a single PHP package.

NginxPHP-FPMMySQL/RDSRedis CacheProduction Stack TopologyIsolated services for scalability and audit compliance
Core server topology required for a compliant Laravel production deployment checklist.

Nginx and PHP-FPM Configuration

Your Nginx configuration must explicitly pass requests to PHP-FPM via a Unix socket rather than TCP for local performance. Ensure the fastcgi_param SCRIPT_FILENAME points to the correct public index path. A common mistake in 2026 is forgetting to increase client_max_body_size for file uploads or failing to set real_ip_header when behind Cloudflare or an AWS ALB, which breaks rate limiting and logging.

<!-- /etc/nginx/sites-available/laravel -->
server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

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

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

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

File Permissions and Ownership

Incorrect permissions are a top security vulnerability. The web server user (www-data) should own the storage and bootstrap/cache directories, but never the entire application root. Use the following commands during every deployment to reset ownership safely:

  • chown -R www-data:www-data storage bootstrap/cache
  • find storage -type d -exec chmod 775 {} \;
  • find storage -type f -exec chmod 664 {} \;
  • Ensure the deployment user is in the www-data group to avoid permission conflicts during CI/CD.

Which application optimizations belong in a Laravel production deployment checklist?

Development environments prioritize debuggability; production demands speed. You must compile all configuration, routes, and views into cached files. This reduces filesystem I/O and eliminates parsing overhead on every request. If you are running containers, review containerizing Laravel apps to ensure these caches are built during the image build stage, not at runtime entrypoint.

OptimizationCommandImpactRisk if Skipped
Config Cachephp artisan config:cache~20% faster bootEnv vars ignored at runtime
Route Cachephp artisan route:cacheSignificant routing speedupClosure-based routes break
View Cachephp artisan view:cacheEliminates Blade compilationHigh CPU on first hits
Event Cachephp artisan event:cacheFaster event discoveryMinor overhead per request
Composer Autoloadcomposer dump-autoload -oClass map optimizationSlower class resolution

A critical warning: route:cache does not support closure-based routes. Audit your routes/web.php and routes/api.php files before enabling this. Convert any closures to controller actions. Also, remember that once config:cache is active, the .env file is completely ignored. All environment variables must be referenced via env() only inside config files, never directly in controllers or services.

How do you manage queues and scheduled tasks in production?

Queues are non-negotiable for modern Laravel applications handling emails, notifications, or heavy processing. Relying on the default sync driver in production will block HTTP requests and degrade user experience. Configure Redis as your queue driver for persistence and visibility timeout control. For detailed tuning, see Laravel queues and background processing.

HTTP RequestRedis QueueWorker ProcessSupervisorAsync Processing FlowSupervisor ensures workers restart after memory limits
Supervisor-managed queue workers are mandatory for reliability in any Laravel production deployment checklist.

Supervisor Configuration

Never run queue:work manually in a terminal session. Use Supervisor to keep workers alive and automatically restart them when they hit memory limits or after deployments. Below is a battle-tested configuration for 2026:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 --memory=256
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/log/laravel-worker.log
stopwaitsecs=3600

The --max-time=3600 flag ensures workers gracefully exit after one hour, allowing Supervisor to spawn fresh processes. This prevents memory leaks from accumulating over days of uptime. Always run supervisorctl reread && supervisorctl update after changing configs.

Scheduler Daemon

Since Laravel 11+, the scheduler daemon (schedule:run every minute) has been replaced by a long-running schedule:work command in many setups, though cron remains valid. If using the daemon approach, manage it via Supervisor similarly to queue workers. Verify timezone settings in config/app.php match your server's system time to prevent tasks firing at unexpected hours—a frequent issue in Nepal where servers may default to UTC while business logic expects NPT.

What security and monitoring steps finalize a Laravel production deployment checklist?

Security is not a feature; it is the baseline. After configuring the application, you must harden the transport layer and validate headers. Obtain certificates via Let's Encrypt or your cloud provider's ACM. Follow this SSL setup guide if managing certificates manually. Enable HSTS, X-Content-Type-Options, and Referrer-Policy headers in Nginx, not just in middleware, for defense-in-depth.

SSL/TLS CheckHeader ScanLog ValidationAlert TestPre-Launch Security GateAutomated verification before traffic handoff
Sequential security validation gates prevent vulnerable code from reaching users.

Observability and Error Tracking

You cannot fix what you cannot see. Integrate Sentry, Flare, or Datadog before going live. Configure log channels to separate application errors from access logs. Set up alerts for queue failures, high error rates, and disk usage. In regulated environments, ensure log retention meets compliance requirements (e.g., 90 days for SOC 2). Verify that sensitive data like passwords or tokens are never written to logs by auditing your exception handlers.

Database and Backup Verification

Test your backup restoration process, not just the backup creation. A backup you cannot restore is worthless. Schedule automated snapshots of RDS or EC2 volumes. For self-managed databases, verify replication lag and connection pool sizing. Run php artisan migrate --force only after confirming migrations are backward-compatible with the previous code version to support zero-downtime deployments.

Finalizing Your Laravel Production Deployment Checklist

A disciplined Laravel production deployment checklist transforms chaotic releases into predictable, auditable events. By systematically verifying server configuration, enforcing caching, managing queues with Supervisor, and validating security controls, you eliminate entire categories of production incidents. Infrastructure is code, and deployment is a pipeline—treat both with engineering rigor. If your team needs help establishing audit-ready deployment workflows or optimizing existing Laravel infrastructure, reach out to discuss your architecture.

Frequently Asked Questions

Production requires bcmath, ctype, curl, dom, fileinfo, json, mbstring, openssl, pdo, tokenizer, xml, and zip. Install via apt install php8.4-fpm php8.4-mysql php8.4-redis on Ubuntu 24.04 to satisfy framework dependencies and prevent runtime errors during deployment.

Yes. Always execute composer install --no-dev --optimize-autoloader --classmap-authoritative to exclude testing packages and generate an optimized class map. This reduces memory usage, speeds up autoloading, and prevents accidental exposure of development tools like PHPUnit or Faker in live environments.

Never commit .env files. Use server-level environment variables or secrets managers like AWS Secrets Manager or Doppler. Inject values at deploy time using CI/CD pipelines, ensuring APP_KEY and database credentials remain encrypted at rest and never appear in version control history.

OPcache caches compiled PHP bytecode, eliminating repeated parsing overhead. Enable opcache.enable=1, set opcache.memory_consumption=256, and configure opcache.validate_timestamps=0 in production. Restart PHP-FPM after config changes to realize significant latency reductions and lower CPU utilization under load.

Set ownership to www-data and permissions to 775 for storage and bootstrap/cache directories. Run chown -R www-data:www-data storage bootstrap/cache and chmod -R 775 storage bootstrap/cache post-deployment to allow Laravel to write logs, sessions, and cached views without permission denied errors.

Integrate health checks into your CI/CD pipeline using curl against /up endpoint or custom Artisan commands. Validate database connectivity, Redis availability, queue workers, and scheduled task execution before marking deployment successful to catch configuration drift immediately.

Not strictly required but strongly recommended for caching, sessions, and queues. Redis outperforms file-based drivers significantly under concurrent load. Use Predis or phpredis extension with TLS encryption for managed cloud instances to ensure low-latency operations and horizontal scalability.

Rotate only when compromised or during major security audits. Changing APP_KEY invalidates all encrypted cookies, sessions, and queued jobs. Schedule maintenance windows, clear caches, and notify users beforehand since active sessions will terminate immediately upon key rotation.

Configure Nginx or Apache to serve only public/index.php as entry point. Block access to .env, .git, and vendor directories. Enforce HTTPS with HSTS headers, disable directory listing, and restrict HTTP methods to GET, POST, PUT, PATCH, DELETE only.

Yes. Execute php artisan config:cache, route:cache, view:cache, and event:cache after every deployment. These commands compile configurations and routes into single cached files, reducing bootstrap time by 30-50% and preventing repeated file system reads during request handling.

Use atomic deploys with symlink switching via tools like Deployer or Envoyer. Maintain two release directories, run migrations and cache warming on new release before swapping symlinks. Keep previous releases for instant rollback if health checks fail post-switch.

Write backward-compatible migrations that add columns as nullable first, deploy code supporting both old and new schema, then backfill data and add constraints in subsequent releases. Avoid destructive changes like renaming columns directly; use expand-contract pattern instead.

Track failed job counts, retry attempts, and queue depth using Horizon dashboard or Prometheus exporters. Set alerts for stuck workers, memory leaks, or processing delays exceeding SLAs. Implement circuit breakers to pause consumption during downstream service outages.

Start with 2 vCPU, 4GB RAM, and SSD storage for applications under 10k monthly requests. Scale vertically before horizontally. Monitor memory usage closely since PHP-FPM workers consume 30-50MB each; adjust pm.max_children based on available RAM.

Check PHP-FPM error logs and Laravel storage/logs/laravel.log first. Verify file permissions, missing extensions, and syntax errors in cached configs. Temporarily enable APP_DEBUG=true via environment variable to reveal exceptions, then disable immediately after identifying root cause.