Self-hosted service
garylab/dnmp avatar
garylab/dnmp

DNMP: a Docker Compose LNMP stack with multi-version PHP

Docker LNMP (Nginx, PHP7/PHP5, MySQL, Redis)

4,089 stars1,409 forksShellMIT

At a glance

What is it?
DNMP packages Nginx or OpenResty, MySQL 5 and 8, PHP 5.4 through 8.0, Redis, MongoDB, Elasticsearch and RabbitMQ into one docker-compose file. It is aimed at PHP developers who want a local or small-server LNMP environment they can edit from the host.
Who is it for?
DNMP fits PHP developers who want a single docker-compose file covering Nginx, several PHP versions, MySQL and optional Redis, MongoDB, Elasticsearch or RabbitMQ, and who are comfortable editing env.sample and docker-compose.sample.yml by hand. It is a poor fit if you expect a control panel, a Kubernetes deployment or an unprivileged container that runs without host bind mounts, since the README's own model is host-mounted source, data, config and logs.
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 21 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

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

Editorial analysis

What DNMP actually bundles, and who it is for

DNMP is a one-command LNMP installer built on Docker Compose. The README describes it as a Docker + Nginx/Openresty + MySQL 5,8 + PHP 5,7,8 + Redis + Elasticsearch + MongoDB + RabbitMQ stack, and lists support for Arm CPUs. The intended user is a PHP developer who wants a working web stack on Windows, Linux or macOS without installing Nginx, PHP-FPM and MySQL directly on the host.

The README's feature list is explicit about the shape of the thing: multiple PHP versions can coexist and be switched, arbitrary numbers of domains can be bound, HTTPS and HTTP/2 are supported, and PHP source, MySQL data, configuration files and log files are all visible and editable from the host. Optional services are enabled by uncommenting blocks rather than by a plugin system, and the project states that all images come from the official Docker Hub repositories.

That last point matters more than it sounds. DNMP is a composition layer, not a distribution of patched binaries. The value is in the sample compose file, the per-service config directories and the build files, not in custom images you would have to trust or rebuild.

How the compose file, env file and services directory fit together

The repository layout tells most of the story. There is a data directory holding Elasticsearch, MongoDB, MySQL 8 and MySQL 5 data, a services directory holding build files and configuration for Elasticsearch, MySQL, MySQL 5, Nginx, PHP, PHP 5.4 and Redis, plus a logs directory and a www directory for PHP code. The two files you copy at setup time are docker-compose.sample.yml and env.sample.

The sample compose file starts three services by default: Nginx, PHP 7 and MySQL 8. Everything else, including Redis, PHP 5.6, PHP 5.4, MongoDB and Elasticsearch, sits behind commented-out blocks that you uncomment to enable. The env file carries the build-time variables, most visibly the PHP extension lists.

Version switching is done through Nginx rather than through a PHP version manager. The README's procedure is to start the other PHP container, then change the fastcgi_pass host in the Nginx configuration from php to php54, where those names match the service names in docker-compose.yml, and reload Nginx. That is a per-site decision made in Nginx config, so two sites can run on two PHP versions at once, but the switch is manual and lives in a file you maintain yourself.

Installing DNMP and serving a first page

The README lists the prerequisites as git, Docker on a 64-bit system (Linux, Windows 10 Build 15063+ or macOS 10.12+) and docker-compose 1.7.0 or later. Clone the repository, then copy the two sample files into place. The README notes that Windows users should use the copy command instead of cp.

bash
git clone https://github.com/yeszao/dnmp.git
cd dnmp
cp env.sample .env
cp docker-compose.sample.yml docker-compose.yml

On Linux, if you are not root, the README also asks you to add your user to the docker group before starting anything.

bash
sudo gpasswd -a ${USER} docker

With the files in place, bring the stack up. The default set is Nginx, PHP 7 and MySQL 8, so this is the shortest path to a running environment.

bash
docker-compose up

After the containers start, the README says to open http://localhost or https://localhost in a browser. The HTTPS route uses a self-signed certificate for demonstration. The PHP code that renders the page lives at ./www/localhost/index.php, which is the file to edit when you want to confirm that changes on the host reach the container.

Adding PHP extensions means rebuilding, or using install-php-extensions

Extensions are the part of DNMP most likely to surprise a new user, because there are two different mechanisms and they behave differently. The build-time route is the env file. The README shows PHP_EXTENSIONS as a comma-separated list and a separate PHP54_EXTENSIONS list for PHP 5.4, with the sample values pdo_mysql, opcache and redis. After editing .env, you rebuild the PHP image.

bash
docker-compose build php

The README states that only a small number of extensions are installed by default beyond PHP's built-ins, and that installing more is a somewhat time-consuming process. The available extension names are documented in the comment block inside env.sample, so that file is the reference rather than the README body.

The second route is the install-php-extensions command inside a running container. The README's example enters the php container and installs apcu.

sh
docker exec -it php /bin/sh
install-php-extensions apcu

That route is faster for experimentation but it is not captured in .env, so it does not survive a rebuild of the container. Treat the env file as the source of truth and install-php-extensions as a way to test whether an extension works before you commit it to the build.

Where DNMP gets awkward

The PHP version list is the clearest limitation. The README's feature list names PHP 5.4, 5.6, 7.0 through 7.4 and 8.0. If your application needs PHP 8.1 or later, the documented set does not cover it, and the supported-extensions table in the README shows columns for PHP versions up to 8.5 that belong to the upstream install-php-extensions project rather than to DNMP's own container definitions. Reading that table as a statement about which PHP versions DNMP ships would be a mistake.

The host-mount design is a trade-off rather than a flaw. Because data, config and logs live in directories on the host, you can inspect them with ordinary tools and edit configuration without rebuilding images. The same design means the stack assumes a reasonably normal filesystem and a user who can write to those directories, which rules out some hardened or ephemeral deployment models. The README devotes a section to safe use in a production environment, which is a signal in itself: the sample configuration is a development starting point, and the project expects you to change things before exposing it.

There is also no rollback story in the README. Nothing documents how to move back to a previous state after a rebuild or a service change, so recovery depends on your own git history and on the data directories you have kept.

DNMP against a hand-written compose file

The realistic alternative is not another branded product but writing your own docker-compose.yml with the official nginx, php-fpm and mysql images. That approach gives you exactly the services you need and nothing else, and it removes a layer of sample configuration you did not write.

The difference in approach is what you get for the extra files. A hand-written compose file has no services directory with prepared configuration for Elasticsearch, MySQL, MongoDB, Nginx, PHP, PHP 5.4 and Redis, no env.sample documenting extension lists, no bash.alias.sample for shortcut commands, and no prearranged directory layout for data and logs. DNMP's own README is candid that the default startup is three services and that the rest are commented blocks you enable yourself, so the comparison is between a curated set of starting points and a blank file. If your stack is one PHP version and one database, the blank file is usually less to maintain. If you regularly need to switch PHP versions per site or want Elasticsearch, MongoDB and RabbitMQ available without writing their compose blocks, DNMP saves that work.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-09, which is recent. The most recent release listed is v3.0.0 from 2025-05-27, preceded by v2.2.0 in October 2024 and v2.10 in March 2023. The gap between the 2025 release and current commit activity suggests the project is maintained through commits rather than through a frequent release cadence, so pinning to a tag is the safer way to reproduce an environment.

The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. Nothing in the README imposes additional terms, but MIT covers the repository's own code; the images pulled from Docker Hub carry their own licences, and MySQL in particular has licensing considerations of its own. That is worth checking against your own distribution plans rather than assuming the MIT file settles it.

Upgrade cost concentrates in two places. Changing a PHP version means editing the compose file, rebuilding the image and repointing fastcgi_pass in Nginx. Changing the extension list means editing .env and running docker-compose build php. Both are manual, and neither is versioned by the project for you, so your own copy of docker-compose.yml and .env is the artifact you maintain.

Editorial conclusion

DNMP fits PHP developers who want a single docker-compose file covering Nginx, several PHP versions, MySQL and optional Redis, MongoDB, Elasticsearch or RabbitMQ, and who are comfortable editing env.sample and docker-compose.sample.yml by hand. It is a poor fit if you expect a control panel, a Kubernetes deployment or an unprivileged container that runs without host bind mounts, since the README's own model is host-mounted source, data, config and logs. Before committing, verify that the PHP version you need is in the supported list, that the extension you need appears in the generated extensions table, and that you have read the section on safe use in production rather than assuming the sample defaults are hardened.

Frequently asked questions

Which PHP versions does DNMP support?

The README's feature list names PHP 5.4, 5.6, 7.0 through 7.4 and 8.0, and states that multiple versions can coexist and be switched. The extension table in the README covers a wider range of PHP versions because it comes from the install-php-extensions project, not from DNMP's own container definitions.

How do I switch the PHP version Nginx uses in DNMP?

Start the other PHP container by uncommenting its block in docker-compose.yml, then change fastcgi_pass in the Nginx configuration from php:9000 to the other service name, for example php54:9000, and reload Nginx. The README notes that php and php54 are the service names defined in docker-compose.yml.

How do I install an extra PHP extension in DNMP?

Add the extension name to the comma-separated PHP_EXTENSIONS list in your .env file and run docker-compose build php. For a quick test you can instead enter the container with docker exec -it php /bin/sh and run install-php-extensions apcu, but that change is not recorded in .env and will not survive a rebuild.

Official sources

  1. garylab/dnmp on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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/garylab-dnmp.svg)](https://hysenlabs.com/projects/garylab-dnmp)