Self-hosted service
ucan-lab/docker-laravel avatar
ucan-lab/docker-laravel

docker-laravel gives you a Laravel environment without installing PHP

🐳 Build a simple laravel development environment with Docker Compose.

1,199 stars364 forksMakefileMIT

At a glance

What is it?
docker-laravel is a Docker Compose setup for Laravel development, with an app container running PHP and Composer, an nginx container in front of it, a MySQL database and a Mailpit mail catcher, and the source tree bind mounted so edits are picked up immediately. It is driven by a Taskfile or a Makefile, it supports Windows through WSL2 and macOS on both Intel and Apple Silicon, and it documents one failure mode in unusual detail.
Who is it for?
docker-laravel is worth using if you want a Laravel environment that is identical on every machine and you would rather not install PHP, Composer and MySQL versions by hand, because the compose file and the two task runners remove the setup decisions rather than adding to them.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Makefile, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The same environment on every machine

The project builds a simple Laravel development environment with Docker Compose, and it supports Windows through WSL2, macOS on both Intel and Apple Silicon, and Linux. The point of a Compose setup for a framework like Laravel is that the version matrix stops being your problem, since the PHP runtime, the web server, the database and the mail catcher are pinned in the compose file and the Dockerfiles rather than resolved on each developer's laptop. The repository is small for what it does, with a compose.yaml, a compose-for-linux.yaml, an infra/ directory holding the Dockerfiles, a Makefile, a Taskfile.yml and a wiki. The repository description states it plainly: it builds a simple Laravel development environment with Docker Compose.

The BuildKit trap, where the build succeeds and composer fails

The Requirements section contains the most valuable paragraph in the README, and it is about a silent failure. The requirement is Docker Engine v23.0 or newer with BuildKit enabled by default, or the latest Docker Desktop. The Dockerfile uses here-documents in the form RUN <<EOF, which require BuildKit, and when BuildKit is disabled the RUN instructions are silently skipped, so required packages such as git are never installed. The build still succeeds, and then composer install later fails with git was not found in your PATH. That is a bad failure mode, because the error points at Composer rather than at the build, and the symptom appears long after the cause. The fix is to enable it explicitly, and the two variables are:

bash
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1

BuildKit is on by default on Docker Engine v23.0 and later and on Docker Desktop, so this only bites people on an older engine, which is exactly the audience that will not expect it.

Two entry points, for a new project or an existing one

There are two workflows, and the difference is one command. For a new project you start from the template, clone it, and run the create-project task or make target, which creates the source directory, builds the images, brings them up and runs composer create-project --prefer-dist laravel/laravel . inside the app container, then copies the environment file, points the database connection at MySQL, generates the application key, links storage and relaxes the permissions on storage and bootstrap/cache. For an existing project the same sequence runs composer install instead of create-project. The manual Linux variant of the same steps is written out in the README, and the difference is that on Linux the UID, GID and USERNAME are written into the environment file first, so the files created inside the container belong to the user on the host rather than to root. The end result is the same in both cases, an application reachable at http://localhost.

Four containers, and what each one is for

The container structure is three in the diagram and four in the compose file, and the fourth is the one that saves the most time. The app container is built on the php 8.4-fpm-bullseye image with composer 2.10 alongside it, and it is where your code runs and where the artisan commands are executed. The web container is nginx 1.31, and it is the only one with a published HTTP port in the diagram, port 80. The db container is mysql 9.7, with a named volume db-store mounted at the data directory using the nocopy option so an empty volume is not pre-populated from the image. The fourth is mailpit, which catches every outbound email from the application and shows it in a web interface on port 8025, so a registration flow or a password reset can be tested without sending real mail. The app, web and db services each build from a Dockerfile under infra/docker, mailpit runs the axllent/mailpit image directly, and the app service has a build target that defaults to development.

The source is bind mounted, and the environment is overridable

Two things in the compose file shape how the environment behaves. First, both the app and the web services bind mount the ./src directory to /workspace, so a file you edit on the host is the file the container serves, with no rebuild and no volume juggling. The database is different, because the MySQL data directory is a named volume rather than a bind mount, and it is mounted with the nocopy option. Second, the environment is written so it can be overridden. The app service sets DB_CONNECTION with a default of mysql, DB_HOST with a default of db, DB_PORT with a default of 3306, and the database name, user and password with defaults of laravel, phper and secret. The web, database and Mailpit ports are likewise configurable through WEB_PUBLISHED_PORT, DB_PUBLISHED_PORT and MAILPIT_PUBLISHED_PORT, all defaulting to 80, 3306 and 8025, and the service ports are published in host mode. There is also a comment that matters more than it looks, that the DB_CONNECTION variable should be removed after the Laravel project is created and written into the project's own .env instead.

Task and Make drive the same thing

The repository ships two task runners over the same commands, and the README points at both, the Taskfile, the Makefile and the wiki. The Makefile shows the shape of the workflow, with a build target that runs docker compose build, an up target that starts the stack detached, an install target that chains them and then runs the Composer and artisan steps, and a create-project target that does the same with create-project instead of install. Around those are the commands you will actually use, stop, down, down-v which also removes the volumes, restart, destroy which removes the images and volumes, remake which destroys and reinstalls, ps, and shells into the web or app container, plus tinker for the artisan console, dump for dump-server, test, migrate, fresh for migrate:fresh with the seed, and seed. The two runners exist for convenience rather than necessity, since the underlying commands are docker compose exec app php artisan something, and the Makefile is the more portable of the two on a machine that does not have the Go task runner installed.

Where this is the wrong tool

Three limits, and they are the usual ones for a development Compose stack. The first is that it is a development environment and it says so, with a bind mount, a database password of secret, and a chmod of 777 over storage and bootstrap/cache, which is fine for a laptop and wrong for anything else. The second is the shape of the stack, which is a single application with one web container, one app container, one database and one mail catcher, and there is no reverse proxy with TLS, no queue worker, no scheduler and no second app instance, so anything that needs those is a different project. The third is the hidden trap of the compose file, that the database variables are passed into the app container from the host environment, which means a developer with a DB_CONNECTION set in their own shell changes the behaviour of the container without touching the repository, which is the kind of thing that produces a support question about why the app cannot find the database. The project is also a template in the GitHub sense, with the Use this template link in the usage steps, so the intended workflow is to fork it and edit it, and the wiki is where the changes go.

Editorial conclusion

docker-laravel is worth using if you want a Laravel environment that is identical on every machine and you would rather not install PHP, Composer and MySQL versions by hand, because the compose file and the two task runners remove the setup decisions rather than adding to them. It is the wrong tool if you want a production-like stack, since the compose file is a development shape with a bind mount, permissive permissions and default credentials, and the wrong tool if you need more than one application. Before you use it, read the BuildKit note, because on an older Docker the image builds without git installed and the failure appears later as composer install reporting that git was not found in your PATH, which is a confusing way to learn that the build was silently incomplete.

Frequently asked questions

How do I create a new Laravel project with docker-laravel?

Click Use this template, clone the repository, and run task create-project or make create-project. On Linux you first write UID, GID and USERNAME into the .env file so files created in the container belong to you on the host, and then the target builds the images, starts the stack and runs composer create-project --prefer-dist laravel/laravel inside the app container. The application is then reachable at http://localhost.

Why does composer install fail with git was not found in your PATH?

Because the Dockerfile uses here-documents in the form RUN <<EOF, which require BuildKit. With BuildKit disabled those RUN instructions are silently skipped, so packages such as git are never installed even though the build succeeds. Enable it with export DOCKER_BUILDKIT=1 and export COMPOSE_DOCKER_CLI_BUILD=1, or use Docker Engine v23.0 or newer where it is on by default.

Which containers does the docker-laravel setup run?

An app container on the php 8.4-fpm-bullseye image with composer 2.10, a web container on nginx 1.31 publishing port 80, a db container on mysql 9.7 with a named volume mounted with the nocopy option, and a mailpit container that catches outbound mail and shows it on port 8025. The source directory is bind mounted to /workspace in both the app and web services.

Which platforms does docker-laravel support?

Windows through WSL2, macOS on both Intel and Apple Silicon, and Linux, with a separate compose-for-linux.yaml file and the for-linux-env target that writes UID, GID and USERNAME into the .env file for correct file ownership inside the containers. The project is MIT licensed and version 2.8.1 was published on 2026-06-27.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. ucan-lab/docker-laravel on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ucan-lab-docker-laravel.svg)](https://hysenlabs.com/projects/ucan-lab-docker-laravel)

Was this useful?