# sprintcube/docker-compose-lamp: a LAMP stack you configure through one .env file

> A Docker Compose LAMP environment for local PHP development, with switchable PHP versions, virtual hosts, Xdebug and Redis. The trade-off is that it is explicitly not built for production.

**sprintcube/docker-compose-lamp** — A basic LAMP stack environment built using Docker Compose.

- Repository: https://github.com/sprintcube/docker-compose-lamp
- Stars: 2,845 · Forks: 1,460
- Language: Dockerfile
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/sprintcube-docker-compose-lamp

## What sprintcube/docker-compose-lamp actually replaces

The project packages the four things a PHP developer usually installs by hand: Apache, MySQL or MariaDB, PHP and phpMyAdmin, plus Redis. The README describes it as "A basic LAMP stack environment built using Docker Compose", and the repository layout backs that up: bin/ holds per-component Dockerfiles, config/ holds php.ini, vhosts, SSL and MySQL configuration, www/ is the document root, and docker-compose.yml wires the services together.

The audience is narrow and stated. The README says the stack "is build for local development and not for production usage". So the problem it solves is not deployment. It is the setup tax of a local PHP environment: matching a PHP version to an application, getting the right extensions compiled, pointing Apache at the right folder, and having a database you can reset without touching your host machine.

What makes it more than a three-line compose file is the version list. The README lists PHP 5.4.x through 8.4.x as available choices. That range matters if you maintain older code, because a stack that only ships PHP 8.x cannot run it.

## How the compose file wires the stack together

The mechanism is environment-variable substitution at compose time. Nothing is configured inside the containers at runtime; the values in .env are interpolated into docker-compose.yml and into build contexts.

The clearest example is the webserver build. The compose file sets context to ./bin/${PHPVERSION}, so the PHP version you write in .env decides which Dockerfile gets built. Change PHPVERSION and you are not reconfiguring a running container, you are building a different image. The container name follows the same pattern: "${COMPOSE_PROJECT_NAME}-${PHPVERSION}".

Volumes are the second half of the mechanism. The document root, php.ini, SSL certificates, virtual host files and Apache logs are all bind mounts with defaults. If you never create a .env, the defaults apply: ${DOCUMENT_ROOT-./www} mounts to /var/www/html, ${VHOSTS_DIR-./config/vhosts} mounts to /etc/apache2/sites-enabled, and ${MYSQL_DATA_DIR-./data/mysql} mounts to /var/lib/mysql. Editing a file under www/ on the host changes what Apache serves, with no rebuild.

The database service is deliberately bound to loopback: the port mapping is "127.0.0.1:${HOST_MACHINE_MYSQL_PORT}:3306". MySQL is reachable from your machine but not from your local network. The README also notes that when an application needs a database host, you pass the value database rather than localhost, because the containers address each other by service name.

## Installing it and serving your first page

The README gives the install as four steps: clone, configure .env, run docker compose up -d, visit localhost. The sample.env file is the template, and the README instructs you to copy it rather than write it from scratch.

```bash
git clone https://github.com/sprintcube/docker-compose-lamp.git
cd docker-compose-lamp/
cp sample.env .env
docker compose up -d
```

After the containers start, http://localhost should serve whatever is in the document root. The README states Apache runs on port 80. phpMyAdmin is on port 8080 with the default credentials root and tiger, which the README lists plainly.

To confirm the stack is alive rather than just running, open the landing page the README points at, http://localhost. That page is what the README's own screenshot shows, and it only renders if Apache is serving from the mounted document root.

When you need a shell inside the web container, the README gives one command for it.

```bash
docker compose exec webserver bash
```

That is the whole first-run loop: no installer, no host packages, no service manager.

## Virtual hosts, SSL and the hosts-file trap

Virtual hosts are enabled by dropping configuration files into config/vhosts, which is mounted at /etc/apache2/sites-enabled. That mount point is the detail worth noticing: files placed there are live Apache site configs, not candidates waiting to be enabled, so a malformed file can take the web server down on restart rather than simply being ignored.

The README adds a warning that is easy to skip and expensive to miss: "Make sure you add an entry to your system's hosts file for each virtual host." The SSL section repeats it in stronger terms. For any non-localhost domain you want HTTPS on, you must point that domain at 127.0.0.1 in your hosts file, or, in the README's words, "SSL will not work and you will be routed to the internet every time you try to visit that domain name". That failure is quiet. You get a working page from a real remote server instead of an error, which makes it look like the stack is fine.

SSL support is described as built-in but disabled by default, with three ways to enable it and https on localhost called the easiest. The compose file mounts ${SSL_DIR-./config/ssl} into /etc/apache2/ssl/, which is where certificates are expected.

Xdebug is the other configuration surface. It ships installed, and the README maps versions: Xdebug 2 for PHP up to 7.3, Xdebug 3 for PHP 7.4 and above. The settings in config/php/php.ini are commented out, so debugging does nothing until you uncomment the block matching your PHP version and restart the container. The README's own tip says you may need to restart after configuring it.

## Where this stack stops being the right tool

The README is direct that this is not a production environment, and the compose file shows why. MySQL is published only on 127.0.0.1, which is exactly right for a laptop and useless for a server that other machines must reach. There is no reverse proxy, no TLS termination beyond the local certificate mount, and no health checking or orchestration layer.

Extensions are the second limit. The default set is listed in the README: mysqli, pdo_sqlite, pdo_mysql, mbstring, zip, intl, mcrypt, curl, json, iconv, xml, xmlrpc and gd, with the caveat that the list may differ for PHP versions below 7.x. If your application needs something outside that set, the README's answer is to edit ./bin/webserver/Dockerfile and rebuild with docker compose build. That is a fork-shaped workflow, not a configuration flag. Every extension you add is a change you carry forward yourself.

Architecture is the third. The README tells Apple Silicon users to select MariaDB as the database because Oracle does not build its SQL containers for arm. That is a real constraint on a common laptop, and it is stated as a note rather than enforced by the compose file, so a wrong choice fails at image pull time.

Finally, the PHP version is not something you can flip on a running stack. Because it selects the build context, switching from 8.3.x to 7.4.x means a rebuild, and the old container's name and image are replaced rather than coexisting. Running two PHP versions side by side is not something this layout offers.

## How it compares with a hand-written compose file

The obvious alternative is writing your own docker-compose.yml with the official php:apache, mysql and phpmyadmin images. The difference is not capability, it is where the decisions live. With official images you choose a tag such as php:8.3-apache and install extensions with docker-php-ext-install in your own Dockerfile. With this project, the tag choice is encoded as PHPVERSION and the extension list is already written for each version under bin/.

That means the two approaches fail differently. A hand-written file gives you exactly the images you asked for and nothing you did not, but you own the extension list, the Apache module list and the php.ini baseline. This project hands you a working baseline, and you pay for it by inheriting its choices: rewrite and headers enabled by default, the extension set above, and a php.ini you are expected to override through the PHP_INI variable rather than edit in place.

There is a middle option worth naming, which is using this repository as a reference rather than a dependency. The bin/ directory is a set of readable Dockerfiles, one per PHP version, and the compose file is short. If you only need Apache, PHP and MySQL, reading those files and writing a smaller compose file of your own is a legitimate outcome, and it costs you the virtual host and SSL wiring that already works here.

What this project does not attempt is the application-level orchestration that tools like DDEV or Lando provide, where the framework and its services are described in one project file. This is a stack, not a project scaffolder.

## Maintenance, licence and the upgrade path

The repository is not archived, and the last push was on 2026-04-03. That is the fact to weigh, not a description of how busy the project is. The README also carries no release history, so there is no changelog to read before upgrading.

The practical upgrade cost sits in two places. First, the Dockerfiles under bin/. Adding an extension or an Apache module means editing one of them and running docker compose build, and the README notes that pull requests for generally useful additions are welcome. Second, the .env file, which is yours. If a future version of the project changes a variable name or a default, your .env is the file that has to be reconciled, and the README's advice to start from sample.env is what keeps that comparison possible.

Data lives in bind mounts, not named volumes: ./data/mysql for the database, ./logs/apache2 and ./logs/mysql for logs. That makes backups a file copy and makes accidental deletion equally easy. It also means the stack survives a docker compose down without losing your database, which is the behaviour most people want locally.

The licence is MIT, which permits commercial and private use, modification and redistribution provided the copyright notice and permission notice are included. That is a permissive licence with few obligations, but it is not legal advice and the LICENSE file in the repository is the authority.

## Conclusion

Adopt it if you want a local PHP environment whose PHP version, document root and database choice live in a single .env file, and if you are comfortable editing Dockerfiles under bin/ when you need another extension. Do not adopt it for production, and do not adopt it if you want a stack that manages its own PHP version matrix for you, because the PHP version is a build-time choice baked into bin/${PHPVERSION}. Before you commit, verify three things: that the PHP version you need exists under bin/, that every virtual host you add has a matching hosts file entry, and that the database image you pick builds on your CPU architecture.

## FAQ

### How can I create a Docker LAMP stack with sprintcube/docker-compose-lamp?

Clone the repository, copy sample.env to .env, adjust the values you need and run docker compose up -d. The README then has you visit http://localhost, with phpMyAdmin on port 8080.

### Is the LAMP stack still relevant if I am using sprintcube/docker-compose-lamp?

The project exists precisely because the LAMP combination is still in use: it ships PHP versions from 5.4.x to 8.4.x, which is only useful if people are running PHP applications. The README frames it as a local development environment rather than a production one.

### Is Docker Compose obsolete for a stack like sprintcube/docker-compose-lamp?

The project's own installation step is docker compose up -d, and its docker-compose.yml uses the version "3" schema with environment-variable substitution throughout. Whatever the wider debate, this stack is built on Compose and has no other documented startup path.

## Sources

- [Issues](https://github.com/sprintcube/docker-compose-lamp/issues)
- [License: MIT](https://github.com/sprintcube/docker-compose-lamp/blob/master/LICENSE)
- [README](https://github.com/sprintcube/docker-compose-lamp/blob/master/README.md)
- [sprintcube/docker-compose-lamp on GitHub](https://github.com/sprintcube/docker-compose-lamp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sprintcube-docker-compose-lamp
