Guide

Deploying Laravel to a Server: 3 Paths, Real Commands, Honest Outcome

Three ways to get Laravel into production: cPanel/FTP (painful), VPS + manual setup (works, wants a sysadmin) and a PaaS (git push). Supervisor, queue workers, cron, Nginx — the real commands are all here.

Author: Skyversal Team

"How do I deploy my Laravel app to a server" has three real answers — and as people who have done all three, we'll show the difference with commands, not marketing. Your choice comes down to two things: how much control you want, and whose phone rings at 3am.

Path 1: cPanel / Shared Hosting — The "I Uploaded Files, Site Opened" Lie

The classic path: FTP the project that ran under php artisan serve into public_html. The site technically opens — then reality starts:

  • composer install can't run (no SSH) → you FTP vendor/, it breaks on first update
  • php artisan migrate → no SSH, no panel equivalent; phpMyAdmin SQL imports are misery
  • queue:work → no persistent processes; the queue never runs
  • schedule:run → "cron" is a URL ping once a minute — fragile
  • APP_ENV=production → lives in .htaccess, gets committed by accident

Outcome: a site that looks alive but is half a Laravel — no queue, no real cron. Our Laravel shared-hosting guide maps this wall fully — if you must stay on that path, start there. But the other two paths here are better.

Path 2: VPS + Manual Setup — The Real Commands

A clean Ubuntu VPS needs all of these done correctly for production Laravel:

1) Stack install

apt update && apt install -y nginx php8.3-fpm php8.3-cli php8.3-mysql \\
  php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip composer nodejs npm

2) Code and dependencies

cd /var/www/app && git pull origin main
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan migrate --force
php artisan config:cache && php artisan route:cache && php artisan view:cache

3) Nginx vhost (the critical line: public/ root)

server {
    listen 80;
    server_name site.com;
    root /var/www/app/public;   # ROOT is public/, NOT the project root!
    index index.php;
    location / { try_files $uri $uri/ /index.php?$query_string; }
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

4) Queue worker — persistent via Supervisor

# /etc/supervisor/conf.d/app-worker.conf
[program:app-worker]
command=php /var/www/app/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
numprocs=2
user=www-data

5) Scheduler — one cron line

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

6) SSL + monitoring + backups

Certbot for SSL; log rotation; an uptime monitor; pg_dump cron — each one is separately your problem. First setup: half a day. Monthly maintenance: a few hours. When supervisor dies at 3am: you.

Path 3: PaaS — Git Push, the Platform Handles the Rest

git push origin main

That's it. The platform detects the framework, runs the build, executes composer install --optimize, migrates, boots the container, attaches SSL. Queue workers and the scheduler are defined as processes inside the same project — no supervisor conf. Zero-downtime: the old process stays up until the new one is healthy.

The Honest Three-Way Table

cPanel/FTPVPS + ManualPaaS
Setup time1 hour (+years of hacks)Half a day to a day10 minutes
Queue/cronNoneSupervisor + cron — you build itBuilt-in
Deploy speedMinutes via FTP, half-file riskSSH script — if you wrote onegit push → 2 min
RollbackRe-upload old filesgit revert + manualOne click
SSLPanel clickCertbot — youAutomatic
Ops loadLow but cappedHigh — full sysadminZero
ControlLowFull (root)Platform boundary

The VPS's single win is control — kernel, custom services, custom networking. You can build everything yourself; the question is do you want to? Our VPS vs PaaS analysis opens the cost side of that decision.

The Decision Formula

  1. A real Laravel app, not WordPress/static → rule out cPanel.
  2. Is Linux ops your job or your hobby? Yes → VPS. No → PaaS.
  3. When supervisor dies at 3am, who do you want waking up? That's your answer.

On Skyversal, web + worker + cron + DB run together inside one project — no triple-invoice dyno model. The environment variables guide and hosting guide cover migration details; pricing is in TRY.

FAQ

Laravel "works" on cPanel — why move?

An opening site ≠ a working application. Without queue, scheduler and composer, half of Laravel is disabled — and every deploy risks half-written files.

What gets forgotten most on a VPS?

Nginx root pointing at public/ (not the project root!), storage/ and bootstrap/cache permissions, supervisor's www-data user, and the schedule:run cron line — the four classic sources of "site works but X doesn't".

How are queues and cron defined on a PaaS?

As processes inside the project: queue:work is a worker process, schedule:run a scheduled task in the panel. No supervisor conf, no crontab editing.

Anything different for Laravel 12?

Same flow — just PHP 8.2+ and current composer. Version notes live in our Laravel 12 upgrade guide.

Last updated: November 5, 2026