foxws / laravel-podman
Podman Quadlet support to your Laravel application
Fund package maintenance!
Requires
- php: ^8.4
- composer-runtime-api: ^2.0
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/contracts: ^11.0||^12.0||^13.0
- illuminate/filesystem: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- spatie/laravel-package-tools: ^1.16
- symfony/console: ^6.0|^7.0|^8.0
Requires (Dev)
- aws/aws-sdk-php: ^3.322
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^11.0.0||^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
Suggests
- aws/aws-sdk-php: Required to use the "podman:s3-setup" command (^3.322).
README
Laravel Podman is a lightweight Laravel package that brings Podman Quadlet support to your app. It generates services from presets and installs them as systemd-managed containers.
It relies on your host Podman/systemd setup (instead of an all-in-one runtime), so it gives you a more advanced and flexible setup. You can swap bundled parts like the default Caddy proxy for your own setup (for example Nginx).
Features
- Ready presets — Use built-in presets for common needs:
frankenphp-octane,development,devcontainer, andproxy. You can also add your own. See Presets. - Generate first, install later — Artisan commands create Quadlet files from your app config. Then
lpodinstalls and manages those services on the host. - Simple daily commands with
lpod— Start and stop services, open a shell, run app commands, and manage installed units from one CLI. - Setup without host PHP (
lpod-setup) — Render presets on machines that have Podman but not PHP installed. - Safe secret handling (
lpod-secrets) — Store.envvalues and service passwords as Podman secrets instead of plain text files.
See the docs/ folder for more: Command Reference, Setting up without PHP on the host, Proxy, S3 Buckets, The lpod CLI, Customizing, Comparison.
Requirements
- Linux with systemd (rootless or system-wide); macOS and Windows, including WSL, are not supported
- A recent version of Podman with the
quadletCLI plugin (podman quadlet --helpshould work)
Installation
You can install the package via composer:
composer require foxws/laravel-podman
You can publish the config file with:
php artisan vendor:publish --tag="podman-config"
This is the contents of the published config file:
return [ 'enabled' => env('PODMAN_ENABLED', true), 'presets' => env('PODMAN_DEFAULT_PRESETS', [ // 'development', // 'devcontainer', 'frankenphp-octane', 'proxy', ]), 's3_buckets' => env('PODMAN_S3_BUCKETS', [ 'local', 'assets', 'media', 'conversions', ]), 's3_cors_buckets' => env('PODMAN_S3_CORS_BUCKETS', [ 'conversions', 'assets', ]), 'quadlet_prefix' => env('PODMAN_QUADLET_PREFIX', env('APP_NAME', 'laravel')), 'proxy_prefix' => env('PODMAN_PROXY_PREFIX', 'proxy'), 'stubs_path' => env('PODMAN_STUBS_PATH', 'containers/stubs'), 'working_path' => env('PODMAN_WORKING_PATH'), 'quadlet_uid' => env('PODMAN_QUADLET_UID'), 'quadlet_gid' => env('PODMAN_QUADLET_GID'), 'publish_path' => env('PODMAN_PUBLISH_PATH', 'podman'), 'selinux_volume_mapping' => env('PODMAN_SELINUX_VOLUME_MAPPING', true), ];
quadlet_prefix is used to namespace the services installed for your application (for example laravel-pgsql), and defaults to your APP_NAME. quadlet_uid/quadlet_gid default to the UID/GID of the user running the Artisan command. s3_buckets/s3_cors_buckets are used by podman:s3-setup — see S3 Buckets.
development is commented out by default — enable it (or pass --preset=development to podman:setup/podman:generate) if you want your working copy live-mounted into the container instead of baked into the image.
Presets
| Preset | Purpose |
|---|---|
frankenphp-octane |
Production-style app image (code baked in) plus its full set of sibling services — database, cache, queue worker, WebSockets, scheduler, SSR, search, S3-compatible storage, mail catcher. |
development |
The same services, but with your working copy live-mounted into the container instead of baked in, for local editing. Commented out by default — see the config above. |
devcontainer |
An image for the VS Code/JetBrains Dev Containers workflow. Not Quadlet-managed — just a Containerfile and devcontainer.json, no quadlets/. |
proxy |
Caddy reverse proxy terminating HTTPS in front of the other services. See Proxy. |
s3 |
A cors.json policy applied by podman:s3-setup against your S3-compatible storage buckets. Not Quadlet-managed either — no quadlets//runtimes/, just the one file. See S3 Buckets. |
Custom presets. A preset is a folder containing a quadlets/ directory of *.quadlets files and a runtimes/ directory of container build files (the devcontainer/s3 presets are exceptions — see the table above). stubs_path (default containers/stubs) is the lookup root for custom presets. For each preset name, the package uses stubs_path/{preset} if it exists; otherwise it falls back to the bundled vendor preset. Once a preset exists under stubs_path, that preset is fully overridden (no file-by-file merge). So you can publish one preset (php artisan podman:publish frankenphp-octane) without touching the others.
Quick Start
The fastest way to render an application's Quadlet units is podman:setup. It generates the default presets' .quadlets/runtime build files in one go, so you don't need to call podman:generate per preset:
php artisan podman:setup
Note: This step only renders files — it substitutes your app's config into the preset's templates and writes the result to the
publish_pathconfig key (podmanby default, one subfolder per preset). It never touches thepodmanbinary, so it works even without Podman installed (e.g. inside a disposablephpcontainer in CI). If you don't have PHP on the host at all, see Setting up without PHP on the host.Generated files in
publish_path(defaultpodman/) are build artifacts. Do not commit them. Add the path to.gitignore(default:/podman), and remove/re-generate it any time afterlpod install.
The presets it generates by default come from the presets config key (frankenphp-octane/proxy out of the box; development/devcontainer are opt-in — see Presets) — edit that, set PODMAN_DEFAULT_PRESETS, or override per run:
php artisan podman:setup --preset=frankenphp-octane
Installing is a separate step, handled by lpod on the host (this is the one step that actually needs the podman binary):
vendor/bin/lpod install frankenphp-octane/app.quadlets --replace
vendor/bin/lpod install frankenphp-octane/pgsql.quadlets --replace
vendor/bin/lpod install frankenphp-octane/valkey.quadlets --replace
vendor/bin/lpod install proxy/proxy.quadlets --replace
# ...and so on for every service you need.
Note:
devcontainerands3aren't Quadlet-managed (see Presets), so there's nothing tolpod installfor them — build the devcontainer image through your editor's Dev Containers extension, and runs3's CORS policy throughpodman:s3-setupinstead.
Secrets a service needs (e.g. your application's .env file, database credentials) are prompted for and set once the service is installed, by unit name:
vendor/bin/lpod secrets app vendor/bin/lpod secrets pgsql
Once installed, use lpod to start everything:
vendor/bin/lpod my-app up
vendor/bin/lpod my-app open # Opens the application URL in your browser
The bundled proxy preset terminates HTTPS with a locally-trusted certificate — trust it once so your browser/OS stop flagging it, see Trusting the local certificate.
Setting up somewhere PHP isn't installed (a disposable container, CI)? Once lpod itself is on the host, vendor/bin/lpod setup (a shortcut for the lpod-setup binary — see The lpod utility) renders the default presets the same way, without needing PHP:
vendor/bin/lpod setup vendor/bin/lpod setup --preset=frankenphp-octane
See Setting up without PHP on the host for the raw podman run ... equivalent (e.g. before lpod is available at all) and the details of what gets rendered where.
Usage
The package discovers preset folders (each containing a quadlets/ directory of *.quadlets files and a runtimes/ directory of container build files) on disk, and exposes them through Artisan commands that only ever render — never install. Every command that needs a preset name will prompt you to select one interactively when it's omitted. Full flag reference and examples: Command Reference.
| Command | Description |
|---|---|
podman:setup |
Generate the default set of presets in one go (see Quick Start) |
podman:publish PRESET |
Publish a preset (its quadlets and runtime files) for customization |
podman:generate PRESET |
Render a single preset's quadlets and runtime files |
podman:s3-setup |
Create S3 buckets and a CORS policy (requires aws/aws-sdk-php, see S3 Buckets) |
Installing, listing, printing, removing, and setting secrets for the rendered services is lpod's job, not Artisan's — see below.
Warning:
lpod remove/lpod uninstalldelete the Podman volumes owned by the services they remove (databases, uploaded files, search indexes), with no undo. Back up first — see Backing up volumes.
The lpod utility
The package ships three Composer binaries that all run on the host — they talk to the real podman/systemctl binaries, unlike the Artisan podman:* commands, which only render templates and can run anywhere PHP is available:
vendor/bin/lpod— a thin wrapper aroundpodman exec,podman quadlet, andsystemctlfor the Quadlet services rendered by Artisan, similar in spirit to Laravel Sail'ssailscript.vendor/bin/lpod-setup— renders presets by runningphp artisan podman:setupinside a disposable container, for hosts that have Podman but not PHP. See Setting up without PHP on the host.vendor/bin/lpod-secrets— prompts for and stores the Podman secrets an installed Quadlet unit needs.
lpod setup and lpod secrets are convenience aliases for the latter two — call vendor/bin/lpod-setup/vendor/bin/lpod-secrets directly if you'd rather skip the lpod wrapper.
vendor/bin/lpod SERVICE COMMAND [options] [arguments]
vendor/bin/lpod my-app up
vendor/bin/lpod my-app artisan queue:work
vendor/bin/lpod my-app shell
# Installing, secrets, and other Quadlet management (see below)
vendor/bin/lpod install frankenphp-octane/app.quadlets --replace
vendor/bin/lpod secrets app
See The lpod CLI for the full command reference (including install/secrets/remove/list/print/uninstall), shortening the call with an alias/PATH entry, and tips & tricks.
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
Disclaimer
AI, specifically Claude, was used to help build this package. All AI-assisted output is reviewed by me, and I retain final say over everything that is implemented and released.
License
The MIT License (MIT). Please see License File for more information.