Shared hosting is the most affordable way to publish a Laravel app, but many beginners stumble because its structure differs from localhost. The most common problems: the entire project becomes publicly visible, or a blank white screen appears with no message. This guide walks you from upload to a securely running app on cPanel, focusing on two key points: pointing the document root at the public folder and setting up a production .env correctly.
1. Prepare the Project Before Upload
Before copying anything, make sure your local project is tidy. Run the front-end asset build if you have one:
npm run build
Do not include the vendor and node_modules folders in the upload — both are large and can be rebuilt on the server. Compress the project into a single ZIP file so the upload is faster and no files are missed.
2. Upload and Extract via File Manager
Log into cPanel and open File Manager. Upload the ZIP to a folder outside public_html — for example, create a new folder named laravel in the home directory and extract there. Keeping the application code outside public_html is important for security: only the public folder should be publicly accessible.
3. Point the Document Root at the public Folder
This is the most crucial step. Laravel is designed so that only the public folder is the web root; everything else (code, config, the .env file) must stay hidden.
If you use the primary domain, the easiest approach is to copy the contents of public into public_html, then edit public_html/index.php so it points to the application location:
require __DIR__.'/../laravel/vendor/autoload.php';
$app = require_once __DIR__.'/../laravel/bootstrap/app.php';
If your host supports changing the document root per domain (via the Domains menu), it is cleaner to point it directly at /home/user/laravel/public without moving any files.
4. Install Dependencies with Composer
Open the Terminal menu in cPanel (or SSH). Enter the application folder and run Composer without development dependencies for a leaner install:
cd ~/laravel
composer install --optimize-autoloader --no-dev
The --no-dev flag skips packages only needed during development, and --optimize-autoloader speeds up class loading in production. If your host offers no terminal, some providers have a "Run Composer" button in the panel, or you can upload the vendor folder manually.
5. Set Up the Production .env File
Copy .env.example to .env, then fill it with production settings. The first three lines determine the app's security:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=database_name
DB_USERNAME=database_user
DB_PASSWORD=secret_password
Mandatory: APP_DEBUG=false. If left as true, any error will display code details, server paths, and even database credentials to visitors. Fill the database credentials with the ones you created in cPanel's MySQL Databases menu.
6. Generate the Application Key
Laravel needs a unique encryption key to secure sessions and encrypted data. Generate it with:
php artisan key:generate
This command fills APP_KEY in .env. Without a valid key, you will get the error "No application encryption key has been specified".
7. Run the Database Migrations
Once the database and credentials are ready, create all the tables. In production Laravel asks for confirmation; skip it with --force:
php artisan migrate --force
If you have initial data (seeders), run php artisan db:seed --force.
8. Set Permissions for storage and bootstrap/cache
Laravel needs to write to these two folders for logs, cache, and uploaded files. Grant write permission:
chmod -R 775 storage bootstrap/cache
If the app displays images or uploaded files, create a symbolic link from storage to public:
php artisan storage:link
On some shared hosts storage:link fails due to symlink restrictions; if so, you can create the link manually via File Manager or copy the folder.
9. Cache Config and Routes for Speed
The final step speeds up the app by merging config and routes into a single cache file:
php artisan config:cache
php artisan route:cache
php artisan view:cache
Remember: whenever you change .env later, re-run php artisan config:cache, or clear it with php artisan config:clear, so the changes take effect.
Checklist When Problems Arise
- White screen / 500 error: check
storage/logs/laravel.log. Temporarily setAPP_DEBUG=true, fix it, then return tofalse. - All files visible in the URL: the document root does not point to
public. - "Permission denied":
storageorbootstrap/cacheis not set to 775. - .env changes have no effect: an old config cache is still active — run
config:clear.
With these nine steps your Laravel app is live and secure on shared hosting: code hidden, debug off, database migrated, and config cached for speed. Keep the checklist above to speed up troubleshooting on your next deploy.