
August 16, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Figuring out how to deploy Laravel on Ubuntu VPS with Nginx correctly prevents the majority of production outages I troubleshoot for clients. Most failures stem from incorrect file permissions, missing PHP-FPM socket configuration, or neglected OPcache invalidation rather than application bugs. This guide provides the exact server configuration, security hardening, and deployment workflow I use for production Laravel systems in 2026.
/public directory, set strict ownership to www-data, enable SSL via Certbot, and automate releases using a symlink-based deployment tool like Deployer.Before touching the server, ensure your local development environment matches production. If you are evaluating whether your current team can handle this infrastructure or if you need specialized help, reviewing the expectations for a Laravel developer in Nepal clarifies the skill gap between shared hosting management and true VPS administration. Getting the foundation right avoids costly rewrites later.
How do you prepare Ubuntu 24.04 for a Laravel production stack?
Ubuntu 24.04 LTS is the current standard for production PHP deployments in 2026. It ships with newer system libraries that align well with Laravel 12.x requirements. Do not use the default php package from the main repository; it often lags behind the latest stable release. Instead, add the Ondřej Surý PPA to get PHP 8.4 with all necessary FPM extensions.
sudo apt update && sudo apt upgrade -y
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install -y nginx \
php8.4-fpm php8.4-mysql php8.4-pgsql \
php8.4-xml php8.4-curl php8.4-zip \
php8.4-mbstring php8.4-bcmath \
php8.4-gd php8.4-intl php8.4-redis \
unzip git curl fail2ban ufw After installation, verify the active PHP version and FPM status. A common mistake on fresh servers is having multiple PHP versions installed but the wrong one enabled in Nginx. Run php8.4 -v to confirm the CLI version, then check the FPM socket path:
sudo systemctl status php8.4-fpm
# Expected socket: /run/php/php8.4-fpm.sock Security hardening must happen before deploying any code. Configure UFW to allow only SSH, HTTP, and HTTPS. Enable fail2ban immediately to protect against brute-force attacks on SSH and future web endpoints. For legal-tech portals handling sensitive client documents, this baseline protection is non-negotiable.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo systemctl enable --now fail2ban How do you configure Nginx and PHP-FPM for Laravel securely?
The Nginx server block is where most deployments fail. Laravel requires all requests to route through index.php, and the document root must point exclusively to the /public directory. Never expose the project root to the web; doing so leaks .env files and source code. Create a new site configuration at /etc/nginx/sites-available/laravel-app:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/laravel-app/current/public;
index index.php;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
}
location ~ /\.(?!well-known).* {
deny all;
}
access_log /var/log/nginx/laravel-app-access.log;
error_log /var/log/nginx/laravel-app-error.log;
} Enable the site and test the configuration before reloading. The fastcgi_param SCRIPT_FILENAME line using $realpath_root is critical for symlink-based deployments; without it, PHP resolves the symlink target incorrectly during atomic swaps, causing intermittent 404s or serving stale files.
sudo ln -s /etc/nginx/sites-available/laravel-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx PHP-FPM tuning matters as much as Nginx config. Edit /etc/php/8.4/fpm/pool.d/www.conf to match your server resources. On a 2GB RAM VPS, start with 10-15 workers. Set pm = dynamic with pm.max_children = 15, pm.start_servers = 5, and pm.max_requests = 500 to prevent memory leaks from long-running processes. Restart FPM after changes:
sudo nano /etc/php/8.4/fpm/pool.d/www.conf
sudo systemctl restart php8.4-fpm What are the correct file permissions and ownership for Laravel?
Incorrect permissions cause more deployment failures than any other issue. The web server user (www-data) must own the storage and cache directories, while the deploy user should own the application code. This separation prevents the web process from modifying source files, reducing attack surface.
- Create the base directory structure outside the web root:
sudo mkdir -p /var/www/laravel-app/{current,releases,shared} - Set ownership:
sudo chown -R deploy:www-data /var/www/laravel-app - Configure shared directories for persistent data across deployments:
storage/,.env, and any uploaded media folders - Set restrictive permissions:
find /var/www/laravel-app -type d -exec chmod 755 {} \;andfind /var/www/laravel-app -type f -exec chmod 644 {} \; - Grant write access only where needed:
sudo chown -R www-data:www-data /var/www/laravel-app/shared/storage
On projects like legal service portals where document uploads are frequent, I create a separate uploads/ directory under shared/ with www-data ownership. This keeps user-generated content isolated from application code and survives deployments without permission resets. Never make the entire project writable by www-data; this is a security vulnerability that allows compromised PHP processes to inject malicious code.
How do you optimize PHP OPcache and SSL for Laravel performance?
OPcache is mandatory for production Laravel. Without it, PHP recompiles every file on each request, adding 200-500ms latency. Edit /etc/php/8.4/fpm/conf.d/10-opcache.ini with these validated settings for Laravel 12:
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.jit=disable Setting validate_timestamps=0 means PHP never checks for file changes, maximizing performance. The tradeoff is that you must explicitly reset OPcache after every deployment. Add opcache_reset(); to your deploy script's post-release hook, or use the cachetool utility to clear it via CLI without restarting FPM. JIT is disabled because Laravel's workload is I/O-bound; JIT adds overhead without measurable benefit for typical web applications.
SSL termination happens at Nginx. Use Certbot with the Nginx plugin for automatic certificate management. After obtaining certificates, Certbot modifies your server block to redirect HTTP to HTTPS and configure modern TLS parameters. Verify your SSL configuration scores A+ on SSL Labs by ensuring HSTS headers and OCSP stapling are enabled.
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run For sites serving Nepali users alongside global traffic, consider Cloudflare's free tier in front of your VPS. This provides DDoS protection and edge caching without changing your origin server configuration. However, ensure your Nginx config trusts Cloudflare's IP ranges so Laravel receives the real client IP for rate limiting and logging.
What is the most reliable zero-downtime deployment workflow?
Manual deployments via git pull in production cause downtime and inconsistency. Use Deployer 7 for atomic, symlink-based releases. This approach keeps the previous release intact, enabling instant rollback if something breaks. Install Deployer globally on your deployment machine:
composer global require deployer/deployer:^7.0 Create a deploy.php in your project root configured for Ubuntu 24.04 + Nginx:
<?php
namespace Deployer;
require 'recipe/laravel.php';
host('production')
->set('remote_user', 'deploy')
->set('hostname', 'your-server-ip')
->set('deploy_path', '/var/www/laravel-app')
->set('branch', 'main');
set('keep_releases', 3);
set('http_user', 'www-data');
task('deploy:opcache_reset', function () {
run('sudo -u www-data php {{release_path}}/artisan opcache:reset');
});
after('deploy:symlink', 'deploy:opcache_reset');
after('deploy:failed', 'deploy:unlock'); This configuration handles Composer installation, migration, cache clearing, and symlink swapping atomically. The opcache_reset task runs after the symlink changes, ensuring PHP picks up new files immediately. Store sensitive environment variables in /var/www/laravel-app/shared/.env — never commit them to Git. Link shared directories in your deploy config so they persist across releases.
| Deployment Method | Downtime | Rollback Speed | Complexity | Best For |
|---|---|---|---|---|
| Manual git pull | High (minutes) | Slow (manual revert) | Low | Hobby projects only |
| FTP/SFTP upload | Very High | Impossible | Medium | Never use for Laravel |
| Deployer 7 (symlink) | Zero (<1s swap) | Instant (dep rollback) | Medium | Production Laravel apps |
| Docker/Kubernetes | Zero | Fast (image rollback) | High | Large teams/microservices |
On sister sites sharing infrastructure, I standardize on Deployer 7 + GitLab CI. The pipeline runs tests, builds frontend assets locally (the server has no Node.js), commits the compiled assets as artifacts, then triggers Deployer. This eliminates build-time dependencies on the production server and ensures identical artifacts across staging and production.
Deploy Laravel on Ubuntu VPS with Nginx Reliably
Mastering how to deploy Laravel on Ubuntu VPS with Nginx requires treating infrastructure as part of the application, not an afterthought. Correct permissions, validated OPcache settings, and atomic deployments separate production systems from fragile prototypes. Every step in this guide reflects configurations running on live client sites in 2026.
If your team lacks bandwidth to maintain this stack or you need a second opinion on an existing deployment, reach out directly. I regularly audit Laravel infrastructure for businesses in Nepal and internationally, identifying permission issues, missing optimizations, and deployment risks before they cause outages. For deeper context on building maintainable Laravel applications, review modern Laravel architecture best practices to ensure your codebase supports reliable operations.

