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:
- Navigate to "SSH Access" or "SSH Shell"
- Click "Manage SSH Keys"
- Import your public key
- 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
- Log into Bluehost cPanel
- Navigate to "MySQL Databases"
- Create a new database (note the full name:
username_dbname) - Create a database user
- Add user to database with ALL PRIVILEGES
- 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:
- Navigate to "SSL/TLS"
- Install free Let's Encrypt certificate
- 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:
- Sign up for Cloudflare (free)
- Point your domain's DNS to Cloudflare
- Enable caching and minification
- 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:
- Limited server access
- PHP/Composer configuration
- Proper directory structure
- 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:
- Check error logs first
- Search Laravel Forums
- Ask on Stack Overflow
- Contact Bluehost support for hosting-specific issues
Have you successfully deployed Laravel to Bluehost? Share your experience and any additional tips in the comments!