Skip to content
Hosting Operations9 min read

Laravel Shared Hosting Production Checklist [2026]

Fix slow Laravel apps on shared hosting with this production checklist. Optimize routes, sessions, and configs to cut load times by 60%.

Written by Abdul AbrorTechnical Hosting Support Engineer
black flat screen computer monitor
On this page

TL;DR — Key takeaways

  • Route and config caching cuts Laravel bootstrap time by 50-70% on shared hosting environments
  • Session driver choice impacts response times by 200-400ms; database or file sessions outperform cookie storage under load
  • The 419 page expired error stems from missing CSRF tokens or session timeouts, fixed by verifying APP_KEY and session configuration
  • Composer autoload optimization and removing dev dependencies reduces memory footprint by 30-40MB
  • Monitoring queue workers and scheduled tasks prevents silent failures that break background processing

Shared hosting puts Laravel apps under tight resource constraints. CPU throttling, limited memory, and no root access force you to optimize before deployment, not after.

I've handled dozens of support tickets where Laravel sites worked fine locally but crawled or threw 419 errors once moved to shared hosting. The pattern is always the same: missing caches, wrong permissions, or session misconfigurations that break under production traffic. This checklist walks through the performance bottlenecks and fixes that actually matter on shared environments.

Pre-Deployment: Route and Config Caching

Laravel compiles routes and configs on every request when caches are missing. On shared hosting where CPU cycles are rationed across accounts, this bootstrap overhead adds 100-300 milliseconds per page load.

Before uploading files, run these commands locally or via SSH if available:

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

Config caching writes all config files into a single bootstrap/cache/config.php. Route caching serializes the route table into bootstrap/cache/routes-v7.php. View caching precompiles Blade templates.

Test the cached app locally first. If you change .env or add routes after caching, the cache won't update automatically—you must clear and rebuild it. On shared hosting without SSH, set up a cron job or protected endpoint to trigger cache clearing when needed.

    Composer Autoload Optimization

    The default Composer autoloader uses PSR-4 directory scanning, which adds file system calls on every class load. Shared hosting I/O is slower than VPS storage, so this compounds quickly.

    Run composer install with optimization flags:

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

    The --optimize-autoloader flag generates a classmap for your application code, replacing directory scans with a direct lookup array. The --no-dev flag strips development dependencies (PHPUnit, Faker, debug tools), cutting vendor size by 30-50%.

    Measure the impact: a typical Laravel 10 app drops from 45MB to 28MB after removing dev packages. Memory usage at runtime falls by 30-40MB. On shared hosting where accounts often cap at 128-256MB PHP memory, that margin matters.

      Session Driver and the 419 Page Expired Problem

      The 419 error code in Laravel means the CSRF token is invalid or expired. This happens when session storage fails or the session lifetime is too short for your user behavior.

      Check your .env file for these lines:

      SESSION_DRIVER=file SESSION_LIFETIME=120

      The default file driver writes session data to storage/framework/sessions. If that directory hits your disk quota or lacks write permissions, sessions silently fail and every form submission returns 419.

      Switch to the database driver for better reliability under quota limits. Run php artisan session:table and php artisan migrate to create the sessions table, then set SESSION_DRIVER=database in .env.

      If users idle for more than two hours before submitting forms, increase SESSION_LIFETIME to 240 or 360 minutes. Just know that longer sessions mean more database rows or files accumulating between garbage collection runs.

        So what if the token validation still fails?

        After fixing the session driver, 419 errors usually trace back to APP_KEY issues or middleware misconfigurations.

        Verify that APP_KEY is set in .env and matches exactly between your local environment and the server. If APP_KEY is missing, Laravel generates a new one on boot—but that breaks sessions created under the old key. Run php artisan key:generate locally, copy the resulting key to your production .env, and never change it again without clearing all sessions.

        Check that VerifyCsrfToken middleware is active in app/Http/Kernel.php. If you excluded certain routes from CSRF protection during development, make sure those exclusions are intentional for production. A common mistake is excluding /api/* but forgetting that web forms still need tokens.

        Test by submitting a form, waiting three hours, then submitting again. If 419 appears, SESSION_LIFETIME is the culprit. If it never appears, your config is solid.

          File Permissions and Storage Paths

          Incorrect permissions block Laravel from writing logs, cache files, and session data. Shared hosting sets default ownership to your cPanel user, but file modes vary.

          Set directories to 755 and files to 644 across the app. The exceptions are storage and bootstrap/cache, which need 775 so the web server can write:

          chmod -R 755 /home/username/laravel chmod -R 775 /home/username/laravel/storage chmod -R 775 /home/username/laravel/bootstrap/cache

          If your host runs PHP via CGI or suPHP, the web server process runs as your user, so 755 on storage works. If it runs via mod_php or FPM with a separate user (like nobody or www-data), you need 775 or 777. Check storage/logs after deployment—if no log files appear, permissions are wrong.

          Never set 777 on the entire app. That exposes config files to other accounts on the same server. Limit 777 to storage/framework and storage/logs only if 775 fails, and only after confirming your host's PHP execution model.

            Document Root and Public Directory Setup

            Laravel's entry point is public/index.php, not the project root. Pointing your domain to /home/username/laravel instead of /home/username/laravel/public exposes .env, config files, and the vendor directory to the web.

            In cPanel, open Domains or the old 'Addon Domains' interface. Find the document root field for your domain and set it to /home/username/laravel/public. Save and wait 2-3 minutes for the change to propagate.

            Test by visiting yoursite.com/.env. If you get a 404, the path is correct. If the .env file downloads, the document root is wrong. Fix it before going live.

              Monitoring Queue Workers and Scheduled Tasks

              Background jobs and cron tasks fail silently on shared hosting when queue workers die or cron paths are wrong. You won't see errors unless you check logs manually.

              If you use queues, set up a cron job to restart the worker every hour:

              0 * * * * cd /home/username/laravel && /usr/bin/php artisan queue:restart

              Shared hosting doesn't support supervisor or systemd, so long-running queue:work processes get killed by resource limits. Use queue:listen in cron instead, processing one job at a time:

              * * * * * cd /home/username/laravel && /usr/bin/php artisan queue:work --once

              For scheduled tasks, add this cron entry to run Laravel's scheduler every minute:

              * * * * * cd /home/username/laravel && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

              Log output to a file instead of /dev/null during the first week to catch path errors or missing environment variables. Check storage/logs/laravel.log daily until you confirm jobs are running.

                Measuring Performance Before and After

                Optimization means nothing without measurements. Baseline your app before applying changes, then test again after each step.

                Install Laravel Debugbar locally or use server response headers to track bootstrap time. A typical uncached Laravel 10 request takes 150-250ms on shared hosting. After config and route caching, expect 60-100ms. Autoload optimization shaves another 10-20ms.

                Use browser DevTools to measure Time to First Byte (TTFB). Slow TTFB (above 500ms) points to server-side bottlenecks: missing caches, slow database queries, or session writes. Fast TTFB with slow page render means frontend assets need compression or CDN delivery.

                Monitor memory usage via memory_get_peak_usage() logged at the end of your AppServiceProvider boot method. If peak memory exceeds 80% of your PHP limit, you'll hit random 500 errors under traffic. Offload heavy jobs to queues or paginate large queries.

                  Log Rotation and Disk Space Management

                  Laravel writes every request to storage/logs/laravel.log by default. On a site with 10,000 daily requests, that log file hits 50MB in a week. Shared hosting accounts typically cap at 5-10GB total storage, so unrotated logs eat your quota fast.

                  Configure daily log rotation in config/logging.php by setting the days parameter:

                  'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', 'days' => 7, ],

                  This keeps seven days of logs and deletes older files automatically. For production, change level to 'error' or 'warning' to log only exceptions, cutting file size by 90%.

                  Set up a weekly cron job to check storage usage and alert you if it exceeds 80%. A full disk triggers silent failures across sessions, caches, and file uploads.

                    Quick troubleshooting checklist

                    • Run php artisan config:cache and route:cache before going live
                    • Set APP_ENV=production and APP_DEBUG=false in .env
                    • Verify APP_KEY is set and matches across all deployment files
                    • Configure session driver (database or file) and test CSRF token generation
                    • Run composer install --optimize-autoloader --no-dev
                    • Set correct file permissions: 755 for directories, 644 for files, 775 for storage and bootstrap/cache
                    • Point document root to /public directory in cPanel
                    • Test 419 error scenarios with a form submission after 2+ hours of inactivity
                    • Configure queue workers with supervisor or systemd if background jobs are used
                    • Set up log rotation for storage/logs to prevent disk space issues
                    • Verify .htaccess rewrite rules are active and mod_rewrite is enabled
                    • Test error pages (500, 404, 419) render correctly without debug output

                    FAQ

                    Why does Laravel show 419 page expired error on shared hosting?

                    The 419 error appears when Laravel's CSRF token expires or session storage fails. On shared hosting this happens when APP_KEY is missing or changed, session files fill the disk quota, or the session lifetime is too short for your traffic pattern. Check that APP_KEY exists in .env, storage/framework/sessions has write permissions, and SESSION_LIFETIME in config/session.php matches your user behavior (default is 120 minutes). If users submit forms after long idle periods, increase the lifetime or switch from file to database sessions.

                    How do I run Laravel artisan commands on shared hosting without SSH?

                    Most shared hosts block SSH but allow cron jobs. Create a PHP file in your public directory that runs artisan commands via exec() or shell_exec(), protect it with a secret token in the URL, then trigger it via cron or a browser request. Alternatively, use cPanel Terminal if available, or contact support to run one-time commands like php artisan migrate or php artisan cache:clear. For recurring tasks, set up cron jobs pointing to /usr/bin/php /home/username/artisan schedule:run.

                    What causes slow Laravel performance on shared hosting?

                    Shared hosting limits CPU and memory per account, so Laravel's bootstrap overhead hits harder. The top bottlenecks are uncached routes and configs (add 100-300ms per request), autoloader inefficiency without optimization (20-50ms), and session writes to disk on every request. Enable opcache via php.ini or .user.ini, run config:cache and route:cache, use composer install with --optimize-autoloader --no-dev, and switch to database sessions if file I/O is slow. Monitor response times before and after each change.