| Install | |
|---|---|
composer require asamoahboateng/frankenphp-deploy |
|
| Latest Version: | v1.3.1 |
| PHP: | ^8.2 |
FrankenPHP + Traefik Docker deployment scaffolding for Laravel Octane projects.
composer require asamoahboateng/frankenphp-deploy --dev
# Install the scaffolding (interactive prompts for domain and project name)
php artisan frankenphp:install
# Or with options
php artisan frankenphp:install --domain=myapp.test --project=myapp
# With pgvector support (vector similarity search)
php artisan frankenphp:install --domain=myapp.test --project=myapp --pgvector
This will create:
frankenphp_server/ directory with Docker configuration filespha CLI script in your project rootcd frankenphp_server
./setup-ssl.sh
This uses mkcert to generate trusted local SSL certificates into certs/local/.
When using Traefik, each project manages its own SSL certificate. Place your cert files in the project's frankenphp_server/certs/ directory:
frankenphp_server/certs/
├── local/ ← local dev certs (generated by setup-ssl.sh)
│ ├── cert.pem
│ └── key.pem
└── prod/ ← production certs (you provide these)
├── cert.pem
└── key.pem
Set APP_ENV=local or APP_ENV=production in your .env to control which certs are loaded.
When ./pha start runs, a cert_loader service copies each project's certs into shared Docker volumes (traefik_certs, traefik_dynamic). Traefik watches these volumes and automatically picks up certificates for all projects — so each domain gets its own SSL without any Traefik restart.
# Start with Traefik reverse proxy (recommended for multiple projects)
./pha start
# Or start standalone (FrankenPHP handles SSL directly)
./pha standalone
| Command | Description |
|---|---|
./pha start |
Start with Traefik reverse proxy |
./pha standalone |
Start without Traefik (FrankenPHP handles SSL) |
./pha stop |
Stop all containers |
./pha reboot |
Restart all services |
./pha reload |
Reload Octane workers (zero downtime) |
./pha fresh |
Wipe and rebuild (local only) |
./pha delete |
Remove all containers, images, volumes |
| Command | Description |
|---|---|
./pha scale [n] |
Scale to n replicas (e.g., ./pha scale 4) |
| Command | Description |
|---|---|
./pha art [cmd] |
Run artisan command |
./pha composer |
Run composer command |
./pha npm |
Run npm command |
./pha tinker |
Open Laravel tinker |
./pha ssh |
Shell into container |
| Command | Description |
|---|---|
./pha ls |
List running containers |
./pha logs |
Tail FrankenPHP logs |
./pha status |
Show detailed status |
After installation, edit frankenphp_server/.env to customize:
APP_URL=https://myapp.test/
APP_DOMAIN=myapp.test
APP_PORT=8000
APP_ENV=local
COMPOSE_PROJECT_NAME=myapp
TRAEFIK_HOST=traefik.myapp.test
ADMINER_DOMAIN=adminer.myapp.test
Standalone (./pha standalone) |
Traefik (./pha start) |
|
|---|---|---|
| SSL | FrankenPHP/Caddy handles SSL directly | Traefik terminates SSL, proxies to FrankenPHP |
| Ports | Exposes 80, 443, 443/udp (HTTP/3) | No ports exposed — Traefik routes traffic |
| Multi-project | One app per server | Multiple apps on the same server |
| Scaling | Single container | Horizontal scaling via replicas |
| Cert management | Caddy auto-manages or uses local certs | cert_loader copies certs to shared Traefik volumes |
| Adminer | Exposed on port 8080 | Routed via adminer.yourdomain.com |
Use standalone for a single app on a server (simpler, fewer moving parts). Use Traefik when you need multiple apps sharing ports 80/443 or horizontal scaling.
┌─────────────┐
│ Traefik │ ← SSL termination, routing
│ (port 443) │
└──────┬──────┘
│
┌──────┴──────┐
│ FrankenPHP │ ← Laravel Octane
└──────┬──────┘
│
┌──────┴──────┐
│ Init │ ← composer install, migrations
└──────┬──────┘
│
┌──────┴──────┐
│ Services │ ← PostgreSQL, Redis, Queue Worker, DB Backup
└─────────────┘
┌─────────────┐
│ FrankenPHP │ ← SSL via Caddy + Laravel Octane
│ (port 443) │
└──────┬──────┘
│
┌──────┴──────┐
│ Init │ ← composer install, migrations
└──────┬──────┘
│
┌──────┴──────┐
│ Services │ ← PostgreSQL, Redis, Queue Worker, DB Backup
└─────────────┘
The init service is a one-shot container that runs before the main FrankenPHP application starts. It ensures your environment is ready by performing:
composer install --optimize-autoloader)php artisan migrate --forceThe startup order is: db/redis → init → frankenphp → worker
The init container uses the same Docker image as the app, exits after completing its tasks, and will not restart. If it fails (e.g., a migration error), the main app will not start — allowing you to fix the issue before the app serves traffic.
To customize what the init service runs, edit frankenphp_server/init.sh.
The db_backup service runs alongside your app and performs a weekly pg_dump of the PostgreSQL database. Each time it runs, it deletes the previous backup and creates a fresh compressed dump.
Backups are stored in frankenphp_server/db-backups/ on the host:
frankenphp_server/db-backups/
└── backup_20260222_030000.sql.gz
To restore from a backup:
gunzip -c frankenphp_server/db-backups/backup_*.sql.gz | docker exec -i <db_container> psql -U laravelUser -d laravel
To enable vector similarity search, use the --pgvector flag during installation:
php artisan frankenphp:install --pgvector
This switches the database image from postgres:16-alpine to pgvector/pgvector:pg16. After starting the containers, enable the extension in your database:
CREATE EXTENSION vector;
This is useful for AI/ML applications that need to store and query vector embeddings (e.g., with Laravel Scout or custom similarity search).
Typesense is included by default but is optional. It's useful for Laravel Scout integration.
Set your API key in frankenphp_server/.env:
TYPESENSE_API_KEY=your-secure-api-key
Add to your Laravel .env:
SCOUT_DRIVER=typesense
TYPESENSE_HOST=typesense
TYPESENSE_PORT=8108
TYPESENSE_PROTOCOL=http
TYPESENSE_API_KEY=your-secure-api-key
Install Laravel Scout with Typesense:
composer require laravel/scout typesense/typesense-php
If you don't need search functionality, comment out or delete the Typesense service in your docker-compose files:
In frankenphp_server/docker-compose-traefik.yml and docker-compose-standalone.yml:
# Comment out or delete this entire block:
# typesense:
# image: typesense/typesense:27.1
# container_name: myapp_typesense_franken
# ...
Also remove the Typesense environment variables from the frankenphp service:
# Remove these lines:
# - TYPESENSE_HOST=typesense
# - TYPESENSE_PORT=8108
# - TYPESENSE_PROTOCOL=http
# - TYPESENSE_API_KEY=${TYPESENSE_API_KEY:-xyz123}
To customize the package configuration:
php artisan vendor:publish --tag=frankenphp-config
This publishes config/frankenphp.php where you can set default values for Traefik network names and other settings.
To reinstall and overwrite existing files:
php artisan frankenphp:install --force
MIT