Laravel Podman

Host Setup

Setting up without PHP on the host

podman:generate/podman:setup only render files — they never touch the podman binary, so they run anywhere PHP does. The output is a build artifact: don't commit it, and feel free to delete and regenerate it any time.

Normal workflow: render on your dev machine as usual (php artisan podman:setup), then copy the generated podman/ folder to production and install it there with lpod. Production needs no PHP, and lpod doesn't need this package installed either.

No PHP anywhere

What if there's no PHP on the rendering machine either? Install dependencies and render inside disposable containers, using the same composer/php:8.5-cli images lpod-setup defaults to:

# vendor/ has to exist before "podman:setup" can boot at all
podman run --rm --userns=keep-id -u "$(id -u):$(id -g)" \
    -v "$PWD":/app:Z -w /app docker.io/library/composer:2 \
    install --no-dev --optimize-autoloader --no-interaction

podman run --rm --userns=keep-id -u "$(id -u):$(id -g)" \
    -e PODMAN_WORKING_PATH="$PWD" \
    -v "$PWD":/var/www/html:Z -w /var/www/html docker.io/library/php:8.5-cli \
    php artisan podman:setup --preset=frankenphp-octane

# On the host: install, then set secrets
lpod install frankenphp-octane/pgsql.quadlets --replace
lpod pgsql secrets

Example output for an app named acmepodman/frankenphp-octane/valkey.quadlets:

# FileName=acme-valkey
[Unit]
Description=Valkey container

[Container]
Image=docker.io/valkey/valkey:latest
AutoUpdate=registry
Exec=valkey-server --save --loglevel warning
Volume=acme-valkey:/data:rw,Z,U
Network=acme.network
ExposeHostPort=6379

[Service]
Restart=always
RestartSec=5
TimeoutStartSec=120
TimeoutStopSec=60
---
# FileName=acme-valkey
[Volume]
Label=acme-valkey
VolumeName=systemd-acme-valkey
lpod install frankenphp-octane/valkey.quadlets --replace

A few things worth knowing about this approach:

  • PODMAN_WORKING_PATH/--working-path= only change the host paths baked into the rendered files — rendering itself always happens from /var/www/html here.
  • --userns=keep-id -u "$(id -u):$(id -g)" keeps the generated files owned by you, not root. Keep :Z on SELinux hosts.
  • lpod setup wraps the podman run command above, once lpod (which also ships lpod-setup) is on the host. Add --install to install immediately, or --secrets to also set secrets.
  • Once services are installed, lpod needs nothing else from this project — that's what makes a production install truly standalone. lpod-setup itself still shells out to php artisan podman:setup, which needs this project's vendor/. That's why copying already-rendered output is the normal path for production.

See lpod CLI for the full command reference.