Quick Start — PHP¶
Deploy a PHP app (plain PHP, Laravel, Symfony, Slim) from git push to a live HTTPS URL in 5 minutes.
Prerequisites¶
- A PHP project with
composer.json - PHP 8.2+ on your machine (
php --version) - The
paasCLI:
Scaffold (if you don't have a project yet — plain PHP)¶
mkdir hello-paas && cd hello-paas
cat > composer.json <<'EOF'
{
"name": "octave/hello-paas",
"require": {
"php": "^8.2"
}
}
EOF
mkdir -p public
cat > public/index.php <<'EOF'
<?php
header('Content-Type: text/plain');
echo "Hello from PaaS Runtime!\n";
EOF
composer install --no-interaction
git init && git add -A && git commit -m "init"
For Laravel:
composer create-project laravel/laravel hello-paas
cd hello-paas
git init && git add -A && git commit -m "init"
Step 1 — Authenticate¶
Verify:
Step 2 — Create the app¶
Output:
✓ Created app hello-paas
URL: https://hello-paas.runtime.di2amp.com
Region: eu-fr-1
Plan: free
Git: https://git.di2amp.com/octave/hello-paas.git
Step 3 — Add a Procfile¶
The Paketo PHP buildpack ships with PHP-FPM + Apache (or Nginx). The simplest production server is heroku-php-apache2:
For plain PHP without Apache (smaller, slower):
Commit:
Step 4 — Push to deploy¶
Live build logs:
remote: ─────── PaaS Build ───────
remote: → Detected: php (paketo-buildpacks/php)
remote: → Installing PHP 8.3.6 (cli + fpm)
remote: → Installing Composer 2.7.2
remote: → Running: composer install --no-dev --optimize-autoloader
remote: → Image: registry.di2amp.com/octave/hello-paas:abc1234
remote: → Image size: 142 MB (PHP runtime + extensions + vendor)
remote: → SBOM: ✓ generated, 36 packages
remote: → CVE scan: ✓ 0 critical, 0 high
remote:
remote: ─────── PaaS Deploy ───────
remote: → Process types: web
remote: → Replicas: 1/1 ready
remote: → Rollout: v1 → v2 (canary 10% → 100%)
remote: → Health: / returns 200 OK
remote: → URL: https://hello-paas.runtime.di2amp.com
remote:
remote: ✓ Deployed in 41s
Step 5 — Verify the app is live¶
Dashboard runtime status:
https://ma30.di2amp.com/runtime/dashboard/apps/hello-paas
Next steps¶
Add a managed PostgreSQL¶
DATABASE_URL is injected (Laravel .env reads it automatically):
$dsn = parse_url(getenv('DATABASE_URL'));
$pdo = new PDO("pgsql:host={$dsn['host']};dbname=" . ltrim($dsn['path'], '/'),
$dsn['user'], $dsn['pass']);
Tail logs¶
Laravel migrations on deploy¶
Enable extensions¶
The Paketo PHP buildpack reads composer.json require constraints (ext-pdo, ext-mbstring, etc.) and enables them automatically. Force additional extensions: