Skip to content

Deploy on Shared Hosting

Deployment on shared hosting is a manual Laravel deployment.

This guide is written for cPanel-like environments, but the same principles apply to other shared hosts.

1) Confirm hosting requirements first

Your hosting plan should provide:

  • PHP 8.4+ with required extensions
  • MySQL/MariaDB database
  • Composer support (SSH terminal preferred)
  • Ability to run Artisan commands
  • Ability to configure cron jobs
  • Access to set document root (ideal)

If your host does not allow running Artisan commands, deployment becomes limited and is not recommended for this project.

2) Upload project files

Upload the full project to a non-public path, for example:

text
/home/your_user/saasforgekit

Do not place the whole Laravel project directly in public_html.

3) Install dependencies and build assets

With SSH (recommended), run:

bash
cd /home/your_user/saasforgekit
composer install --no-dev --optimize-autoloader
npm install
npm run build

If SSH is unavailable, build locally and upload the resulting vendor and public/build folders.
SSH access is still strongly recommended for running migrations and maintenance commands.

4) Configure .env

Create .env and update production values:

bash
cp .env.example .env

Set at minimum:

  • APP_ENV=production
  • APP_DEBUG=false
  • APP_URL=https://your-domain.com
  • DB_* values for your shared-hosting database
  • MAIL_* for real email delivery
  • STRIPE_* if billing is enabled

Set tenancy mode before migrations:

env
TENANCY_DB_MODE=single_db

For shared hosting, single_db is usually the safest choice.

About multi_db on shared hosting

multi_db requires a DB user that can create/manage tenant databases. Most shared-hosting plans do not grant these privileges to customer database users.

If your host cannot provide database create/drop privileges for your app user, you should use:

env
TENANCY_DB_MODE=single_db

5) Point your public web root

Preferred setup

Set your domain document root to:

text
/home/your_user/saasforgekit/public

This is the cleanest and safest Laravel setup.

If your host forces public_html

  1. Copy contents of /home/your_user/saasforgekit/public into public_html.
  2. Edit public_html/index.php so paths point to your app directory.

Example:

php
require __DIR__.'/../saasforgekit/vendor/autoload.php';
$app = require_once __DIR__.'/../saasforgekit/bootstrap/app.php';

Adjust the relative path to match your real directories.

Asset not found fix (cPanel/public_html)

If CSS/JS assets return 404 even after correct public_html setup, force Laravel's public path in bootstrap/app.php.

Update bootstrap/app.php to use an $app variable and add a public_html override:

php
$app = Application::configure(basePath: dirname(__DIR__))
    // ... existing configuration ...
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();

if (is_dir($app->basePath('../public_html'))) {
    $app->usePublicPath($app->basePath('../public_html'));
}

return $app;

If your host uses another public folder name (for example httpdocs), replace public_html accordingly.

6) Run Laravel setup commands

From project root:

bash
php artisan key:generate
php artisan storage:link
php artisan migrate --force

If needed on first deploy:

bash
php artisan db:seed --class=AdminRoleSeeder --force

7) Fix writable permissions

Ensure these are writable by PHP:

  • storage/
  • bootstrap/cache/

Many cPanel hosts expose a File Manager permissions UI if shell chmod is restricted.

8) Configure queue worker via cron (common shared-hosting approach)

Shared hosting often cannot run long-lived daemons. Use cron to process jobs repeatedly:

bash
* * * * * /usr/local/bin/php /home/your_user/saasforgekit/artisan queue:work --stop-when-empty >> /dev/null 2>&1

If your host supports Supervisor or persistent workers, use that instead (better reliability).

9) Verify deployment

  • Site opens at your production domain
  • Login works
  • Jobs are processed (emails/async operations)
  • Billing webhooks can reach your app (if Stripe enabled)

Default seeded admin credentials:

Change these immediately after first login.