Laravel is the most popular PHP framework for building web applications. This guide covers deploying a Laravel project on a GoZen VPS running Ubuntu 22.04 or 24.04 with Nginx, PHP-FPM, and MySQL.

Prerequisites

Step 1: Install PHP and Required Extensions

Laravel needs PHP 8.2+ and several extensions:

  sudo apt update && sudo apt upgrade -y

# Add the PHP repository
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Install PHP and extensions
sudo apt install php8.3 php8.3-fpm php8.3-cli php8.3-mysql php8.3-pgsql \
  php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip php8.3-bcmath \
  php8.3-gd php8.3-intl php8.3-redis php8.3-opcache -y
  

Verify the install:

  php -v
# Should show PHP 8.3.x
  

Step 2: Install Composer

Composer manages PHP dependencies:

  curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version
  

Step 3: Install and Configure MySQL

  sudo apt install mysql-server -y
sudo mysql_secure_installation
  

Create a database and user for your app:

  sudo mysql
  
  CREATE DATABASE laravel_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel'@'localhost' IDENTIFIED BY 'your-strong-password-here';
GRANT ALL PRIVILEGES ON laravel_app.* TO 'laravel'@'localhost';
FLUSH PRIVILEGES;
EXIT;
  

If you use PostgreSQL instead, install postgresql postgresql-contrib and adjust the commands accordingly.

Step 4: Install Nginx

  sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
  

Step 5: Deploy Your Laravel Project

Clone the Repository

  sudo mkdir -p /var/www/laravel-app
sudo chown $USER:$USER /var/www/laravel-app

cd /var/www
git clone git@github.com:yourusername/your-laravel-app.git laravel-app
cd laravel-app
  

Install Dependencies

  composer install --optimize-autoloader --no-dev
  

The --no-dev flag skips development packages (PHPUnit, debugbar, etc.) which you don’t need in production.

Configure the Environment

  cp .env.example .env
nano .env
  

Update these values:

  APP_NAME="Your App Name"
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=https://yourdomain.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_app
DB_USERNAME=laravel
DB_PASSWORD=your-strong-password-here

CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
  

Generate the application key:

  php artisan key:generate
  

Set Permissions

  sudo chown -R www-data:www-data /var/www/laravel-app
sudo chmod -R 775 storage bootstrap/cache
  

Run Migrations and Caching

  php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
  

Step 6: Configure Nginx

Create an Nginx server block:

  sudo nano /etc/nginx/sites-available/laravel-app
  
  server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/laravel-app/public;

    index index.php index.html;

    charset utf-8;

    # Handle Laravel routes
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # PHP processing
    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;
    }

    # Block access to dotfiles
    location ~ /\.(?!well-known).* {
        deny all;
    }

    # Cache static assets
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2|woff|ttf)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}
  

Enable the site:

  sudo ln -s /etc/nginx/sites-available/laravel-app /etc/nginx/sites-enabled/

# Remove default site if this is the primary app
sudo rm -f /etc/nginx/sites-enabled/default

sudo nginx -t
sudo systemctl reload nginx
  

Step 7: Install SSL

  sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
  

Test auto-renewal:

  sudo certbot renew --dry-run
  

Step 8: Set Up Queue Workers

If your app uses queues (email, jobs, notifications), set up a Supervisor process:

  sudo apt install supervisor -y
  

Create a worker config:

  sudo nano /etc/supervisor/conf.d/laravel-worker.conf
  
  [program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel-app/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/laravel-app/storage/logs/worker.log
stopwaitsecs=3600
  

Start the workers:

  sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
  

Step 9: Set Up the Scheduler

Laravel’s task scheduler needs a cron entry:

  sudo crontab -u www-data -e
  

Add:

  * * * * * cd /var/www/laravel-app && php artisan schedule:run >> /dev/null 2>&1
  

Deploying Updates

When you push new code, run this on the server:

  cd /var/www/laravel-app

# Pull latest code
git pull origin main

# Install/update dependencies
composer install --optimize-autoloader --no-dev

# Run migrations
php artisan migrate --force

# Clear and rebuild caches
php artisan config:cache
php artisan route:cache
php artisan view:cache

# Restart queue workers
sudo supervisorctl restart laravel-worker:*
  

You can wrap this in a deploy script:

  nano /var/www/deploy-laravel.sh
  
  #!/bin/bash
set -e

cd /var/www/laravel-app

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 "Rebuilding caches..."
php artisan config:cache
php artisan route:cache
php artisan view:cache

echo "Restarting workers..."
sudo supervisorctl restart laravel-worker:*

echo "Deploy complete."
  
  chmod +x /var/www/deploy-laravel.sh
  

For automated deployments via GitHub, see Deploy from GitHub to Your Server.

Performance Tuning

PHP-FPM Settings

For a VPS with 4GB RAM, tune the pool:

  sudo nano /etc/php/8.3/fpm/pool.d/www.conf
  
  pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
  

Restart:

  sudo systemctl restart php8.3-fpm
  

OPcache

OPcache should be enabled by default. Verify:

  php -i | grep opcache.enable
  

If you need to tune it:

  sudo nano /etc/php/8.3/fpm/conf.d/10-opcache.ini
  
  opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
  

Setting validate_timestamps=0 means PHP won’t check if files have changed. This is faster but requires you to restart PHP-FPM after each deploy:

  sudo systemctl restart php8.3-fpm
  

Redis

If you’re using Redis for caching, sessions, and queues (recommended):

  sudo apt install redis-server -y
sudo systemctl enable redis-server
  

See How to Set Up Redis Caching for the full configuration.

Troubleshooting

ProblemFix
500 error after deployCheck storage/logs/laravel.log. Usually a missing .env key or failed migration
“Permission denied” on storageRun sudo chown -R www-data:www-data storage bootstrap/cache
“Class not found”Run composer dump-autoload
Blank page with no errorsSet APP_DEBUG=true temporarily to see the error, then turn it off
Nginx shows default pageCheck server_name matches your domain. Verify the symlink in sites-enabled
Queue jobs not processingCheck Supervisor: sudo supervisorctl status. Check the worker log
Slow response timesEnable OPcache, use Redis for sessions/cache, check database query performance

Last updated 19 Apr 2026, 23:46 +0300. history

Was this page helpful?