Skip to content

Laravel ​

What Zenavo detects ​

A repository with composer.json (or index.php) builds with zbpack as PHP, and laravel/framework in composer.json marks it as Laravel. The image is the official php:<version>-fpm image with nginx in front, listening on port 8080:

StepWhat happens
PHP versionZBPACK_PHP_VERSION, else the Laravel Sail runtime in docker-compose.yml, else require.php in composer.json; 8 when none is set
Extensionsapcu, bcmath, gd, intl, mysqli, opcache, pcntl, pdo_mysql, sysvsem and zip, plus every ext-* in composer.json (add "ext-pdo_pgsql": "*" for PostgreSQL)
Installcomposer install --optimize-autoloader --classmap-authoritative --no-dev, and npm install when there is a package.json (Node.js 22)
Optimizephp artisan optimize, config:cache, event:cache, route:cache, view:cache, then npm run build if package.json has a build script
Servenginx serves public/ and passes PHP to php-fpm

Settings for Laravel ​

The optimize step runs during the build, and builds do not get the service's variables (Build Plan). config:cache would cache a configuration without your database and APP_KEY, and Laravel then ignores the variables at runtime. Turn the build-time optimization off and run it when the service starts instead. Under Settings → Build → zbpack options:

sh
ZBPACK_PHP_OPTIMIZE=false
ZBPACK_BUILD_COMMAND=npm run build
ZBPACK_START_COMMAND=php artisan migrate --force && php artisan optimize && _startup
  • ZBPACK_BUILD_COMMAND builds the Vite assets, which the optimize step would otherwise have done. Leave it out if the app has no front-end build.
  • _startup starts nginx and php-fpm; it must come last. php artisan optimize caches the configuration, routes, events and views with the service's variables, and migrations run before the app starts serving, because the build cannot reach the database.

Variables ​

On the service's Variable tab:

sh
APP_KEY=base64:…
APP_ENV=production
APP_DEBUG=false
APP_URL=${ZENAVO_WEB_URL}
LOG_CHANNEL=stderr
DB_CONNECTION=pgsql
DB_URL=${POSTGRESQL_CONNECTION_STRING}
  • Create APP_KEY once with php artisan key:generate --show on your computer, and keep it: changing it logs everyone out and makes encrypted data unreadable.
  • LOG_CHANNEL=stderr sends Laravel's logs to Runtime Logs instead of files in the container, which are lost on every deploy.
  • APP_URL uses the domain of the port named web; use the name shown on the Networking tab.
  • For MySQL, use DB_CONNECTION=mysql and DB_URL=${MYSQL_CONNECTION_STRING}. Laravel reads DB_URL from version 11; older versions use DATABASE_URL.
  • Redis for cache, sessions and queues: REDIS_URL=${REDIS_CONNECTION_STRING}, CACHE_STORE=redis, SESSION_DRIVER=redis.

Deploy ​

  1. Add PostgreSQL (or MySQL) to the project (Databases).
  2. Add Service → GitHub, pick the repository and branch, add the variables above and click Next.
  3. Check that the preview shows php, then click Deploy. Set the zbpack options above under Settings → Build and redeploy.
  4. Generate a domain or bind your own on the Networking tab.

Files and queues ​

  • Uploads in storage/app are lost on every deploy. Store them in S3-compatible storage (FILESYSTEM_DISK=s3 with the AWS_* variables).
  • Queue workers and the scheduler run as separate services from the same repository: add the repository again with the start command php artisan queue:work (or php artisan schedule:work) in ZBPACK_START_COMMAND, and no HTTP port.

Common problems ​

SymptomCause
No application encryption key has been specifiedAPP_KEY is missing, or the configuration was cached during the build. Set APP_KEY and ZBPACK_PHP_OPTIMIZE=false.
The app uses SQLite or localhost instead of the databaseThe configuration was cached during the build, without the variables. Set ZBPACK_PHP_OPTIMIZE=false and run php artisan optimize at start.
could not find driverThe PDO extension is missing. Add "ext-pdo_pgsql": "*" to require in composer.json.
CSS and JavaScript return 404The Vite build did not run. Set ZBPACK_BUILD_COMMAND=npm run build.
Links and redirects use http://Laravel does not trust the proxy in front of it. Trust it in bootstrap/app.php with $middleware->trustProxies(at: '*').

Not affiliated with Zeabur.