Following laravel deployment best practices is the difference between a smooth launch and a midnight firefighting session. Whether you're deploying your first Laravel app or your fiftieth, having a reliable checklist ensures nothing gets missed — no forgotten environment variables, no debug mode left on, no exposed credentials.
This guide gives you a complete, copy-paste-ready deployment checklist for getting Laravel into production on a VPS.
Pre-Deployment: Local Preparation
Before touching your server, make sure your local setup is production-ready.
1. Environment Configuration
# Copy .env.example and configure for production cp .env.example .env.production Critical settings to change:
APP_ENV=production APP_DEBUG=false APP_URL=https://yourdomain.com LOG_CHANNEL=stack LOG_LEVEL=warning DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_DATABASE=your_production_db DB_USERNAME=your_db_user DB_PASSWORD=your_strong_password CACHE_DRIVER=redis SESSION_DRIVER=redis QUEUE_CONNECTION=redis Never set APP_DEBUG=true in production. It exposes your entire configuration, database credentials, and stack traces to anyone who triggers an error.
2. Optimize Autoloading
composer install --optimize-autoloader --no-dev The --no-dev flag removes development dependencies (PHPUnit, Debugbar, etc.), reducing your deployment size and attack surface. The --optimize-autoloader flag generates a class map for faster class loading.
3. Run Tests
php artisan test Never deploy code that hasn't passed its test suite. If you don't have tests yet, at least verify the app boots without errors.
Server Setup: The Foundation
4. Server Requirements
For a Laravel 11 application, ensure your server has:
- PHP 8.2 or higher
- Required extensions: BCMath, Ctype, cURL, DOM, Fileinfo, JSON, Mbstring, OpenSSL, PCRE, PDO, Tokenizer, XML
- Composer
- Node.js and npm (for frontend assets)
- MySQL 8.0+ or PostgreSQL 15+
- Redis (recommended for caching and queues)
Install everything on Ubuntu:
sudo apt update sudo apt install php8.2-fpm php8.2-mysql php8.2-redis php8.2-xml \\ php8.2-mbstring php8.2-curl php8.2-zip php8.2-bcmath php8.2-gd \\ nginx mysql-server redis-server nodejs npm -y 5. Directory Permissions
Laravel needs write access to specific directories:
sudo chown -R www-data:www-data /var/www/yourapp sudo chmod -R 755 /var/www/yourapp sudo chmod -R 775 /var/www/yourapp/storage sudo chmod -R 775 /var/www/yourapp/bootstrap/cache Getting permissions wrong is one of the most common laravel deployment best practices violations. Too permissive (777) is a security risk. Too restrictive and Laravel can't write logs or cache files.
6. Nginx Configuration
server { listen 80; server_name yourdomain.com www.yourdomain.com; root /var/www/yourapp/public; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; index index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \\.php$ { fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\\.(?!well-known).* { deny all; } } Important: The root must point to the /public directory, not the application root. This prevents direct access to your .env file, config files, and application code.
Deployment Steps
7. Clone and Configure
cd /var/www git clone git@github.com:youruser/yourapp.git cd yourapp # Install dependencies composer install --optimize-autoloader --no-dev # Copy environment file cp .env.production .env # Generate application key php artisan key:generate 8. Run Migrations
php artisan migrate --force The --force flag is required in production because Laravel asks for confirmation by default. If you're using seeders for initial data:
php artisan db:seed --force 9. Laravel Deployment Best Practices: Cache Everything
This is where many developers skip steps. Caching these files significantly improves performance:
# Cache configuration (merges all config files into one) php artisan config:cache # Cache routes (compiles routes into a single file) php artisan route:cache # Cache views (pre-compiles Blade templates) php artisan view:cache # Cache events (if using event discovery) php artisan event:cache Warning: After running config:cache, Laravel ignores your .env file and reads only from the cached config. If you change .env, you must run config:cache again.
10. Build Frontend Assets
npm ci npm run build Use npm ci instead of npm install in production — it's faster and ensures exact versions from your lock file.
11. SSL Certificate
sudo apt install certbot python3-certbot-nginx -y sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com Post-Deployment: Production Essentials
12. Set Up Queue Workers
If your app uses queues (emails, notifications, jobs), set up Supervisor to keep workers running:
sudo apt install supervisor -y Create /etc/supervisor/conf.d/laravel-worker.conf:
[program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/yourapp/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=2 redirect_stderr=true stdout_logfile=/var/www/yourapp/storage/logs/worker.log stopwaitsecs=3600 sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start laravel-worker:* 13. Set Up the Scheduler
Add Laravel's scheduler to cron:
sudo crontab -u www-data -e Add this line:
* * * * * cd /var/www/yourapp && php artisan schedule:run >> /dev/null 2>&1 14. Configure Log Rotation
Prevent logs from filling your disk:
sudo nano /etc/logrotate.d/laravel /var/www/yourapp/storage/logs/*.log { daily missingok rotate 14 compress delaycompress notifempty } Common Deployment Mistakes
Forgetting to cache config after .env changes — Your app uses stale values. Always run php artisan config:cache after changing environment variables.
Leaving debug mode on — Exposes your entire stack. One error page can reveal database passwords, API keys, and file paths.
Not setting up queue workers — Emails don't send, notifications don't fire, jobs pile up silently.
Deploying without --no-dev — Dev dependencies bloat your app and may introduce security vulnerabilities.
Wrong file permissions — Either too open (security risk) or too restrictive (app crashes with permission errors).
No backup strategy — Always have automated database backups before deploying updates.
Quick Deployment Script
Combine everything into a reusable script:
#!/bin/bash # deploy.sh set -e cd /var/www/yourapp echo "Pulling latest code..." git pull origin main echo "Installing dependencies..." composer install --optimize-autoloader --no-dev echo "Running migrations..." php artisan migrate --force echo "Building assets..." npm ci && npm run build echo "Clearing and rebuilding caches..." php artisan config:cache php artisan route:cache php artisan view:cache php artisan event:cache echo "Restarting queue workers..." php artisan queue:restart echo "✅ Deployment complete!" Deploy Laravel with Confidence on DeployBase
Following laravel deployment best practices ensures your application runs smoothly, securely, and performantly in production. A reliable server makes all the difference.
At DeployBase, our VPS plans come with PHP 8.2+, MySQL, Redis, and Nginx pre-configured — everything Laravel needs out of the box. Starting at $5.99/month with NVMe SSD storage, full root access, and email support, you can deploy your Laravel app with confidence.
Get your VPS at DeployBase → — optimized hosting for Laravel applications.