Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Dockerfile Laravel Laravel Package

fly-apps/dockerfile-laravel

Fly.io's Dockerfile for Laravel gives Laravel applications a production-ready container setup with sensible defaults for PHP, Composer, frontend assets, and deployment. Simplify Docker builds, reduce configuration, and ship to Fly.io faster with a reliable, out-of-the-box Dockerfile.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is the Dockerfile generator used for Laravel apps on Fly.io (and usable anywhere). It inspects your application and emits a production-ready Dockerfile (plus supporting config) rather than asking you to hand-write one.

Minimal steps:

  1. Add it as a dev dependency in the Laravel app you intend to containerize:
    composer require --dev fly-apps/dockerfile-laravel
    
    If you arrived via fly launch, this is already wired up — the launcher runs the generator for you.
  2. Read in this order before touching anything: the repo README.md, the generated Dockerfile itself, and .dockerignore. The generated Dockerfile is the real documentation; it tells you the base image, PHP version, web server (nginx + php-fpm), and build stages you're actually getting.
  3. Run the generator from your project root and inspect the diff before committing:
    ./vendor/bin/dockerfile-laravel
    git diff Dockerfile .dockerignore
    
  4. Validate locally before involving Fly at all:
    docker build -t myapp:local .
    docker run --rm -p 8080:8080 --env-file .env myapp:local
    

First use case: take a stock Laravel 11 app, generate the Dockerfile, build it, and confirm you can hit /up (or your health route) on localhost:8080. That single loop — generate, diff, build, curl — is the whole workflow you'll repeat for the life of the project.

Implementation Patterns

Treat the Dockerfile as a generated-but-owned artifact. The healthy pattern is: commit the generated file, and on every package upgrade regenerate into a scratch branch and review the diff. You get upstream improvements without silently inheriting behavior changes.

Pin the version. Since you're on 1.0.9, pin "fly-apps/dockerfile-laravel": "1.0.9" in require-dev. The generator's output is effectively a build contract; unpinned regeneration mid-sprint is a source of surprise.

Layer-cache-friendly regeneration. Generated Dockerfiles do the right thing (copy composer.json/composer.lock first, install, then copy source), but your edits can easily break it. If you add steps, keep dependency manifests ahead of source copies so composer install and npm ci stay cached across code-only changes.

Build assets in a separate stage. The standard shape is: a Node stage running npm ci && npm run build, a Composer stage running composer install --no-dev --optimize-autoloader, and a runtime stage that copies vendor/, public/build/, and the app. Keep it that way — copying node_modules into the final image is the most common way to balloon an image to gigabytes.

CI pattern. Build once in CI and deploy the built image, so the artifact you tested is the artifact that ships:

- run: docker build -t registry.fly.io/myapp:${{ github.sha }} .
- run: docker push registry.fly.io/myapp:${{ github.sha }}
- run: flyctl deploy --image registry.fly.io/myapp:${{ github.sha }}

Customization without forking the output. Two options: (a) edit the generated Dockerfile directly and accept manual reconciliation on upgrades, or (b) keep your additions in a small overlay (an extra COPY/RUN, additional PHP extensions, a custom php.ini) and re-apply after regeneration. For anything more than a couple of lines, track your deltas in a docker/README or a small patch file — future-you will not remember which RUN lines were yours.

PHAR deployments (new in 1.0.9). The added PHAR support targets apps that can be shipped as a single compiled artifact — Laravel Zero/CLI tools, queue workers, scheduled-command runners, and small-footprint services. The pattern is to compile the PHAR in an earlier build stage (Box or Laravel Zero's app:build) and copy only the resulting .phar into a slim runtime image, skipping vendor/ and the app source entirely. This is a genuinely different deployment shape from the standard nginx+fpm image: no docroot, no asset pipeline, just php app.phar. Use it for workers and consoles; keep the conventional image for anything serving HTTP with views and assets unless you're deliberately going all-in on the PHAR route.

Sidecar/worker reuse. The same generated image typically serves web, queue, and scheduler roles. Rather than emitting three Dockerfiles, override the command per process type (php artisan queue:work, php artisan schedule:work) in fly.toml process groups or your orchestrator. One image, three process definitions.

Gotchas and Tips

Regeneration is destructive. The generator writes Dockerfile (and .dockerignore) in place. Always git diff after running it, and never regenerate on a dirty working tree — you will lose hand edits with no undo beyond git.

Never bake secrets in. .env must be in .dockerignore. Config should be cached at build time only when it doesn't read runtime env; php artisan config:cache in the image plus runtime env vars is the classic footgun. Cache config at container start, or ensure cached config doesn't depend on build-time values.

PHP extension parity. The most common "works locally, dies in the container" cause is a missing extension (pdo_pgsql, bcmath, intl, gd). Local PHP and the image's PHP are different builds. When adding an extension, add it in the runtime stage and make sure the corresponding -dev package isn't left installed.

Build args and platform. On Apple Silicon, docker build produces linux/arm64. Fly runs amd64 by default. Build with --platform linux/amd64 (or configure your builder) or you'll get baffling runtime failures on deploy that never reproduce locally.

Permissions and storage/. Running as a non-root user is correct but breaks if storage/ and bootstrap/cache/ aren't writable by that user. Symptom: blank 500s with nothing in storage/logs because the log file itself can't be written.

Debugging the built image. Use docker build --progress=plain . to see full stage output, and docker run --rm -it myapp:local sh to poke around. Logs live where the generated nginx/fpm config puts them (/var/log/nginx/, /var/log/php*, or stderr via supervisord) — check storage/logs/laravel.log only after confirming the app can write to it.

Health checks. The generated fly.toml points at an internal port (typically 8080) and a health path. If you change the web server port or remove the health route, deploys will hang in "unhealthy" and roll back — usually with no useful error. Verify the port matches what the container actually listens on.

PHAR-specific pitfalls (1.0.9). Compiling a PHAR requires phar.readonly=0 at build time only — don't leak that into the runtime php.ini. The PHAR must bundle vendor/ or the artifact won't boot. Watch file paths: code that relies on base_path() resolving to the real source tree can behave differently inside a PHAR, and __DIR__-relative includes to non-bundled files will fail. Also ensure the .phar is executable and that the entrypoint invokes it with the same PHP binary/ini the image ships.

Config quirks worth knowing first. The generator looks at composer.json for the PHP version constraint — an absent or loose constraint gets you a default you may not want. Set "php": "^8.3" explicitly. Similarly, asset build detection depends on package.json scripts; a custom build command (Vite with a nonstandard output dir, or a missing build script) won't be picked up and you'll get an image with no compiled assets and a page of 404s for /build/*.

Extension points. If you need repeatable customization, wrap the generator in a Composer script or a Makefile target that runs it and then applies your overlay, so the sequence is codified rather than remembered.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core