A PHP app deploys from its repository with no Dockerfile. Nimbus Land recognises it from a root composer.json and serves it with Apache.
Quick start#
A stock laravel new project deploys as is. In the console, create an app from your repository with the deploy wizard. From the CLI, run this in the project directory:
nimbus deploy
Check these first:
composer.jsonis at the root of the app (or choose the app directory; see repositories with several apps).- Anything the app must keep is not in the app directory. Files written at run time are lost on the next release. See Where your app can write.
- Laravel: accept the suggested Postgres database and release command in the wizard. See Laravel.
Apache by default#
Unless you commit a Procfile, Nimbus Land serves the app with Apache and configures it to treat requests that reached the platform over HTTPS as HTTPS, so your app builds https:// URLs. A committed Procfile always wins, for example:
web: heroku-php-nginx -C nginx.conf public/
See what every app needs.
Laravel#
A stock laravel new project deploys as is:
- Document root. Apache serves
public/(Nimbus: no Procfile; serving public/ with Apachein the log). Nothing above it (.env,composer.json,routes/) is reachable. APP_KEYis generated on the first deploy when absent and stored on the app, so sessions and encrypted values survive redeploys. It is stored as a plain variable: mark it secret on the Resources tab once the first deploy succeeds. A key committed in.envdoesn't count, because the platform's variable takes precedence.APP_URLis set tohttps://<app>.nimbusapps.ca(or your verified custom domain) when unset. When you add a custom domain on the Access tab, you can moveAPP_URLto it. See Custom domains.- Environment. The wizard suggests
APP_ENV=production,APP_DEBUG=falseandLOG_CHANNEL=stderr. The last one sends Laravel's logs to the app's logs instead of a file inside the instance. - Front-end assets. If
package.jsonhas abuildscript, the build installs Node dependencies with your lockfile's package manager (npm ci,yarn installorpnpm install), runsbuildwith Node 22, and putspublic/build/in the image. Onlybuildruns. Without a lockfile, one is generated for the build. - Database. The wizard suggests Postgres, pre-checked, because a stock project keeps sessions, cache and queues in the database. Attaching it sets
DB_URL,DB_HOST,DB_PORT,DB_DATABASE,DB_USERNAME,DB_PASSWORDandDB_SSLMODE, and the wizard addsDB_CONNECTION=pgsql. - Migrations. The wizard suggests
php artisan migrate --forceas the release command (see release command). To run it once:nimbus run php artisan migrate --force, or Run a command on the Monitoring tab. - Queue workers. In Background workers on the Resources tab, add Queue worker (
php artisan queue:work) or Scheduler (php artisan schedule:work). See commands, workers and one-off runs.
Symfony#
Symfony apps are also served from public/, and need symfony/apache-pack for routes other than / to work under Apache.
Plain PHP#
For PHP without Laravel or Symfony, and no Procfile, Apache serves:
- the repository root, if it has an
index.phporindex.html; - otherwise the one folder among
public/,www/,web/,htdocs/andpublic_html/that has one, so nothing outside it is reachable; - otherwise the root, with a build log warning. Serving the root exposes every file in the repository, so add a
Procfile(web: heroku-php-apache2 site/).
Where your app can write#
The app directory (/workspace/src) and /tmp are writable, but each instance has its own copy, reset on every release and restart. Everything else is read-only, so writing to /var/www/uploads fails with Permission denied; build paths from __DIR__. Keep files that must last (uploads, a SQLite database) on a volume mounted outside the document root, such as /workspace/src/storage, or in object storage.
Troubleshooting#
For problems that aren't specific to PHP, such as an app that never answers, see Apps troubleshooting.
Page styles or scripts blocked#
The page loads over HTTPS but has no styles or JavaScript, the browser console reports Mixed Content, and the app's Overview shows Page loads styles or scripts over HTTP (see Page check).
Nimbus Land handles HTTPS at its edge and forwards requests to your app over HTTP with X-Forwarded-Proto: https. A framework that doesn't trust that header builds http:// URLs. Only Nimbus Land's edge can reach your app, so trusting every proxy is safe:
- PHP without a
Procfile(Laravel, Symfony, WordPress, plain PHP): deploy again. - Laravel with its own
Procfile: Laravel 11 and later,$middleware->trustProxies(at: '*')inbootstrap/app.php; Laravel 10,protected $proxies = '*';inapp/Http/Middleware/TrustProxies.php. - Symfony:
framework.trusted_proxies: '127.0.0.1,REMOTE_ADDR'andtrusted_headers: ['x-forwarded-for', 'x-forwarded-proto']. - A hard-coded
http://URL (a CDN, a theme setting): change it tohttps://.
Then choose Check again on the Overview.
Permission denied writing a file#
The path is outside the app directory and /tmp. See Where your app can write.
Routes other than / return 404 (Symfony)#
Add symfony/apache-pack. See Symfony.
Database certificate errors#
Attaching Postgres sets DATABASE_CA_CERT. PHP's libpq connects in prefer mode by default, which works as is. To verify the certificate, write DATABASE_CA_CERT to a file at start-up and use sslmode=verify-full sslrootcert=<path>.
Also available as Markdown.