How to deploy Laravel on an Ubuntu VPS
By Andrea Pollastri · Last updated: · free to read, no paywall
A $5–7/month VPS is still the cheapest, most flexible way to run Laravel in production — if you set it up properly. This guide walks through the full production stack, every manual step, the one-command alternative, and the operational habits that keep a server healthy for years.
Why a VPS (and when not)
Shared hosting can't run queue workers, WebSockets or Laravel Octane properly, and managed PaaS platforms charge for convenience with usage-based pricing. A VPS from Hetzner, DigitalOcean, Vultr or Linode gives you root access, predictable billing and enough headroom to host several Laravel apps on one machine.
- Sizing: 1 vCPU / 2 GB RAM is a comfortable starting point for a production app with a database, queue worker and cache on the same box. Add swap on anything under 4 GB.
- Ubuntu version: use a current LTS — Ubuntu 24.04 or 26.04. Skip interim releases for production.
- When not to use a VPS: if nobody on the team can respond to a server alert, a managed platform like Laravel Cloud is the safer trade — you pay to make operations someone else's problem.
The production stack, explained
Every production Laravel server converges on the same components. Understand what each piece does before you automate any of it:
| Component | Role | Notes |
|---|---|---|
| Nginx | Web server / reverse proxy | Serves static assets, proxies PHP requests |
| PHP-FPM or Octane | PHP runtime | FPM is the reliable default; Octane (FrankenPHP) keeps the app booted for high throughput |
| MariaDB / PostgreSQL | Database | Either works with Laravel; pick per app |
| Valkey (Redis-compatible) | Cache, sessions, queues | Open-source Redis fork; drop-in for Laravel |
| Supervisor | Process manager | Keeps queue:work and Horizon alive |
| Cron | Scheduler | One entry: artisan schedule:run every minute |
| UFW + Fail2ban | Firewall / brute-force protection | Default-deny, ban repeated SSH failures |
| Certbot | TLS certificates | Free Let's Encrypt certs with auto-renewal |
| Deployer-style releases | Zero-downtime deploys | Releases directory + symlink swap |
The manual setup, step by step
This is the honest, unabridged checklist. Budget 2–4 hours the first time, and remember you'll own every one of these choices at upgrade time too.
- Create a sudo user and lock down SSH.
adduser deploy, install your public key, then disable root login and password auth in/etc/ssh/sshd_config. - Enable the firewall.
ufw allow OpenSSH http httpsthenufw enable. Install Fail2ban for SSH brute-force protection. - Install Nginx.
apt install nginx. - Install PHP. Add a maintained PHP repository, then install
php8.x-fpmwith the extensions Laravel needs: mbstring, xml, curl, zip, intl, mysql (or pgsql), redis, gd, opcache. - Tune PHP for production. Enable opcache, set sane
memory_limitandupload_max_filesize, turnexpose_phpoff. - Install Composer globally.
- Install MariaDB, run
mariadb-secure-installation, create a database and a dedicated user per app — never reuse root. - Install Valkey (or Redis) for cache, sessions and queues.
- Write the Nginx server block. Document root points at
current/public,try_filesfalls back toindex.php, FastCGI passes to the app's PHP-FPM socket. - Ship the code. Clone into a
releases/directory,composer install --no-dev --optimize-autoloader, copy.env, runphp artisan key:generate,storage:link, and fix permissions so onlystorage/andbootstrap/cache/are writable. - Migrate and cache.
php artisan migrate --forcethenconfig:cache,route:cache,view:cache. - Configure Supervisor to run
php artisan queue:work(or Horizon) and restart it on every deploy. - Add the scheduler cron:
* * * * * php artisan schedule:run. - Issue TLS certificates with Certbot and force HTTPS.
Now multiply by every app you host, and again by every server — and keep PHP, Nginx and the OS patched forever. It's all doable; it's just undifferentiated work.
The one-command alternative
Everything in the previous section is exactly what Cipi automates. On a fresh Ubuntu 24.04/26.04 VPS:
In about ten minutes you get the full stack — Nginx, PHP, MariaDB, Valkey, Supervisor, UFW, Fail2ban,
Certbot, Deployer — plus hardening you'd otherwise do by hand: root login disabled, key-only SSH for the
admin user, and a random root password stored in /etc/cipi/server.json. Then each app is one
more command:
That provisions an isolated system user, PHP-FPM pool, Nginx vhost and database per app,
connects GitHub or GitLab with deploy keys and webhooks for zero-downtime Git deploys, and wires queue
workers and the scheduler. SSL is cipi ssl install; PostgreSQL is
cipi db install pgsql. See the getting started
guide for the full walkthrough, or the comparison hub if
you're evaluating it against Forge, Ploi and friends.
Post-deploy operations that matter
Getting to "it works" is half the job. These habits are what separate a server that lasts years from one that surprises you:
- Backups you have actually restored. Automate database and storage backups to
S3-compatible storage (
cipi backup configurehandles schedule and retention). Any S3 target works — including Johnny, an open-source S3-compatible object storage you can run on a second VPS for genuinely independent off-site copies. Do a restore drill quarterly: an untested backup is a hope, not a plan. - Exception tracking from day one. Production errors need to reach you before users do. Boogle is a self-hosted exception tracker that keeps error data on your own infrastructure — a good fit if you chose a VPS for data ownership in the first place.
- Health checks and logs. Cipi 5 ships app health checks, and
cipi app logstails Laravel, Nginx and deploy logs without SSH gymnastics. - Patching discipline. Unattended OS security updates plus a deliberate PHP upgrade
path (
cipi php upgrademanages PHP security patches with a weekly check) beat "we'll update when we remember". - Tame your SSH sprawl. Once you run more than two servers, connection details rot in your shell history. Conn is a tiny Bash tool that manages servers as named aliases — pairs nicely with a fleet of Cipi machines.
Common mistakes to avoid
- Deploying as root. One compromised app owns the whole box. Use per-app users — this is why Cipi isolates every app under its own system user.
- APP_DEBUG=true in production. Debug pages leak env vars, credentials and paths. It's the single most common self-inflicted Laravel breach.
- Committing
.envor leaving.git/web-accessible. - 777 permissions "to make the error go away". Only
storage/andbootstrap/cache/need to be writable by the runtime user. - No queue worker. Mail and jobs silently pile up in the queue table forever.
- Skipping opcache — free 2–3x throughput lost.
- No swap on small instances — Composer and asset builds OOM-kill at the worst time.
- Untested SSL renewals. Certificates auto-renew until the day they don't; monitor expiry.
Put this into practice with Cipi
Cipi is the free, open-source deploy CLI referenced throughout this guide: one command turns a fresh Ubuntu VPS into a hardened production server for Laravel — Nginx, PHP-FPM or Octane, MariaDB or PostgreSQL, queues, scheduler, SSL and zero-downtime Git deploys included.
Frequently asked questions
What are the minimum server requirements for Laravel in production?
A single vCPU with 2 GB RAM runs a typical Laravel app with database, cache and a queue worker comfortably; add swap below 4 GB. Octane, Horizon and heavy build steps benefit from 4 GB. Cipi installs its full stack on any fresh Ubuntu 24.04/26.04 VPS.
Can I host multiple Laravel apps on one VPS?
Yes, and it is usually the most cost-effective setup. The key is isolation: each app should have its own system user, PHP-FPM pool and database credentials so one compromised or misbehaving app cannot touch the others. Cipi provisions exactly that isolation automatically with cipi app create.
Should I use PHP-FPM or Laravel Octane?
PHP-FPM is the boring, reliable default and right for most apps. Octane keeps the framework booted between requests and shines on high-traffic APIs and latency-sensitive endpoints. With Cipi you can run both on the same server and create Octane apps with cipi app create --octane.
How do I keep PHP updated on Ubuntu?
Track a maintained PHP repository and apply security patches promptly rather than waiting for distro upgrades. Cipi manages PHP security patches itself with a weekly check (cipi php upgrade), so servers do not silently fall behind.
Do I still need Laravel Forge if I manage my own VPS?
No. Forge is a paid SaaS that automates the same stack this guide describes. If you want that automation without the subscription or the third-party dependency, Cipi covers the same workflow free and open source — see the detailed Cipi vs Forge comparison.