Laravel + Next.js on VPS (CloudPanel)
A complete step-by-step CloudPanel workflow for deploying a Laravel backend and Next.js frontend on a VPS with MySQL, SSL, scheduler, queues, and update commands.
Khaled Saifullah
Complete Step-by-Step Deployment Guide
Laravel Backend + Next.js Frontend on Hostinger VPS (CloudPanel)
This guide assumes:
* Frontend: `example.com` (Next.js)
* Backend API: `api.example.com` (Laravel)
* Server: Hostinger KVM VPS
* Control Panel: CloudPanel
* Database: MySQL/MariaDB
Server Architecture
Internet
│
▼
CloudPanel (Nginx)
│
├── example.com
│ │
│ ▼
│ Next.js (Node.js)
│
└── api.example.com
│
▼
Laravel
│
▼
MySQL DatabaseSTEP 1 — Point Your Domain
Create DNS records.
| Type | Name | Value |
| ---- | ---- | -------------- |
| A | @ | YOUR_SERVER_IP |
| A | www | YOUR_SERVER_IP |
| A | api | YOUR_SERVER_IP |Wait until DNS propagates.
STEP 2 — Login to CloudPanel
https://YOUR_SERVER_IP:8443STEP 3 — Create Laravel Site
CloudPanel
Sites↓
Add Site↓
PHP SiteFill in
Domain:
api.example.com
PHP:
8.3
Application:
LaravelClick
Create SiteSTEP 4 — Create Next.js Site
CloudPanel
Sites
Add Site
Node.js SiteFill in
Domain:
example.com
Node Version:
22 LTS (recommended)
Application Port:
3000Click
Create SiteSTEP 5 — Clone Laravel Project
SSH
cd ~/htdocs/api.example.comClone
git clone git@github.com:username/backend.git .STEP 6 — Install Laravel
composer install --no-dev --optimize-autoloaderCreate environment
cp .env.example .envEdit
nano .envGenerate key
php artisan key:generateRun migration
php artisan migrateRun seed
php artisan db:seedStorage link
php artisan storage:linkOptimize
php artisan optimizePermissions
chmod -R 775 storage bootstrap/cacheSTEP 7 — Create Database
CloudPanel
Databases
Add DatabaseCreate
Database Name
Database User
PasswordUpdate Laravel `.env`
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=example_db
DB_USERNAME=example_user
DB_PASSWORD=passwordSTEP 8 — Clone Next.js Project
cd ~/htdocs/example.com
git clone git@github.com:username/frontend.git .STEP 9 — Configure Next.js Environment
Create
.env.productionExample
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_URL=https://example.comSTEP 10 — Install Dependencies
npm installSTEP 11 — Create Production Build
npm run buildIf successful, you'll see:
✓ Compiled successfully
✓ Collecting page data
✓ Finalizing page optimizationSTEP 12 — Configure CloudPanel Node.js
CloudPanel
Sites
example.com
Settings
Node.jsConfigure
Application Root
/home/example/htdocs/example.com
Application Port
3000
Start Command
npm startSave.
STEP 13 — Start Application
Click
Restart ApplicationCloudPanel starts
npm startautomatically.
**Do not manually run `npm start` from SSH in normal operation.**
STEP 14 — Enable SSL
CloudPanel
Sites
example.com
SSL/TLS
Issue Let's EncryptRepeat for
api.example.comEnable
Force HTTPSSTEP 15 — Laravel Scheduler
CloudPanel
Cron JobsAdd
* * * * * php /home/example/htdocs/api.example.com/artisan schedule:run >> /dev/null 2>&1STEP 16 — Queue Worker (Optional)
If your application uses queues, configure a Supervisor service or another long-running worker:
php artisan queue:workSTEP 17 — Test
Laravel
https://api.example.comNext.js
https://example.comEverything should load successfully.
Daily Deployment
Laravel
SSH
cd ~/htdocs/api.example.comPull latest code
git pullIf composer files changed
composer install --no-dev --optimize-autoloaderIf new migrations exist
php artisan migrateOptimize
php artisan optimize
php artisan config:cache
php artisan route:cache
php artisan view:cacheDone.
Next.js
SSH
cd ~/htdocs/example.comPull
git pullIf package.json changed
npm installBuild
npm run buildCloudPanel
Sites
example.com
Restart ApplicationDone.
When to Run Each Command
Every Deployment
git pullOnly if package.json changed
npm installEvery frontend code change
npm run buildRestart
Use the **Restart Application** button in CloudPanel after a successful build.
Only if composer.json changed
composer install --no-dev --optimize-autoloaderOnly if new migrations were added
php artisan migrateComplete Initial Deployment Commands
Laravel
cd ~/htdocs/api.example.com
git clone git@github.com:username/backend.git .
composer install --no-dev --optimize-autoloader
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan db:seed
php artisan storage:link
php artisan optimize
chmod -R 775 storage bootstrap/cacheNext.js
cd ~/htdocs/example.com
git clone git@github.com:username/frontend.git .
npm install
npm run buildThen restart the Node.js application from CloudPanel.
Complete Update Commands
Laravel
cd ~/htdocs/api.example.com
git pull
composer install --no-dev --optimize-autoloader # only if needed
php artisan migrate # only if needed
php artisan optimize
php artisan config:cache
php artisan route:cache
php artisan view:cacheNext.js
cd ~/htdocs/example.com
git pull
npm install # only if package.json changed
npm run buildFinally:
CloudPanel
↓
Sites
↓
example.com
↓
Restart ApplicationProduction Checklist
Laravel
✅ Database configured
✅ `.env` configured
✅ Dependencies installed
✅ Storage linked
✅ Migrations completed
✅ Optimized
✅ SSL enabled
Next.js
✅ Dependencies installed
✅ Production build completed
✅ CloudPanel Node.js configured
✅ Application restarted after each deployment
✅ SSL enabled
This workflow follows a clean production setup where **CloudPanel manages the Node.js process**, while you rebuild the Next.js application after code changes and restart it through CloudPanel. You do not need to use PM2 when CloudPanel is already managing the Node.js application.
Last updated on 07/08/2026
