Skip to content
Extra 20% off HostingerWEBHOST2026Get my link →
DiscountOffer.Store
Tutorials

Deploy Laravel on a Hostinger VPS (Nginx, PHP-FPM, MySQL, queues)

11 min read

From a clean Ubuntu server to a production Laravel app: PHP-FPM, Composer, MySQL, the correct Nginx config, storage permissions, queue workers, the scheduler and free HTTPS.

Shared hosting or VPS for Laravel?

A simple Laravel site can run on Hostinger's Premium or Business shared plans, which include SSH, Composer and a recent PHP version. You point the domain at the `public` folder and you're done.

Pick a VPS once you need queue workers that run all the time, Redis, WebSockets (Reverb), or full control over PHP extensions. That's the setup this guide covers.

Before you start

You'll need the groundwork done first:

  • Ubuntu 24.04 LTS on the VPS, secured with a sudo user and a firewall that allows 80 and 443.
  • An A record for your domain pointing at the server.
  • Your app in a Git repository the server can pull from.

Step 1 — Install PHP, Nginx, MySQL and Composer

Ubuntu 24.04 ships PHP 8.3, which meets the requirements of current Laravel releases. Check the `php` constraint in your `composer.json`. If you're on Ubuntu 26.04, swap `8.3` in the package names for whatever `php -v` reports.

bash
sudo apt update
sudo apt install -y nginx mysql-server unzip git \
  php8.3-fpm php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml \
  php8.3-curl php8.3-zip php8.3-bcmath php8.3-intl php8.3-gd

sudo apt install -y composer
composer --version

Step 2 — Create the database

Give the app its own MySQL user with access to one database, never root.

bash
sudo mysql <<'SQL'
CREATE DATABASE laravel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel'@'localhost' IDENTIFIED BY 'use-a-long-random-password';
GRANT ALL PRIVILEGES ON laravel.* TO 'laravel'@'localhost';
FLUSH PRIVILEGES;
SQL

Step 3 — Clone, install and configure

The deploy user owns the code. The web server's `www-data` group only needs write access to `storage` and `bootstrap/cache`, which is the cause of most 500 errors on a fresh Laravel server.

bash
sudo mkdir -p /var/www && sudo chown $USER:$USER /var/www
cd /var/www
git clone https://github.com/you/your-app.git laravel
cd laravel

composer install --no-dev --optimize-autoloader
cp .env.example .env
php artisan key:generate
Edit .env: the lines that matter in production
bash
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=use-a-long-random-password
Permissions, migrations and caches:
bash
sudo chown -R $USER:www-data storage bootstrap/cache
sudo chmod -R 775 storage bootstrap/cache

php artisan migrate --force
php artisan storage:link
php artisan optimize

Step 4 — Nginx server block

The document root must be `public`, not the project folder. Pointing Nginx at the project root exposes `.env` to anyone who asks for it.

/etc/nginx/sites-available/laravel
nginx
server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/laravel/public;

    index index.php;
    charset utf-8;
    client_max_body_size 20M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
bash
sudo ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Step 5 — HTTPS

Same as any Nginx site: Certbot installs the certificate and renews it on a timer.

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

Step 6 — Queue worker and scheduler

If your app dispatches jobs, something has to process them all the time. A systemd unit restarts the worker if it crashes and starts it on boot. The scheduler needs a single cron line.

/etc/systemd/system/laravel-worker.service
ini
[Unit]
Description=Laravel queue worker
After=network.target mysql.service

[Service]
User=deploy
Group=www-data
WorkingDirectory=/var/www/laravel
ExecStart=/usr/bin/php artisan queue:work --sleep=3 --tries=3 --max-time=3600
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl enable --now laravel-worker

# Scheduler: run 'crontab -e' as deploy and add
* * * * * cd /var/www/laravel && php artisan schedule:run >> /dev/null 2>&1

Step 7 — A redeploy script

Save it as `deploy.sh` in the project and it works with our GitHub Actions guide unchanged.

bash
#!/usr/bin/env bash
set -euo pipefail
cd /var/www/laravel

php artisan down --retry=15 || true
git pull origin main
composer install --no-dev --optimize-autoloader --no-interaction
php artisan migrate --force
php artisan optimize
sudo systemctl restart laravel-worker
sudo systemctl reload php8.3-fpm
php artisan up

echo "Deployed at $(date -Iseconds)"
Extra 20% off with WEBHOST2026Claim 20% off →

Frequently asked questions

Can I host Laravel on Hostinger shared hosting?

Yes, on plans with SSH access (Premium and up). Upload the project, run Composer over SSH, and set the domain's document root to the public folder. Long-running queue workers and Redis need a VPS.

Which Hostinger VPS plan is enough for Laravel?

KVM 1 runs a typical Laravel app with MySQL and a queue worker comfortably. Move to KVM 2 when you add Redis, Horizon with several queues, or noticeably more traffic.

Why do I get a 500 error after deploying?

Almost always permissions on storage or bootstrap/cache, or a missing APP_KEY. Check storage/logs/laravel.log, and run the chown and chmod commands from Step 3 again.

Should I use Forge or a control panel instead?

If you'd rather not manage servers by hand, Laravel Forge or a panel like CloudPanel provisions everything in this guide for you, on the same Hostinger VPS.

Ready to save an extra 20% with coupon WEBHOST2026?

Get my discount link →

Disclosure: links to Hostinger on this page are referral links. If you buy through them we may earn a commission, at no extra cost to you. It doesn't change what we recommend. About us

Ready to claim your Hostinger discount?

Generate your personalised cart link with coupon WEBHOST2026 attached — it takes 20 seconds.