
Deploying Laravel on Nginx with PHP-FPM
You've built an amazing Laravel application on your local machine. It's fast, beautiful, and does exactly what you want. But now comes the exciting (and slightly nerve-wracking) part: getting it online for the world to see.
I remember my first Laravel deployment. I spent hours trying to figure out why my beautiful local application was showing "502 Bad Gateway" errors in production. The terminology was confusing, the configurations seemed endless, and I was convinced I'd broken everything.
But here's the good news: deploying Laravel on Nginx with PHP-FPM isn't as complicated as it seems. Once you understand how the pieces fit together, it becomes a repeatable process that you can do with confidence.
In this guide, I'll walk you through deploying a Laravel application step by step. We'll cover everything from server setup to final configuration, with plenty of troubleshooting tips along the way. Let's get your Laravel application online! ๐
Understanding the Architecture
Before we dive in, let's understand what we're building:
- Nginx: The web server that handles incoming HTTP requests
- PHP-FPM: The PHP FastCGI Process Manager that executes your Laravel code
- Laravel: Your PHP application framework
- MySQL/PostgreSQL: Your database (we'll assume you have this set up)
Think of it like this: Nginx is the front door that receives visitors, PHP-FPM is the kitchen that prepares your application's response, and Laravel is the recipe that tells the kitchen what to cook.
Prerequisites: What You Need Before Starting
Make sure you have these ready before we begin:
- Ubuntu Server (20.04 or 22.04 recommended)
- SSH Access with sudo privileges
- Domain Name pointed to your server's IP
- Laravel Application ready to deploy (we'll cover getting it to the server)
- Basic comfort with the command line
Step 1: Setting Up the Server Foundation
First, let's make sure your server is ready for Laravel. We'll install the LEMP stack (Linux, Nginx, MySQL, PHP).
Update Your System
sudo apt update
sudo apt upgrade -y
Install Nginx
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Install PHP and Required Extensions
Laravel needs specific PHP extensions to function properly:
sudo apt install php-fpm php-mysql php-mbstring php-xml php-bcmath php-curl php-zip php-gd php-json -y
Install Composer
Composer is PHP's dependency manager and essential for Laravel:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer
Install Git
We'll use Git to clone your Laravel application:
sudo apt install git -y
Step 2: Configuring PHP-FPM for Laravel
PHP-FPM needs a few tweaks to work optimally with Laravel.
Check Your PHP Version
php -v
Take note of your PHP version (like 8.1, 8.2, etc.) as we'll need it for configuration.
Configure PHP-FPM
Open the PHP-FPM configuration file:
sudo nano /etc/php/[your-php-version]/fpm/pool.d/www.conf
Find and adjust these settings:
; Change the user and group to www-data
user = www-data
group = www-data
; Adjust process manager settings
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 8
; Set proper permissions
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
Restart PHP-FPM
sudo systemctl restart php[version]-fpm
sudo systemctl enable php[version]-fpm
(Replace [version] with your actual PHP version, like php8.1-fpm)
Step 3: Setting Up Your Laravel Application
Now let's get your Laravel code onto the server.
Create Project Directory
sudo mkdir -p /var/www/your-app-name
sudo chown -R $USER:$USER /var/www/your-app-name
Clone Your Laravel Application
If your project is on GitHub:
cd /var/www/your-app-name
git clone https://github.com/yourusername/your-laravel-app.git .
Alternative: If you're deploying from a local project, you can use SCP or rsync:
# From your local machine
scp -r /path/to/your/laravel-project/* user@your-server:/var/www/your-app-name/
Install Dependencies
cd /var/www/your-app-name
composer install --optimize-autoloader --no-dev
Create Environment File
cp .env.example .env
nano .env
Configure your production environment:
APP_NAME=YourAppName
APP_ENV=production
APP_KEY=base64:your-generated-key-here
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_database_user
DB_PASSWORD=your_secure_password
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
Generate Application Key
php artisan key:generate
Optimize Your Application
php artisan config:cache
php artisan route:cache
php artisan view:cache
Step 4: Configuring Nginx for Laravel
This is where many people get stuck, but don't worryโwe'll configure Nginx to properly handle Laravel's routing.
Create Nginx Configuration File
sudo nano /etc/nginx/sites-available/your-app-name
Add Laravel-Specific Configuration
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/your-app-name/public;
index index.php index.html index.htm;
# Log files
access_log /var/log/nginx/your-app-name.access.log;
error_log /var/log/nginx/your-app-name.error.log;
# Handle static files directly
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM configuration
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php[version]-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to .htaccess files
location ~ /\.ht {
deny all;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
}
Important: Replace [version] with your PHP version (like 8.1).
Enable Your Site
sudo ln -s /etc/nginx/sites-available/your-app-name /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 5: Setting Up Proper File Permissions
File permissions are crucial for Laravel to work correctly.
Set Ownership and Permissions
cd /var/www/your-app-name
# Set ownership
sudo chown -R www-data:www-data storage bootstrap/cache
# Set permissions
sudo chmod -R 775 storage
sudo chmod -R 775 bootstrap/cache
Optional: Set Up Cron Job for Scheduler
If your Laravel application uses scheduled tasks:
crontab -e
Add this line:
* * * * * cd /var/www/your-app-name && php artisan schedule:run >> /dev/null 2>&1
Step 6: Database Setup
If you haven't already, let's set up your database.
Create Database and User
sudo mysql -u root -p
In MySQL:
CREATE DATABASE your_database_name;
CREATE USER 'your_database_user'@'localhost' IDENTIFIED BY 'your_secure_password';
GRANT ALL PRIVILEGES ON your_database_name.* TO 'your_database_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Run Database Migrations
cd /var/www/your-app-name
php artisan migrate --force
Step 7: Adding SSL Certificate (Optional but Recommended)
Let's secure your Laravel application with HTTPS.
Install Certbot
sudo apt install certbot python3-certbot-nginx -y
Obtain SSL Certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the prompts to configure automatic HTTPS redirection.
Step 8: Testing Your Deployment
Let's make sure everything is working correctly.
Test PHP Processing
curl -I http://yourdomain.com
You should see a 200 OK response.
Check Laravel Application
Open your browser and navigate to your domain. You should see your Laravel application!
Verify Error Pages
Try accessing a non-existent route to ensure 404 errors are handled properly.
Common Issues and Troubleshooting
Even with the best setup, things can go wrong. Here are the most common issues and how to fix them:
"502 Bad Gateway" Error
Cause: PHP-FPM isn't running or Nginx can't connect to it.
Solution:
# Check if PHP-FPM is running
sudo systemctl status php[version]-fpm
# Start it if needed
sudo systemctl start php[version]-fpm
# Check PHP-FPM socket
sudo ls -la /var/run/php/php[version]-fpm.sock
"404 Not Found" for Laravel Routes
Cause: Nginx isn't properly forwarding requests to Laravel's index.php.
Solution: Ensure your Nginx configuration has the correct `try_files` directive:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
"File Permission Denied" Errors
Cause: Incorrect permissions on storage or cache directories.
Solution:
cd /var/www/your-app-name
sudo chown -R www-data:www-data storage bootstrap/cache
sudo chmod -R 775 storage bootstrap/cache
White Screen of Death
Cause: PHP errors not displaying due to production environment settings.
Solution: Check Laravel logs:
tail -f /var/www/your-app-name/storage/logs/laravel.log
Database Connection Failed
Cause: Incorrect database credentials or MySQL isn't running.
Solution:
# Check MySQL status
sudo systemctl status mysql
# Test database connection
mysql -u your_database_user -p your_database_name
Performance Optimization Tips
Once your Laravel app is running, consider these optimizations:
Enable Opcache
sudo nano /etc/php/[version]/fpm/conf.d/10-opcache.ini
Set these values:
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=4000
opcache.revalidate_freq=0
Configure Nginx Caching
Add caching to your Nginx configuration:
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Use Queue Workers
For background jobs, set up queue workers:
php artisan queue:work --daemon
Production Best Practices
- Always use HTTPS in production
- Set APP_DEBUG=false in your .env file
- Regularly update dependencies and Laravel itself
- Set up monitoring for uptime and performance
- Implement regular backups of your database and files
- Use environment variables for all sensitive configuration
Deployment Workflow for Future Updates
Once your Laravel app is deployed, here's a simple workflow for future updates:
# Pull latest changes
cd /var/www/your-app-name
git pull origin main
# Install new dependencies
composer install --optimize-autoloader --no-dev
# Clear and cache Laravel
php artisan config:clear
php artisan cache:clear
php artisan view:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Run migrations if needed
php artisan migrate --force
# Restart services if needed
sudo systemctl reload nginx
sudo systemctl restart php[version]-fpm
Wrapping Up
Congratulations! ๐ You've successfully deployed your Laravel application on Nginx with PHP-FPM. That's a significant achievement, and you now have a solid foundation for serving your Laravel application to the world.
Remember, deployment gets easier with practice. The first time might feel overwhelming, but each deployment will build your confidence and understanding. Keep this guide handy, and don't be afraid to experiment in a staging environment before making changes to production.
Your Laravel application is now live and ready to serve users. Whether you're building a startup, a personal project, or an enterprise application, this setup will provide the performance and reliability you need.
Happy coding and happy deploying! ๐