Framework guides
Laravel
Deploy Laravel with PostgreSQL, then add queues, the scheduler, object storage and Redis caching.
Symfony
Deploy a Symfony application from a Git repository.
WordPress
Deploy WordPress from a Git repository with a MySQL database.
How PHP applications run on Sevalla
Every process (web, worker, cron job and job) runs from the same image, each with its own start command. Ingot recommends processes it finds a use for, such as a migration job when
database/migrations has migrations, and lists them in the generated Dockerfile’s header; it doesn’t create them. See Run workers and jobs.
Pin the PHP version
Ingot builds on PHP 8.5, its default line, unless the project sets a version. Pin the line you develop with inrequire.php in composer.json, so the build doesn’t change when a new Ingot release moves its default line:
INGOT_PHP_VERSION environment variable, versions.php in ingot.json, config.platform.php in composer.json, then require.php. A range such as ~8.5.0 or ^8.3 builds on the newest release of a line it allows, preferring Ingot’s default line, so every new build picks up the line’s security fixes. Ingot 0.4.1 knows PHP 8.2 to 8.5. The build plan’s PHP row shows the version and where it came from.
Ingot also checks composer.lock, because Composer refuses to install a package that doesn’t support the PHP it runs on:
- When only
require.phpsets the version, or nothing does, and a locked package doesn’t support the line Ingot would choose, Ingot builds on the newest line that every locked package supports and names the package in the PHP row. - When you set the version with the variable,
ingot.jsonorconfig.platform.php, and a locked package doesn’t support it, the build fails withPHP 8.5 doesn't satisfy composer.lock: <package> requires php "<range>". Runcomposer updateto lock newer packages, or choose a version they support. - Write
~8.5.0or8.5.*rather than8.5: Composer reads8.5as exactly 8.5.0, so Ingot installs with--ignore-platform-req=php+and warns about it.
PHP extensions
FrankenPHP’s image includes the extensions most applications need, among themctype, curl, dom, fileinfo, mbstring, openssl, pdo_sqlite, sodium, tokenizer, xml, zlib and OPcache. Ingot installs more from these sources, and the build plan’s Extensions row names each one with its source:
To add an extension Ingot doesn’t detect, add it to
require in composer.json, for example "ext-imagick": "*". Composer then refuses to install without it on your computer too, which keeps your computer and the image in step.
Build with a Dockerfile
Ingot needs no Dockerfile. To control every layer of the image, the Dockerfile build strategy builds your own. A Dockerfile for PHP on Sevalla installs the extensions withinstall-php-extensions in a stage based on FrankenPHP’s official image and lists the Debian packages their libraries come from, installs the dependencies with composer install --no-dev from composer.lock in a build stage, builds front-end assets in a Node.js stage, and copies PHP, those packages and the application into a debian:trixie-slim final image that runs as a non-root user. FrankenPHP listens on PORT and trusts Sevalla’s proxy for HTTPS, as Ingot’s configuration does, and nothing secret is written into the image. Deploy Laravel, Symfony and WordPress each have a complete example.