Laravel + Next.js on VPS (CloudPanel)
laravelnextjscloudpaneldeployment

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.

Author logo

Khaled Saifullah

14 min read

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 Database

STEP 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:8443

STEP 3 — Create Laravel Site

CloudPanel

Sites

Add Site

PHP Site

Fill in

Domain:
api.example.com

PHP:
8.3

Application:
Laravel

Click

Create Site

STEP 4 — Create Next.js Site

CloudPanel

Sites

Add Site

Node.js Site

Fill in

Domain:
example.com

Node Version:
22 LTS (recommended)

Application Port:
3000

Click

Create Site

STEP 5 — Clone Laravel Project

SSH

cd ~/htdocs/api.example.com

Clone

git clone git@github.com:username/backend.git .

STEP 6 — Install Laravel

composer install --no-dev --optimize-autoloader

Create environment

cp .env.example .env

Edit

nano .env

Generate key

php artisan key:generate

Run migration

php artisan migrate

Run seed

php artisan db:seed

Storage link

php artisan storage:link

Optimize

php artisan optimize

Permissions

chmod -R 775 storage bootstrap/cache

STEP 7 — Create Database

CloudPanel

Databases

Add Database

Create

Database Name

Database User

Password

Update Laravel `.env`

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=example_db
DB_USERNAME=example_user
DB_PASSWORD=password

STEP 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.production

Example

NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_APP_URL=https://example.com

STEP 10 — Install Dependencies

npm install

STEP 11 — Create Production Build

npm run build

If successful, you'll see:

✓ Compiled successfully
✓ Collecting page data
✓ Finalizing page optimization

STEP 12 — Configure CloudPanel Node.js

CloudPanel

Sites

example.com

Settings

Node.js

Configure

Application Root

/home/example/htdocs/example.com

Application Port

3000

Start Command

npm start

Save.

STEP 13 — Start Application

Click

Restart Application

CloudPanel starts

npm start

automatically.

**Do not manually run `npm start` from SSH in normal operation.**

STEP 14 — Enable SSL

CloudPanel

Sites

example.com

SSL/TLS

Issue Let's Encrypt

Repeat for

api.example.com

Enable

Force HTTPS

STEP 15 — Laravel Scheduler

CloudPanel

Cron Jobs

Add

* * * * * php /home/example/htdocs/api.example.com/artisan schedule:run >> /dev/null 2>&1

STEP 16 — Queue Worker (Optional)

If your application uses queues, configure a Supervisor service or another long-running worker:

php artisan queue:work

STEP 17 — Test

Laravel

https://api.example.com

Next.js

https://example.com

Everything should load successfully.

Daily Deployment

Laravel

SSH

cd ~/htdocs/api.example.com

Pull latest code

git pull

If composer files changed

composer install --no-dev --optimize-autoloader

If new migrations exist

php artisan migrate

Optimize

php artisan optimize

php artisan config:cache

php artisan route:cache

php artisan view:cache

Done.

Next.js

SSH

cd ~/htdocs/example.com

Pull

git pull

If package.json changed

npm install

Build

npm run build

CloudPanel

Sites

example.com

Restart Application

Done.

When to Run Each Command

Every Deployment

git pull

Only if package.json changed

npm install

Every frontend code change

npm run build

Restart

Use the **Restart Application** button in CloudPanel after a successful build.

Only if composer.json changed

composer install --no-dev --optimize-autoloader

Only if new migrations were added

php artisan migrate

Complete 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/cache

Next.js

cd ~/htdocs/example.com

git clone git@github.com:username/frontend.git .

npm install

npm run build

Then 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:cache

Next.js

cd ~/htdocs/example.com

git pull

npm install      # only if package.json changed

npm run build

Finally:

CloudPanel

↓

Sites

↓

example.com

↓

Restart Application

Production 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