# LNMP Docker: a one-command PHP stack with MySQL, Redis and Nginx

> LNMP Docker is a Docker Compose bundle that brings up Nginx, PHP, MySQL and Redis for PHP development in one command, with a wrapper script for the common operations, optional extras behind feature flags, and an explicit instruction not to edit any file except .env. It is built for developers who want a working stack without assembling it by hand.

**khs1994-docker/lnmp** — :computer: :whale: :elephant: :dolphin: :penguin: :rocket: Start Docker LNMP(LEMP) In less than 2 minutes Powered by Docker Compose. 让 PHP 开发者快速（一键）搭建基于容器技术（Docker、Kubernetes）的开发、测试、生产（CI/CD by Drone）环境.

- Repository: https://github.com/khs1994-docker/lnmp
- Website: https://docs.lnmp.khs1994.com
- Stars: 668 · Forks: 128
- Language: Dockerfile
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/khs1994-docker-lnmp

## One wrapper command instead of a compose file to read

The pitch is in the README's own line: start LNMP in less than 2 minutes, powered by Docker Compose, with one command, and the command is $ ./lnmp-docker up. That wrapper is the whole design decision. A raw Compose project for a PHP stack needs a dozen files and several environment variables before it serves a page, and the value here is that the wiring is already written and the wrapper hides the compose invocation. The repository layout backs this up. There is an lnmp-docker script at the root with lnmp-docker.ps1 alongside it for PowerShell, plus docker-lnmp.yml as the main compose file and separate override and swarm examples, a config directory for nginx and other service configuration, a dockerfile directory holding the per-service Dockerfiles, and a scripts directory. There is also a bin directory, a log directory, an app directory as the mount point for your project, and a secrets directory. The result is that starting the stack, stopping it, restarting one service, rebuilding an image and listing the containers are all single commands, and the actual compose file is something you read rather than something you write.

## What the stack actually contains

The What's inside table lists the images and their versions, and it doubles as a compatibility map. ACME.sh runs as khs1994/acme:3.1.0 based on alpine:3.20. NGINX is nginx:1.31.6-alpine on alpine:3.22. NGINX Unit is khs1994/php:8.5.11-unit-alpine at version 1.35.0. HTTPD is httpd:2.4.53-alpine on alpine:3.16. MySQL is mysql:8.0.33 on oraclelinux:8-slim, and MariaDB is mariadb:10.11.5 on ubuntu:jammy. Redis is redis:7.0.0-alpine on alpine:3.16, and PHP-FPM comes from the khs1994/php image family. The defaults are set in the .env example, where LNMP_SERVICES is set to "nginx mysql php8 redis" and the available extras are listed in the commented block below it: workspace, vscode-remote-container-workspace, php7, mariadb, memcached, rabbitmq, phpmyadmin, postgresql, mongodb, httpd, registry, minio, minio-old, supervisord, nginx-unit, kong, postgresql-kong and konga. Each of those is a service you opt into by naming it, not by writing compose yourself.

## The .env file is the only thing you should edit

The README carries a warning that decides how you work with this project: do not edit any files except .env. The .env.example file explains the shape of that configuration and the loading order, with .env.example first, then .env, then .env.${LNMP_ENV}, with the priority running from last to first, and LNMP_ENV selecting the last of those. The global switches at the top are LNMP_CN_ENV, which defaults to true and should be set to false in a non-China environment such as GitHub Actions, and COMPOSE_PROJECT_NAME, which is set to lnmp and exists so you can run several LNMP instances on one host without port conflicts. The service list is LNMP_SERVICES="nginx mysql php8 redis", and APP_ROOT points at ./app by default, with a comment showing how to set it to a WSL2 path such as \\wsl$\debian\app when the project lives inside WSL. The reason for the edit restriction is that the compose file and the scripts are regenerated as the project evolves, so a local edit is a change that a later pull will silently overwrite. A separate section in the .env example handles the image mirror problem: because Docker image addresses are slow to reach from China, LNMP_DOCKER_IMAGE_PREFIX and LNMP_LIBRARY_NS can be pointed at a mirror.

## Cloning, starting and the first curl

The prerequisites are Git, Docker, Docker Compose v2.17.0 or later, and WSL on Windows only. The install is a shallow clone, and the README gives a second option from a Gitee mirror for the same reason as the image mirror:

```bash
$ git clone --depth=1 https://github.com/khs1994-docker/lnmp.git

# $ git clone --depth=1 git@github.com:khs1994-docker/lnmp.git

# 中国镜像

$ git clone --depth=1 https://gitee.com/khs1994-docker/lnmp.git

# $ git clone --depth=1 git@gitee.com:khs1994-docker/lnmp.git
```

Starting the demo is two commands and a check:

```bash
$ cd lnmp

$ ./lnmp-docker up

$ curl 127.0.0.1

Welcome use khs1994-docker/lnmp v25.11 x86_64 With Pull Docker Image

development

```

The MySQL default root password is mytest, which is worth knowing before you connect to anything. To start your own project you create a folder under ./app/, for example a Laravel application, edit the nginx config file in ./config/nginx/yourfilename.conf, and then run the restart command for nginx:

```bash
# $ ./lnmp-docker new

$ ./lnmp-docker restart nginx
```

The commented new command is the scaffold helper, and APP_ROOT is the setting that changes where your PHP project folder is looked up.

## Service names change inside the network, not on the host

One detail trips up every new user, and the README shows it as a diff because the change is the whole point. Inside the compose network, a service is addressed by its service name, not by localhost, so the Redis client changes from connecting to 127.0.0.1 on port 6379 to connecting to redis on port 6379, and the PDO DSN changes its host from 127.0.0.1 to mysql, with the separator changing from a semicolon to a comma in the DSN:

```diff
$redis = new \Redis();

- $redis->connect('127.0.0.1',6379);
+ $redis->connect('redis', 6379);

- $pdo = new \PDO('mysql:host=127.0.0.1;dbname=test;port=3306','root','mytest');
+ $pdo = new \PDO('mysql:host=mysql,dbname=test,port=3306', 'root', 'mytest');
```

The host port mapping still means the service is reachable on 127.0.0.1 from the host machine, so the rule is that code running inside a container uses the service name and code running on the host uses the published port. The README also lists the PHPer commands the wrapper provides, with lnmp-php, lnmp-composer, lnmp-phpunit and lnmp-laravel among them, so the common tools run inside the right container without you working out which image has them.

## The operations the wrapper covers

The commands the wrapper exposes cover the daily loop, and reading them tells you what the project considers its job. Restarting everything is ./lnmp-docker restart, and restarting one service is ./lnmp-docker restart nginx php8, so you can target a subset. Stopping is ./lnmp-docker stop, and stopping and removing is ./lnmp-docker down. Listing the containers uses a label filter rather than naming them:

```bash
$ docker container ls -a -f label=com.khs1994.lnmp
```

Building your own images is done by editing the Dockerfile in ./dockerfile/*/Dockerfile and then running ./lnmp-docker build, which is the documented escape hatch for the no-editing rule since the Dockerfiles are the exception the project itself points you to. SSL certificates are issued through the bundled acme.sh, and the command takes a domain and a wildcard:

```bash
$ ./lnmp-docker ssl khs1994.com -d *.khs1994.com
```

The API key and id go in the .env file or the system environment, and self-signed certificates are supported. The other repository directories map onto the wider ambition of the project: a drone directory for CI, a kubernetes directory with a separate lnmp-k8s project for the Kubernetes version, and wsl and wsl2 directories for the Windows setup, with a windows directory and a .devcontainer for the VS Code remote container flow.

## Where this stack stops being the right answer

Three limits are worth naming. The first is scope. This is a development and test environment, not a production deployment, and the README's own description says the goal is for PHP developers to quickly set up development, test and production CI/CD environments based on container technology, with the CI/CD part handled by Drone in the drone directory and the Kubernetes part by the separate lnmp-k8s project. A production deployment on this compose file is not what the maintainer built it for. The second is the platform matrix. It is supported on Linux, macOS, Windows 10 on x86_64, and Debian on Raspberry Pi 3 on arm, and the README warns that running Laravel on Docker for Windows is very slow with a pointer to a solution document, and the CI table shows separate AppVeyor, Linux and macOS pipelines plus a Linux arm64v8 build. Windows users are therefore on the slow path by the project's own admission. The third is the coupling to the compose file. Because the instruction is to edit only .env, anything your team needs that is not an option in LNMP_SERVICES, not a documented image and not a volume, means working around the project rather than with it. The genuinely open-ended option, the custom script examples for lnmp-docker, exist for exactly that reason.

## Conclusion

LNMP Docker suits a PHP developer on Linux, macOS or Windows with WSL who wants a working Nginx, PHP, MySQL and Redis stack immediately and expects to change nothing but the .env file, since the README's standing instruction is not to edit any other file. It is the wrong tool for a production deployment, because the project is explicitly a development, test and CI environment and the same README points at separate Kubernetes and CI work, and it is the wrong tool if you need a service set outside the ones listed, since the extras are selected by name from a fixed list in LNMP_SERVICES. Verify first which services you need and whether they appear in that list, set LNMP_CN_ENV to false when you are not on a China-region network, and note that the newest tagged release is v24.11.0 from 2025-08-24 while the default branch is 25.11 and the last push was on 2026-10-13.

## FAQ

### How do I start the LNMP Docker stack?

Clone the repository with git clone --depth=1, cd into the lnmp directory and run ./lnmp-docker up. The README's demo check is curl 127.0.0.1, which prints a welcome line naming the version and the development environment.

### Which files am I allowed to change?

The README warns not to edit any files except .env, and points to an issue explaining why. The documented exception is the Dockerfile in ./dockerfile/*/Dockerfile, which you edit and then build with ./lnmp-docker build.

### How do I add a service such as PostgreSQL or phpMyAdmin?

You add its name to the LNMP_SERVICES list in the .env file. The .env.example lists the available extras, which include mariadb, memcached, rabbitmq, phpmyadmin, postgresql, mongodb, httpd, registry, minio, supervisord, nginx-unit and kong.

### Why does my code fail to connect to MySQL or Redis from inside a container?

Inside the compose network a service is reached by its service name rather than 127.0.0.1. The README shows the change, connecting to redis on port 6379 and to mysql in the PDO DSN instead of 127.0.0.1.

### What are the requirements for running LNMP Docker?

Git, Docker, Docker Compose v2.17.0 or later, and WSL on Windows only. The project is supported on Linux, macOS, Windows 10 on x86_64, and Debian on Raspberry Pi 3 on arm.

## Sources

- [khs1994-docker/lnmp on GitHub](https://github.com/khs1994-docker/lnmp)
- [License: Apache-2.0](https://github.com/khs1994-docker/lnmp/blob/25.11/LICENSE)
- [Project website](https://docs.lnmp.khs1994.com)
- [README](https://github.com/khs1994-docker/lnmp/blob/25.11/README.md)
- [Releases](https://github.com/khs1994-docker/lnmp/releases)

---

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