# Deploying Laravel Applications

> Best practices and configuration tips for deploying Laravel applications on Ploi Cloud.

Laravel on Ploi Cloud
---------------------

Ploi Cloud is optimized for Laravel applications, providing automatic configuration and best practices out of the box.

### Automatic Configuration

When you create a Laravel application, Ploi Cloud automatically:

- Sets up the correct PHP version and extensions
- Installs your Composer dependencies
- Runs database migrations during deployment
- Generates a secure APP\_KEY for encryption
- Configures Laravel scheduler (when enabled)

### Environment Secrets

Essential environment variables for Laravel applications:

```
  APP_ENV=production
  APP_DEBUG=false
```

Database connection variables are automatically injected when you add a database service.

### Database Migrations

Migrations run automatically as init commands during deployment:

- The default command is `php artisan migrate --force`
- Migrations execute when your application starts, before serving traffic
- If migrations fail, the application startup stops to prevent issues
- Init commands run on every deployment to ensure your database is up to date

### Queue Workers

To process Laravel queues, add a Worker service:

1. Navigate to your application's Services section
2. Click "Add service" and select "Worker"
3. Enter a descriptive name (e.g., "queue-worker")
4. Set the command to `php artisan queue:work --sleep=3 --tries=3`
5. Deploy your application to start the worker

Workers use the same code and storage as your main application.

### Laravel Scheduler

The Laravel scheduler runs your scheduled tasks automatically:

1. Go to your application's Settings tab
2. Find the "Laravel scheduler" section
3. Toggle "Enable scheduler" to activate it
4. Deploy your application to apply the change

The scheduler executes `php artisan schedule:run` every minute.

### Build Commands

Default build commands for Laravel applications:

- `composer install --no-interaction --optimize-autoloader --no-dev`
- If you enable frontend builds: `npm ci` and `npm run build`

You can customize these in the Build Configuration section.

### HTTPS URLs behind the load balancer

Ploi Cloud terminates TLS at the load balancer and forwards requests to your application over plain HTTP, adding the standard `X-Forwarded-Proto: https` header. This internal hop stays on the private network between the load balancer and your application, so it is not insecure. It is the standard pattern for any app sitting behind a reverse proxy or load balancer. Laravel only honours that header when the `TrustProxies` middleware is registered. Without it, helpers like `route()`, `url()`, `action()` and `asset()` generate URLs with `http://` even though visitors arrived over HTTPS. This typically shows up as form `action` attributes, redirects, password reset or email verification links, or signed URLs being rendered with the wrong scheme.

On Laravel 11 and 12 the middleware is configured in `bootstrap/app.php`:

```php
use Illuminate\Foundation\Application;
use Illuminate\Http\Middleware\TrustProxies;
use Illuminate\Http\Request;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->trustProxies(at: '*', headers: Request::HEADER_X_FORWARDED_FOR
            | Request::HEADER_X_FORWARDED_HOST
            | Request::HEADER_X_FORWARDED_PORT
            | Request::HEADER_X_FORWARDED_PROTO
            | Request::HEADER_X_FORWARDED_AWS_ELB);
    })
    ->create();
```

On Laravel 10 and earlier, set `$proxies = '*'` in `app/Http/Middleware/TrustProxies.php` and make sure the middleware stays in the global `$middleware` array of `app/Http/Kernel.php`.

If your application uses a custom `Http\Kernel` that replaces the default middleware stack, add `\Illuminate\Http\Middleware\TrustProxies::class` back to the global `$middleware` array. Setting `APP_URL=https://...` is not enough on its own, because the URL generator uses the incoming request's scheme, not `APP_URL`, for requests served through the web server.

As a quick fallback you can also call `URL::forceScheme('https')` in `AppServiceProvider::boot()` when `app()->environment('production')`, but registering `TrustProxies` is the recommended fix because it also exposes the correct client IP and host.
