Skip to content
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Login Client Area
ALL SYSTEMS OPERATIONAL
Troubleshooting

Laravel 500 Error After Deploy: Fix Permissions & .env Issues

Getwebup 5 min read

You've just pushed your Laravel app to a live server - cPanel, a VPS, doesn't matter - and instead of your app, you get a blank page or a plain "500 Internal Server Error". No stack trace, no hint. Here's how to actually find out what broke and fix it, instead of guessing.

Symptom

You deploy (git pull, zip upload, or CI script), open the domain, and get one of these:

  • A blank white page with nothing in it
  • "500 Internal Server Error" with no detail
  • "The stream or file could not be opened" mentioning storage/logs/laravel.log
  • "No application encryption key has been specified"
  • The site loads but CSS/JS is missing and links 404

Laravel hides errors in production by default (APP_DEBUG=false), which is correct for security - but it also means the generic 500 page tells you nothing. You have to go looking.

Step 1: Find the real error

Don't guess - read the log. SSH in (or use cPanel Terminal) and tail Laravel's own log first:

tail -n 50 storage/logs/laravel.log

If that file doesn't exist or is empty, the problem is happening before Laravel even boots - check the web server's error log instead:

# cPanel / shared hosting
tail -n 50 ~/logs/yourdomain.com/error_log

# VPS with Nginx + PHP-FPM
tail -n 50 /var/log/nginx/error.log
tail -n 50 /var/log/php8.2-fpm.log

If you need the actual error on screen instead of digging through logs, temporarily set APP_DEBUG=true in .env, reload, and read the trace. Turn it back to false immediately after - a debug page in production leaks your config, database credentials, and file paths to anyone who hits a broken route.

Common causes and fixes

1. Storage and cache folders aren't writable

By far the most common cause. Laravel writes logs, compiled views, and session/cache files into storage/ and bootstrap/cache/. If the web server user (usually www-data, nobody, or your cPanel account user) can't write there, you get exactly this kind of silent 500.

chmod -R 775 storage bootstrap/cache
chown -R $USER:www-data storage bootstrap/cache

# on a fresh clone, make sure these exist too
mkdir -p storage/framework/{sessions,views,cache}
mkdir -p storage/logs

On a VPS running PHP-FPM under a dedicated pool user, replace www-data with whatever user your pool actually runs as - check ps aux | grep php-fpm if you're not sure.

2. .env is missing or has stale values

.env should never be committed to git (it's in .gitignore by default), which means every fresh deploy needs one created manually or by your deploy script. If it's missing entirely, Laravel can't read the database connection, mail settings, or app key, and it fails before rendering anything.

cp .env.example .env
php artisan key:generate

Double-check the values that actually change between environments - APP_URL, DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD. A leftover DB_HOST=127.0.0.1 pointing at your local machine is a classic copy-paste mistake.

3. No application key set

If the log says No application encryption key has been specified, the fix is one command:

php artisan key:generate

This writes a fresh APP_KEY into .env. If you already had one and it went missing, check that your deploy process isn't overwriting .env with a template on every push.

4. vendor/ folder missing or out of date

If you deployed by zipping your project folder and vendor/ wasn't included (or you deployed via git and never ran Composer on the server), Laravel's autoloader can't find any of its classes - you'll see Class 'X' not found errors.

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

Use --no-dev in production - it skips testing/debug packages you don't need live, and keeps the deployed footprint smaller.

5. Document root points at the wrong folder

Laravel's entire app lives outside the web root except for public/. If your domain's document root is set to the project's top-level folder instead of project/public, visitors either see a directory listing of your raw source code (a serious security problem) or a 500/404 because there's no working index.php at that level.

  • cPanel: in WHM/cPanel, set the domain's document root to /home/user/laravel-app/public, or symlink public_html to point at the app's public folder.
  • Nginx on a VPS: set root in your server block to the app's public directory, not the project root:
server {
    listen 80;
    server_name example.com;
    root /var/www/laravel-app/public;

    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

6. Stale cached config after changing .env

If you ran php artisan config:cache at some point (common in deploy scripts), Laravel stops reading .env directly and uses the cached file instead. Change a value in .env after that and nothing happens until you clear it:

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

# then re-cache for production performance
php artisan config:cache
php artisan route:cache

Quick reference

Error message / symptomLikely causeFix
Blank 500, nothing in laravel.logWrong document root or missing vendor/Point root at public/, run composer install
"stream or file could not be opened": storage/logsstorage/ not writablechmod -R 775 storage bootstrap/cache
"No application encryption key has been specified"Missing APP_KEYphp artisan key:generate
SQLSTATE connection refusedWrong DB_HOST/credentials in .envFix .env, then config:clear
.env edits have no effectStale config cachephp artisan config:clear
CSS/JS missing, assets 404Wrong APP_URL or unbuilt assetsSet correct APP_URL, run npm run build

Prevention

  • Keep a deploy checklist (or script) that always runs: composer install --no-dev, php artisan migrate --force, cache clear + re-cache, and a permissions fix on storage/ and bootstrap/cache.
  • Never commit .env - keep a .env.production template outside git that you copy in during deploy instead.
  • Set APP_DEBUG=false on every production deploy, and rely on storage/logs/laravel.log for debugging, not the browser.
  • If you deploy often, script the cache-clear-then-recache sequence so a forgotten config:cache never masks a real .env change again.

Frequently asked questions

Why does my Laravel site show a blank page instead of an error?

With APP_DEBUG=false (the correct production setting), PHP fatal errors render as a blank page or generic 500 instead of a stack trace. Check storage/logs/laravel.log or your web server's error log to see what actually happened.

Is it safe to leave APP_DEBUG=true on my live site?

No. Debug mode exposes your full stack trace, environment variables, database credentials, and file paths to anyone who triggers an error. Only enable it briefly while diagnosing, then set it back to false.

Do I need a VPS to run Laravel, or does cPanel shared hosting work?

Laravel runs fine on cPanel shared hosting as long as PHP is 8.1+ and you can set the domain's document root to the app's public folder. A VPS gives you more control (custom PHP-FPM pools, queue workers, scheduled tasks via real cron) which larger Laravel apps eventually need.

What permissions should storage/ and bootstrap/cache/ actually have?

775 is the safe default - owner and group get write access, others get read/execute. Avoid 777; it's rarely necessary and it's an easy target if the server is ever compromised.

My composer install fails on the server - why does it work locally but not here?

Usually a PHP version mismatch (check composer.json's require.php against the server's active PHP version) or a memory limit hit during dependency resolution. Run composer install -vvv to see the real error, and bump memory_limit temporarily if it's an out-of-memory failure.

#laravel #500-error #php #composer #file-permissions #cpanel

Keep reading

Chat with Support