EthioDeploy/Docs
HomePricing
Overview

Overview

  • Getting started
  • How deploys work

Frameworks

  • Framework guides

Configuration

  • Web services & background workers
  • Environment variables
  • Addons
  • Database & Redis tools
  • Branch deployments
  • Custom domains
  • Analytics

Domains

  • Buying a domain

Agent mode

  • Agent mode
  • Agent plans & credit

CLI

  • Command-line tool

Account

  • Team access
  • Billing

Help

  • Troubleshooting
  • Still stuck?
Deploy guides
  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Firebase Studio
  • Claude Code & Cursor
Compare
  • AI coding agent
  • Hosting in Ethiopia
  • vs Heroku
  • vs Vercel
  • vs Render
  • vs Railway
  • vs Fly.io
  • vs Netlify
  • Heroku alternatives
Deploy guidesLaravel

Deploy a Laravel app

Laravel is detected from artisan and built on the official PHP image with nginx and PHP-FPM. Vite assets are built for you and config, route and view caches are warmed on start.

Last updated October 23, 2026

Detected by
artisan + laravel/framework in composer.json
Install
composer install --no-dev --optimize-autoloader
Build
npm run build for Vite assets (if package.json has one)
Start
nginx + PHP-FPM, after config:cache, route:cache and view:cache

These are the defaults. Override any of them in Settings → Build.

Laravel 11+ defaults to SQLite, which resets on every deploy

New Laravel apps set DB_CONNECTION=sqlite. The app still starts (we create and migrate the SQLite file on start), but each deploy starts a fresh container, so the file and everything in it is wiped on every push. Add a MySQL or Postgres addon and set DB_CONNECTION as described below before you rely on any data.

Prepare your app

No Dockerfile or nginx config is needed. We build every PHP app from the official php:X.Y-fpm image:

  • PHP version comes from require.php in composer.json (or config.platform.php). We support 8.2 to 8.5 and prefer 8.4 when your constraint allows it.
  • Extensions: bcmath, intl, opcache, pcntl, pdo_mysql, pdo_pgsql and zip are always installed. Anything your app or its packages declare as ext-* in composer.json or composer.lock is added.
  • Frontend assets: if package.json has a build script, it runs on Node 22 after composer install, and the result lands in public/build.
  • On start we run storage:link, config:cache, route:cache and view:cache (plus a fresh SQLite file and migrations if the app is still on SQLite), then start PHP-FPM and nginx with public/ as the web root.
  • Logs go to stderr (LOG_CHANNEL=stderr), so they show in the Logs tab.

Trust the platform's proxy so Laravel generates https:// URLs and asset links. In bootstrap/app.php (Laravel 11+):

->withMiddleware(function (Middleware $middleware) {
    $middleware->trustProxies(at: '*');
})

Environment variables

Add these in the project's settings before the first deploy:

APP_KEY=base64:...        # php artisan key:generate --show
APP_ENV=production
APP_DEBUG=false
APP_URL=https://myapp.ethiodeploy.com

Config is cached at start, after env vars are loaded, so a changed value takes effect on the next deploy. VITE_ values are baked into the assets at build time. See Environment variables.

Add MySQL or Postgres

Add a MySQL or Postgres addon. Its connection string is injected as DATABASE_URL, but Laravel 11 and later read DB_URL. Make the connection you use fall back to it in config/database.php:

'pgsql' => [
    'driver' => 'pgsql',
    'url' => env('DB_URL', env('DATABASE_URL')),
    // ...
],

Then set DB_CONNECTION=pgsql (or mysql). Laravel 10 and earlier already read DATABASE_URL. Run migrations before the server starts by setting the Start command to:

php artisan migrate --force && ethiodeploy-start

ethiodeploy-start is the script that warms the caches and starts nginx and PHP-FPM, so keep it at the end.

Redis for cache, sessions and queues

Laravel 11+ stores cache, sessions and queued jobs in the database by default, which works once migrations have run. To move them to Redis, add a Redis addon (REDIS_URL is injected) and set:

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

Laravel's default Redis client is the phpredis extension. Add "ext-redis": "*" to require in composer.json so it's installed, or install predis/predis and set REDIS_CLIENT=predis.

Queue workers and the scheduler

Addons are private to the project that owns them, so a separate worker project can't reach your database or Redis. Run the queue worker and the scheduler in the same container:

php artisan migrate --force && (php artisan queue:work --tries=3 &) && (php artisan schedule:work &) && ethiodeploy-start

The background processes aren't restarted on their own if they crash, so check the Logs tab after changes. For low volume, QUEUE_CONNECTION=sync runs jobs inline and needs no worker at all.

File uploads

Files written to storage/app are lost on the next deploy, because each deploy starts a fresh container. Use the s3 disk with any S3-compatible storage for user uploads. Requests up to 64 MB are accepted.

Deploy

  1. Sign in with GitHub and install the EthioDeploy app on the repo.
  2. Click “New Project” and pick the repo.
  3. Watch the build in the dashboard. When the health check passes, your app is live at <project-slug>.ethiodeploy.com. Every push to the default branch redeploys, and the old version keeps serving until the new one is healthy.

Troubleshooting

Data disappears after every deploy

Cause: The app is still on SQLite, the Laravel 11+ default, and the file lives in the container.

Fix: Add a MySQL or Postgres addon and set DB_CONNECTION and the DB_URL fallback.

No application encryption key has been specified

Cause: APP_KEY isn't set.

Fix: Run php artisan key:generate --show locally and add the value as APP_KEY.

Mixed content warnings, or CSS and JS load over http://

Cause: Laravel doesn't trust the proxy's forwarded headers.

Fix: Add trustProxies(at: '*') and set APP_URL to your https URL.

Build fails: composer.json requires php ..., which none of the supported versions satisfy

Cause: Your PHP constraint excludes 8.2 to 8.5.

Fix: Widen require.php, for example to ^8.2.

Class "Redis" not found

Cause: The phpredis extension isn't installed.

Fix: Add "ext-redis": "*" to composer.json, or use predis.

Changed an env var but the app still uses the old value

Cause: Config is cached when the container starts.

Fix: Redeploy after changing env vars.

Still stuck? Check the deployment's build log in the dashboard, or see Troubleshooting.

Questions

Which PHP version does my Laravel app run on?

The newest of 8.2, 8.3, 8.4 and 8.5 that your composer.json php constraint allows, preferring 8.4. Images come from the official PHP Docker images, which are refreshed soon after each PHP security release.

Do I need a Dockerfile, nginx.conf or Procfile?

No. nginx, PHP-FPM, the web root and the start script are set up for you. A Procfile is ignored for PHP apps; set a custom start command in Settings if you need one.

Can I use MySQL instead of Postgres?

Yes. Add a MySQL addon instead (a project has one or the other) and set DB_CONNECTION=mysql. Both inject DATABASE_URL.

How do I run Laravel's scheduler without cron?

Run php artisan schedule:work in the background from your start command. It runs due tasks every minute, the same as a cron entry calling schedule:run.

Ready to deploy? Sign in with GitHub and pick your repo. No Dockerfile, no YAML.

Other framework guides

Next.jsNode.jsPythonSvelteKitLovableBoltClaude Code & CursorDjangoFastAPIFlaskExpressGoFirebase Studio

See the full docs for custom domains, env vars, addons, and billing.

On this page

  • Prepare your app
  • Environment variables
  • Add MySQL or Postgres
  • Redis for cache, sessions and queues
  • Queue workers and the scheduler
  • File uploads
  • Deploy
  • Troubleshooting
  • Questions

Product

  • Pricing
  • Documentation
  • AI coding agent
  • Agent mode docs
  • Domains
  • Hosting in Ethiopia

Deploy guides

  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Firebase Studio
  • Claude Code & Cursor

Compare

  • EthioDeploy vs Heroku
  • EthioDeploy vs Vercel
  • EthioDeploy vs Render
  • EthioDeploy vs Railway
  • EthioDeploy vs Fly.io
  • EthioDeploy vs Netlify
  • Heroku alternatives

Company

  • About
  • Support
  • Contact
  • Terms
  • Privacy

EthioDeploy: agentic first development and deployment, started in Ethiopia, built for developers everywhere.