0% read
Skip to main content
Backend

Complete Guide - Deploying Laravel to Bluehost Shared Hosting

Step-by-step instructions for deploying a Laravel application to Bluehost shared hosting including SSH setup composer configuration and troubleshooting common issues.

Prerequisites

Basic Laravel knowledge Bluehost shared hosting account Git installed locally and SSH client

Introduction

Deploying Laravel to shared hosting like Bluehost can be tricky. Unlike VPS hosting where you have full control, shared hosting has limitations. This guide will walk you through the entire process, including solutions to common problems.

Prerequisites

Before starting, ensure you have:

  • A Bluehost shared hosting account
  • SSH access enabled (contact Bluehost support if needed)
  • Laravel application in a Git repository
  • Local development environment working
  • Basic command line knowledge

Time Estimate: 45-60 minutes for first deployment, 5-10 minutes for updates

Step 1: Enable SSH Access

1.1 Generate SSH Key Pair

On your local machine:

# Generate new SSH key
ssh-keygen -t rsa -b 4096 -C "your-email@example.com"

Save to default location: ~/.ssh/id_rsa

Set a passphrase when prompted (optional but recommended)

1.2 Add Public Key to Bluehost

# Copy your public key
cat ~/.ssh/id_rsa.pub
# Copy the entire output

In Bluehost cPanel:

  1. Navigate to "SSH Access" or "SSH Shell"
  2. Click "Manage SSH Keys"
  3. Import your public key
  4. Authorize the key

1.3 Test SSH Connection

# Test connection (replace with your actual credentials)
ssh username@yourdomain.com

Or using IP address

ssh username@server-ip-address

If successful, you'll see the server's command prompt.

Step 2: Prepare Your Laravel Application

2.1 Optimize for Production

In your local project:

# Update environment file for production
cp .env.example .env.production

Set production values

APP_ENV=production

APP_DEBUG=false

APP_URL=https://yourdomain.com

2.2 Build Frontend Assets

# Install dependencies
npm install

Build for production

npm run build

Verify build directory exists

ls -la public/build

2.3 Commit Changes

# Add built assets (if not gitignored)
git add public/build

Commit

git commit -m "Build production assets"

Push to repository

git push origin main

Step 3: Set Up Server Directory Structure

3.1 Connect via SSH

ssh username@yourdomain.com

3.2 Create Directory Structure

# Navigate to home directory
cd ~

Create application directory (outside public_html)

mkdir laravel-app cd laravel-app

Clone your repository

git clone https://github.com/yourusername/your-repo.git .

Important: The Laravel application should be outside public_html. Only the public folder contents will be in public_html.

3.3 Verify Directory Structure

# You should now have:
# ~/laravel-app/          (your Laravel app)
# ~/public_html/          (web root, currently separate)

ls -la ~/laravel-app

Should show: app/, bootstrap/, config/, public/, etc.

Step 4: Install Composer Dependencies

This is where Bluehost gets tricky. Shared hosting often has outdated PHP versions or limited composer access.

4.1 Check PHP Version

php -v
# Should be PHP 8.1 or higher for Laravel 10

If PHP version is too old:

# Bluehost usually provides multiple PHP versions
which php81
which php82
which php83

Create alias in .bashrc

echo 'alias php="/usr/local/bin/php83"' >> ~/.bashrc source ~/.bashrc

Verify

php -v

4.2 Install Composer (if not available)

# Download composer installer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"

Install composer

php composer-setup.php --install-dir=$HOME/bin --filename=composer

Remove installer

php -r "unlink('composer-setup.php');"

Add to PATH if needed

echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc source ~/.bashrc

Verify

composer --version

4.3 Install Laravel Dependencies

cd ~/laravel-app

Install dependencies (this may take 5-10 minutes)

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

If you encounter memory errors:

php -d memory_limit=512M /home/username/bin/composer install --optimize-autoloader --no-dev

Common Error: "Allowed memory size exhausted"

Solution:

# Increase PHP memory limit
php -d memory_limit=512M /path/to/composer install

Step 5: Configure Environment

5.1 Create Production .env File

cd ~/laravel-app

Copy example environment

cp .env.example .env

Edit with nano or vim

nano .env

5.2 Set Environment Variables

Update these critical values:

APP_NAME="YourAppName"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com

Generate a new app key (we'll do this next)

APP_KEY=

Database credentials from cPanel

DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=your_database_name DB_USERNAME=your_database_user DB_PASSWORD=your_database_password

Mail settings (optional)

MAIL_MAILER=smtp MAIL_HOST=mail.yourdomain.com MAIL_PORT=587 MAIL_USERNAME=your-email@yourdomain.com MAIL_PASSWORD=your-email-password MAIL_ENCRYPTION=tls

Cache driver

CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_CONNECTION=sync

5.3 Generate Application Key

# Generate unique application key
php artisan key:generate

Verify it was added to .env

cat .env | grep APP_KEY

5.4 Set Permissions

# Make storage and bootstrap writable
chmod -R 775 storage bootstrap/cache

If you get permission errors later, try:

chmod -R 777 storage bootstrap/cache

(Not ideal for security, but sometimes necessary on shared hosting)

Step 6: Configure Database

6.1 Create Database in cPanel

  1. Log into Bluehost cPanel
  2. Navigate to "MySQL Databases"
  3. Create a new database (note the full name: username_dbname)
  4. Create a database user
  5. Add user to database with ALL PRIVILEGES
  6. Note the credentials (update .env if needed)

6.2 Run Migrations

cd ~/laravel-app

Run database migrations

php artisan migrate --force

The --force flag is required in production

Common Error: "Access denied for user"

Solution: Double-check database credentials in .env. The database name is usually username_dbname.

6.3 Seed Data (Optional)

# If you have seeders
php artisan db:seed --force

Step 7: Link Public Directory

This is the crucial step that makes Laravel work on shared hosting.

7.1 Backup Existing public_html

# Backup existing files
cd ~
mv public_html public_html.backup

7.2 Create Symbolic Link

# Create symlink from public_html to Laravel's public folder
ln -s ~/laravel-app/public ~/public_html

Verify the link

ls -la ~ | grep public_html

Should show: public_html -> /home/username/laravel-app/public

7.3 Alternative: Copy Files (if symlink doesn't work)

Some hosts don't allow symlinks:

# Remove the symlink
rm ~/public_html

Create public_html directory

mkdir ~/public_html

Copy public folder contents

cp -R ~/laravel-app/public/* ~/public_html/

Update index.php paths (important!)

nano ~/public_html/index.php

Edit index.php to update paths:

<?php

// Find these lines and update the paths:

require DIR.'/../laravel-app/vendor/autoload.php';

$app = require_once DIR.'/../laravel-app/bootstrap/app.php';

Step 8: Configure .htaccess

8.1 Update public/.htaccess

nano ~/laravel-app/public/.htaccess

Ensure it contains:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>
RewriteEngine On

# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

</IfModule>

8.2 Add Root .htaccess (if needed)

Some configurations require this:

nano ~/public_html/.htaccess

Add:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

Step 9: Optimize for Production

9.1 Cache Configuration

cd ~/laravel-app

Cache configuration

php artisan config:cache

Cache routes

php artisan route:cache

Cache views

php artisan view:cache

9.2 Verify Optimization

# Check that cache files were created
ls -la bootstrap/cache/
# Should see: config.php, routes-v7.php, etc.

Step 10: Test Your Deployment

10.1 Visit Your Site

Open your browser and navigate to https://yourdomain.com

You should see your Laravel application!

10.2 Test Key Functionality

  • Homepage loads
  • Navigation works
  • Database queries work
  • Forms submit correctly
  • Assets (CSS/JS) load properly

10.3 Check Error Logs

If something doesn't work:

# Check Laravel logs
tail -50 ~/laravel-app/storage/logs/laravel.log

Check PHP error logs (location varies)

tail -50 ~/public_html/error_log

or

tail -50 ~/.logs/error_log

Troubleshooting Common Issues

Issue 1: "500 Internal Server Error"

Causes:

  • Incorrect file permissions
  • Missing .env file
  • PHP version mismatch
  • .htaccess errors

Solutions:

# Check permissions
chmod -R 775 storage bootstrap/cache

Verify .env exists

ls -la ~/laravel-app/.env

Check PHP version

php -v

Check error logs

tail ~/laravel-app/storage/logs/laravel.log

Issue 2: "419 Page Expired" on Forms

Cause: Session configuration issues

Solution:

# In .env, ensure:
SESSION_DRIVER=file
SESSION_LIFETIME=120

Clear and recache config

php artisan config:clear php artisan config:cache

Issue 3: Assets (CSS/JS) Not Loading

Cause: Incorrect asset paths

Solution:

# Ensure APP_URL is correct in .env
APP_URL=https://yourdomain.com

Rebuild assets

npm run build

Re-upload public/build folder

Issue 4: Database Connection Errors

Cause: Wrong database credentials

Solution:

# Verify database credentials
cat .env | grep DB_

Test connection manually

php artisan tinker >>> \DB::connection()->getPdo();

Should connect without errors

Issue 5: Composer Memory Limit

Cause: Shared hosting memory restrictions

Solution:

# Use memory limit flag
php -d memory_limit=512M /path/to/composer install --optimize-autoloader --no-dev

Or install locally and upload vendor folder (not recommended but works)

Step 11: Set Up Deployment Workflow

11.1 Create Deployment Script

Create a deployment script for future updates:

nano ~/deploy.sh

Add:

#!/bin/bash

cd ~/laravel-app

Pull latest code

git pull origin main

Install/update dependencies

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

Run migrations

php artisan migrate --force

Clear caches

php artisan config:clear php artisan route:clear php artisan view:clear

Recache

php artisan config:cache php artisan route:cache php artisan view:cache

Fix permissions

chmod -R 775 storage bootstrap/cache

echo "Deployment complete!"

Make executable:

chmod +x ~/deploy.sh

11.2 Deploy Updates

For future deployments:

# SSH into server
ssh username@yourdomain.com

Run deployment script

~/deploy.sh

Step 12: Security Hardening

12.1 Protect Sensitive Files

Create .htaccess in Laravel root:

nano ~/laravel-app/.htaccess

Add:

# Deny access to all files in this directory
Deny from all

12.2 Disable Directory Listing

In public/.htaccess, ensure:

Options -Indexes

12.3 Enable HTTPS

In Bluehost cPanel:

  1. Navigate to "SSL/TLS"
  2. Install free Let's Encrypt certificate
  3. Enable "Force HTTPS Redirect"

Update .env:

APP_URL=https://yourdomain.com

Maintenance Tasks

Daily/Weekly

  • Monitor error logs: tail ~/laravel-app/storage/logs/laravel.log
  • Check disk usage: du -sh ~/*
  • Monitor uptime

Monthly

  • Update dependencies: composer update
  • Review and rotate log files
  • Check for Laravel security updates

As Needed

  • Clear old sessions: php artisan session:gc
  • Optimize database: php artisan optimize
  • Backup database

Backup Strategy

Manual Backup

# Backup database
mysqldump -u username -p database_name > backup_$(date +%Y%m%d).sql

Backup files

tar -czf ~/backups/app_$(date +%Y%m%d).tar.gz ~/laravel-app

Download backups via SFTP

Automated Backup

Create cron job:

crontab -e

Add:

# Daily database backup at 2 AM
0 2 * * * mysqldump -u username -p'password' database_name > ~/backups/db_$(date +\%Y\%m\%d).sql

Weekly file backup

0 3 * * 0 tar -czf ~/backups/files_$(date +%Y%m%d).tar.gz ~/laravel-app

Performance Optimization

Enable OPcache

Check if enabled:

php -i | grep opcache

If not enabled, contact Bluehost support to enable it.

Use CDN for Assets

For better performance:

  1. Sign up for Cloudflare (free)
  2. Point your domain's DNS to Cloudflare
  3. Enable caching and minification
  4. Assets will be served from edge servers

Database Query Optimization

# Enable query logging temporarily
# In .env:
DB_LOG_QUERIES=true

Check slow queries in logs

tail -100 ~/laravel-app/storage/logs/laravel.log | grep "Query took"

Add indexes as needed

Conclusion

Deploying Laravel to Bluehost shared hosting requires patience and attention to detail, but it's definitely achievable. The key challenges are:

  1. Limited server access
  2. PHP/Composer configuration
  3. Proper directory structure
  4. File permissions

Once you have the initial setup working, updates are straightforward with a deployment script.

Additional Resources

Get Help

If you encounter issues not covered here:

  1. Check error logs first
  2. Search Laravel Forums
  3. Ask on Stack Overflow
  4. Contact Bluehost support for hosting-specific issues

Have you successfully deployed Laravel to Bluehost? Share your experience and any additional tips in the comments!