Laravel VPS Deployment Guide: Nginx Configuration, PHP-FPM Pools & OPcache Tuning
A production deployment runbook for Laravel on Linux KVM VPS, covering Nginx server blocks, PHP-FPM process pools, OPcache tuning, and queue management.
Deploying a production Laravel application on a Linux KVM VPS involves configuring Nginx to route requests to the public document root, tuning PHP-FPM worker pools for concurrency, and enabling OPcache precompilation. Setting up automated process management with Supervisor ensures robust background queue execution. Following documented deployment standards eliminates security misconfigurations and unlocks high request throughput.
Directory Security and Document Root Isolation
A critical operational requirement when deploying Laravel is pointing the web server's document root strictly to the application's public/ subfolder. Pointing the document root to the project root exposes sensitive files—such as .env containing database credentials and API secrets—directly to public web requests.
When provisioning your application on VPSWala's KVM VPS, clone your repository into a secure directory such as /var/www/laravel_app and ensure ownership is assigned to the web service account (www-data):
sudo chown -R www-data:www-data /var/www/laravel_app/storage /var/www/laravel_app/bootstrap/cache
sudo chmod -R 775 /var/www/laravel_app/storage /var/www/laravel_app/bootstrap/cacheConfiguring a Production-Ready Nginx Server Block
Create an optimized Nginx server block under /etc/nginx/sites-available/laravel.conf that routes incoming requests to index.php, manages FastCGI buffering, and denies access to hidden dotfiles:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/laravel_app/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
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.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_hide_header X-Powered-By;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
}
location ~ /\.(?!well-known).* {
deny all;
}
}Tuning PHP-FPM Worker Pools for Concurrency
PHP-FPM processes dynamic PHP execution threads. Default pool configurations often allocate too few worker processes, causing request timeouts under concurrent web traffic. Edit /etc/php/8.3/fpm/pool.d/www.conf to calibrate workers based on your VPS memory capacity:
[www]
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 1000- pm.max_children = 50: If each PHP process consumes approximately 40 MB of RAM, 50 children require ~2 GB of memory under peak concurrency. Adjust this number according to total VPS RAM.
- pm.max_requests = 1000: Recycles worker processes after handling 1,000 requests, preventing memory leaks in third-party packages from bloating memory.
Enabling OPcache for Bytecode Precompilation
OPcache improves PHP performance by compiling script bytecode once and storing it directly in shared RAM, eliminating the overhead of parsing PHP source files on every web request. Configure the following parameters in /etc/php/8.3/fpm/php.ini:
[opcache]
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0
opcache.save_comments = 1
opcache.revalidate_freq = 0Critical Production Notice: Setting opcache.validate_timestamps = 0 delivers maximum throughput because PHP stops checking the filesystem for modified files. However, this means subsequent code deployments will not take effect until PHP-FPM is reloaded. Always include sudo systemctl reload php8.3-fpm in your deployment scripts.
Running Laravel Production Artisan Caching
During deployment, execute Laravel's internal optimization commands to compile configuration, routes, and Blade templates into static cached arrays:
# Install dependencies without development packages
composer install --optimize-autoloader --no-dev
# Compile configuration, routes, and views into cache
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cacheConfiguring Cron Task Scheduling and Automated Jobs
Laravel includes a built-in task scheduler that manages recurring console commands. Rather than configuring multiple cron entries in Linux, create a single entry in the system crontab that executes every minute:
# Open crontab for www-data user
crontab -u www-data -e
# Add Laravel schedule worker entry
* * * * * php /var/www/laravel_app/artisan schedule:run >> /dev/null 2>&1This single entry allows you to define all future scheduled maintenance, data backups, and report generation routines directly inside Laravel's routes/console.php or app/Console/Kernel.php file.
Automating Background Queues with Supervisor
Laravel's queue workers handle asynchronous tasks such as sending emails, processing payments, and generating reports. Use Supervisor to keep queue workers running continuously:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel_app/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/laravel_app/storage/logs/worker.logFor applications demanding extreme request-per-second performance, consider deploying on high-frequency hardware such as VPSWala's AMD Ryzen 9 9950X VPS plans equipped with Zen 5 cores and DDR5 memory.
Integrating Redis for High-Speed Session and Queue Storage
On high-concurrency production applications, storing session states and queue jobs in the primary relational database introduces unnecessary table locks and disk I/O overhead. Utilizing an in-memory Redis instance on your KVM VPS eliminates database contention:
# Install php-redis extension and configure Laravel environment
sudo apt install -y php8.3-redis redis-server
# Update application configuration variables
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redisStoring sessions in Redis ensures sub-millisecond session validation on every HTTP request, allowing your Nginx and PHP-FPM web stack to handle substantial concurrent user sessions without saturating storage throughput.
Sources
Not sure which size?
Send the stack, get a size.
Tell us the operating system, application stack, current traffic, database size and where it hurts today. You get a sizing recommendation, the matching plan and a price.
Related
MongoDB VPS Requirements: WiredTiger Cache Sizing, Memory & NVMe Storage
A technical database sizing guide for MongoDB on Linux KVM VPS, covering WiredTiger cache calculations, memory allocation, and swap tuning.
VPS Hosting for Varanasi: Which VPSWala Node to Pick and How to Test It
A technical node selection and ICMP diagnostic guide for Varanasi developers and businesses deploying KVM Cloud VPS instances across India.
FastAPI VPS Requirements: Uvicorn Workers, Memory Tuning & Production Sizing
Learn how to size Linux VPS hardware for FastAPI production deployments with Uvicorn worker calculations, systemd service management, and Nginx proxy tuning.