A step-by-step guide to deploying a Laravel app on Hostinger shared hosting. Covers folder structure, PHP/Composer setup, Vite manifest fixes, database configuration, storage links, troubleshooting common errors, and ends with a one-screen deploy checklist.
Promise: what the reader will get (deployment flow, quirks, fixes, troubleshooting, checklist).
If your app is a brochure site, a portfolio, a small SaaS MVP, or an internal tool with predictable traffic and no long-running workers, shared hosting is fine (and cheap). You get an SSL, SFTP/SSH, PHP selector, MySQL, and automatic backups out of the box. The trade-off is that you don’t control the server: no root access, limited CLI tooling, and process managers (for queues/websockets) are constrained.
Go shared hosting when:
schedule:run
/cron (not 24/7 workers).Go VPS/Forge/Docker when:
My rule of thumb: if you’re fighting the platform (crons, workers, memory), you’re already paying the “dev time tax.” That’s when a VPS pays for itself.
Most shared hosts force your web root to public_html/
. A safe layout is:
/home/USERNAME/ ├── laravel/ # your Laravel project root (private) │ ├── app/ │ ├── bootstrap/ │ ├── config/ │ ├── public/ # original Laravel /public (we won’t expose this directly) │ └── ... └── public_html/ # the actual web root ├── index.php # points back to ../laravel/* ├── .htaccess └── build/ # symlink to ../laravel/public/build
You do not point the domain directly at laravel/public
. Instead, keep all app code outside the web root, then place only the web-facing files in public_html/
.
Update public_html/index.php
so it references your app correctly:
make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() )->send(); $kernel->terminate($request, $response);
Permissions to sanity-check:
chmod -R ug+rwx storage bootstrap/cache
On Hostinger, you can target a specific PHP version by calling its full path. I used PHP 8.3:
/opt/alt/php83/usr/bin/php -v
If composer
isn’t globally available, install a local copy once:
cd ~/laravel /opt/alt/php83/usr/bin/php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" /opt/alt/php83/usr/bin/php composer-setup.php --install-dir=. --filename=composer.phar rm composer-setup.php
Then install dependencies with sane flags:
cd ~/laravel /opt/alt/php83/usr/bin/php -d memory_limit=1024M composer.phar install \ --no-dev --prefer-dist --optimize-autoloader
Run Laravel optimizations (once your .env exists):
/opt/alt/php83/usr/bin/php artisan key:generate --force /opt/alt/php83/usr/bin/php artisan config:cache /opt/alt/php83/usr/bin/php artisan route:cache /opt/alt/php83/usr/bin/php artisan view:cache
Tip: If composer install
keeps failing due to memory, run it locally, zip vendor/
, upload, and unzip on the server.
Goal: keep your app private; only expose the web root.
Steps:
1. Create folders: mkdir -p /home/USERNAME/laravel # public_html already exists 2. Upload project via SFTP into /home/USERNAME/laravel/ - Skip node_modules and .git - Skip vendor/ if you’ll run composer remotely 3. Populate public_html/: - Copy only the contents of laravel/public/ once - Or create fresh index.php and .htaccess - Never put .env here (.env stays in /home/USERNAME/laravel/.env) 4. Build assets locally: npm ci npm run build Upload laravel/public/build 5. Symlink build folder: ln -s /home/USERNAME/laravel/public/build /home/USERNAME/public_html/build
Checklist: App code → /laravel, Only index.php, .htaccess, and build symlink → /public_html.