Zodiac Tech CRM Docs

Deployment & server errors

Fix 500s, broken uploads, dead queues and failed cron after a deploy — caches, migrations, storage links, the cron.php entry point and safe rollback.

super-admin developer Medium ⏱ 30 min Updated 2026-10-05

Deployment & server errors

Something broke after a deploy, an update or a server change: white screens, 500s, uploads that 404, a queue that stopped draining, or cron that silently is not running. On shared hosting (cPanel/Apache) most of these come down to five things: caches built for the wrong environment, migrations not run, the storage symlink missing, the cron entry point not wired, or a .env that did not travel. Work down this page; each step is a check you can actually perform.

Who this is for: the super admin performing the deploy or update, and developers supporting one.

Problem

The app is up but unhealthy, or unhealthy after a change you just made — and you need to get back to a known-good state without guessing.

What you see

Symptom First suspect
White page / HTTP 500 for all pages Environment or caches built elsewhere, missing APP_KEY, permission errors
SQLSTATE errors Migrations not run, or wrong database credentials
Uploads and images broken (404) Missing storage symlink
Queue never processes; sync driver in production Worker not running / driver misconfigured
Scheduled jobs never fire Cron entry missing or cron.php unreachable
Errors only after an update Cache staleness or a failed migration — rollback path below
"Please provide a valid cache path" / view errors storage/framework/ directories missing or not writable

Likely causes

  • Deployed files without running the migration step, or without clearing/rebuilding caches — a cached config from the old release is the classic post-deploy 500.
  • storage/ and bootstrap/cache/ not writable by the web user on the new host.
  • No storage:link after a fresh deployment or move.
  • The single cron.php entry point (shared hosting) or the schedule:run cron line (VPS) missing — everything "scheduled" then quietly stops.
  • Queue worker not running, or running without the full queue list.
  • .env missing or still holding development values (APP_DEBUG=true, wrong APP_URL, LOG_LEVEL too noisy to find anything).

Quick fix

The one-click recovery pass — on Super Admin → Settings → System Health (/super-admin/settings/system-health), in this order:

  1. Clear caches (optimize:clear) — the first thing to try after any deploy.
  2. Run migrations (migrate --force) — if the update brought schema changes, php artisan migrate:status should then be clean.
  3. Rebuild caches — only once the app is confirmed working; rebuilding too early bakes in a broken state.
  4. Storage link (storage:link) — restores public access to uploads.
  5. Restart queue (queue:restart) — graceful worker restart; note the page warns when the driver is sync, in which case this action does not help and the driver itself needs fixing.

Step-by-step fix

  1. Confirm the blast radius. GET /api/v1/health — 503 tells you which core check (db, cache, storage) is failing. One workspace broken usually means data; everything broken means infrastructure.
  2. Read the log. storage/logs/laravel.log (stack → single driver). If LOG_LEVEL is high, the newest entries are still there — read from the end. Fix the exception class you see, not the symptom you first heard about.
  3. Environment check. .env exists, is readable, and holds the right values: APP_KEY (missing key = instant crypto failures), APP_URL (drives generated URLs, webhooks and redirects — a wrong value silently breaks webhook callbacks), database credentials, QUEUE_CONNECTION. Reference: Environment.
  4. Permissions. storage/ and bootstrap/cache/ must be writable by the web server user, recursively. On cPanel, that is usually 775 with the right group — and recheck it after every deploy, because uploading files often resets ownership.
  5. Storage link. php artisan storage:link (or the System Health action). Verify by opening a known uploaded file's URL.
  6. Maintenance mode around risky steps. php artisan down before a manual fix, php artisan up after verifying — and remember the last step of any incident is turning it back up.
  7. Cron on shared hosting. One entry runs everything: cron.php every minute. It drains the queue within a time budget (max 30 jobs, ~55 seconds) and then runs the scheduler. If web-reachable cron is used, CRON_SECRET protects the endpoint. Check the hosting panel that the cron is actually still configured — after a hosting migration it is the most commonly forgotten piece.
  8. Workers. php artisan queue:work --queue=default,webhooks,automations,integrations,notifications,exports,ai-sdr,mail. All queues on one list. Supervise or restart it after every deploy so it picks up new code.
  9. Applying an update properly. Use Super Admin → Settings → Updates (/super-admin/settings/updates): applying creates a pre-update backup automatically — note its name before clicking, because rollback is "restore that backup" from the Backups page. After the update: clear caches, run migrations, restart the queue, then health-check.
  10. Rollback when it goes wrong. Super Admin → Settings → Backups (/super-admin/settings/backups): verify the pre-update backup, then use Restore (extracts the zip, imports the SQL, reports files restored and rows imported). Deployments on a VPS can roll back code with your normal tooling, but the database side is the backup restore — plan for both.

Admin fix

  • The one-click pass above (System Health + Updates + Backups) covers the whole admin-side toolkit.
  • Keep a short written runbook for your own hosting: where the cron is configured, where the worker is supervised, how the site is deployed. The next deploy, done under pressure, will follow it.

Developer fix

  • Common root: caches (config/route/view) built under one environment served under another. optimize:clear then rebuild after switch/move.
  • cron.php bootstraps the kernel explicitly for shared hosting, enforces the 30-job/55-second budget, checks CRON_SECRET for web access, then runs the queue drain and schedule:run.
  • Vue/asset build outputs and public/build must be deployed alongside PHP; a JS error breaking the panel usually looks like "server is broken" in a screenshot but has no server exception.
  • Check APP_DEBUG before anything else when a screenshot shows a stack trace to an end user — debug mode must be off in production.

Logs to check

  • storage/logs/laravel.log — the primary source; read the newest entries first.
  • Hosting panel: cron history/error mail, PHP error log, disk quota.
  • php artisan migrate:status — any pending migration after a deploy is a red flag.
  • GET /api/v1/health — the fast external verdict after every step.

When to escalate

  • Restores fail or the backup turns out unverifiable — stop, preserve everything, escalate to the platform owner before touching production further.
  • The database itself is unreachable or the host is out of disk/quota — hosting support is the only fix.
  • A reproducible 500 that survives cache clearing, migrations and an untouched .env — capture the full stack trace (with debug on, temporarily, on a staging copy) and hand it to the developer.

Was this page helpful?