Sign inSign up

rizkybs70/docker-lamp

By rizkybs70

•Updated about 19 hours ago

Lightweight LAMP stack with domain whitelist, multi-arch support, and phpMyAdmin.

Image
0

926

rizkybs70/docker-lamp repository overview

⁠Docker-LAMP

Single-container LAMP stack on Alpine Linux: Apache, PHP, MariaDB and phpMyAdmin in one image, built for small site hosting and homelab use. Multi-architecture (linux/amd64 + linux/arm64), optional domain whitelist, and all Apache/MariaDB output on docker logs.

Two generations are published side by side. Modern PHP 8.4 is the default; the original PHP 7.4 image is kept unchanged for archival and compatibility.

⁠Current release: PHP 8.4

Tags: latest, php8.4

ComponentVersion
Alpine Linux3.24.3
PHP8.4.27
Apache2.4.69
MariaDB11.8.9
phpMyAdmin5.2.3
  • Multi-arch image index: linux/amd64 and linux/arm64 in the same tag.
  • phpMyAdmin dependencies resolved at build time from official sources: 58 packages, identical tree on both architectures.
  • PHP extensions include mysqli, pdo_mysql, pdo_sqlite, gd, intl, mbstring, zip, opcache, apcu, simplexml, xmlreader, xmlwriter, bz2, curl, dom, fileinfo.
  • Hardened PHP runtime settings: display_errors off, expose_php off, errors to stderr, HTTP-only session cookies, 100M upload/post limits, no Xdebug.
  • Container healthcheck on the web server, MariaDB datadir auto-initialization, and in-series datadir auto-upgrade for existing volumes.
  • Signal-safe shutdown: docker stop is handled across the whole lifecycle, including while the datadir is being initialized or upgraded. An intentional stop exits 0.

⁠Legacy release: PHP 7.4 (end of life)

Tag: php7.4-legacy

The image previously published as latest (Alpine 3.14, Apache 2.4, PHP 7.4 with Xdebug, MariaDB 10.6, phpMyAdmin 5.2.0) is preserved unmodified under this tag, byte-identical to the historical release, for archival and compatibility purposes only.

PHP 7.4 is end of life. This image receives no security updates and must not be treated as free of known vulnerabilities. Do not use it as the default and do not deploy it for new work.

⁠Tags

TagReleaseNotes
latestModern PHP 8.4Recommended default
php8.4Modern PHP 8.4Same image index as latest
php7.4-legacyLegacy PHP 7.4Archived original image, EOL

Each tag resolves to a multi-platform index; docker pull picks the right architecture for your host.

⁠Quick start

docker run -d \
  --name docker-lamp \
  -e MYSQL_ROOT_PASSWORD='change-me' \
  -e ALLOWED_DOMAIN='example.com,www.example.com' \
  -p 8080:80 \
  -v /srv/lamp/website:/var/www/localhost/htdocs \
  -v /srv/lamp/mysql:/var/lib/mysql \
  --stop-timeout 60 \
  --restart unless-stopped \
  rizkybs70/docker-lamp:latest
# docker-compose.yml
services:
  lamp:
    image: rizkybs70/docker-lamp:latest
    stop_grace_period: 60s
    ports:
      - "8080:80"
    volumes:
      - /srv/lamp/website:/var/www/localhost/htdocs
      - /srv/lamp/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: "change-me"
      ALLOWED_DOMAIN: "example.com,www.example.com"
    restart: unless-stopped

Then open http://<host>:8080/ for the website and http://<host>:8080/phpmyadmin/ for phpMyAdmin.

To build the image yourself instead:

git clone https://github.com/rizkybs70/docker-lamp.git
cd docker-lamp
docker build -t docker-lamp:php84 .

The build fetches Alpine packages, the phpMyAdmin release archive, Composer and the phpMyAdmin dependency tree from official sources, so it needs internet access and no local vendor folder.

⁠Environment variables

VariableRequiredDescription
MYSQL_ROOT_PASSWORDyesMariaDB root password. Applied when the data directory is initialized for the first time. The container refuses to start when it is missing.
ALLOWED_DOMAINnoComma-separated hostname whitelist. Unset or empty allows every hostname.

MYSQL_RANDOM_ROOT_PASSWORD from the legacy stack is not supported by the PHP 8.4 image; set MYSQL_ROOT_PASSWORD explicitly.

The image ships no credentials and no host-specific configuration: everything comes from the environment or the mounted volumes.

⁠Domain whitelist

ALLOWED_DOMAIN restricts HTTP access to the listed hostnames.

  • Comma-separated list, for example example.com,test.org; surrounding spaces are trimmed.
  • www. variants are accepted automatically: example.com also allows www.example.com.
  • Subdomains are not implied: list them explicitly if you need them.
  • Direct access by IP address and localhost is always allowed, with or without a port.
  • Invalid values (illegal characters, leading/trailing dots) make the container exit with an error instead of silently allowing traffic.
  • Unset or empty means no restriction at all; the container behaves like a plain LAMP stack.
  • Blocked requests receive 403 Forbidden, enforced by an Apache RewriteRule on the Host header.

⁠Data and permissions

Mount both paths, otherwise the data lives in the container writable layer and disappears with the container:

  • /var/www/localhost/htdocs - website files (phpMyAdmin is served from /phpmyadmin/ inside the container).
  • /var/lib/mysql - MariaDB data directory.

The image declares no volumes, so nothing is persisted implicitly. If you hit permission errors, match the ownership to the in-container users:

sudo chown -R 100:101 /srv/lamp/website   # apache, uid 100 / gid 101
sudo chown -R 101:102 /srv/lamp/mysql     # mysql,  uid 101 / gid 102

Both services run unprivileged inside the container (Apache as apache, MariaDB as mysql).

⁠Ports and services

PortPurpose
80/tcpApache, website and /phpmyadmin/
3306/tcpMariaDB, internal only by default

MariaDB also listens on the container socket /run/mysqld/mysqld.sock. Publish 3306 only when an external client really needs direct database access:

mysql -h <host-ip> -P 3306 -u root -p

⁠Logs

Apache access and error logs go to stdout/stderr, so a single command shows everything:

docker logs -f docker-lamp

Example line:

192.168.1.10 - - [03/Mar/2026:12:00:00 +0000] "GET /index.php HTTP/1.1" 200 1234 "-" "Mozilla/5.0 ..."

⁠Healthcheck and shutdown

  • Healthcheck: curl -fsS http://127.0.0.1/ every 30s, 5s timeout, 20s start period, 3 retries.
  • Use --stop-timeout 60 (Compose: stop_grace_period: 60s). This is a safety margin, not a workaround: a steady-state stop finishes in seconds, but a stop that arrives while MariaDB is still initializing or upgrading a volume is allowed to finish, and flushing dirty pages on slow storage can exceed Docker's 10 second default.
  • Apache and MariaDB are stopped in order and no child process is left behind; a deliberate stop exits 0.

⁠Upgrading an existing database

The automatic upgrade step only applies in-place upgrades to a datadir already in the format of the running MariaDB series. Moving a volume from an older stack (for example MariaDB 10.6 to 11.8) is a major-version jump and is not covered by it: stop the old container, back up both the website volume and a consistent database dump, rehearse the migration on a copy, and only then point the new container at the migrated volume.

⁠Architecture support

ArchitectureStatus
linux/amd64Built and runtime-tested natively on x86_64.
linux/arm64Cross-built on x86_64, then runtime-tested natively on aarch64.

A native run proves the image works on the ARM64 hardware used for testing; it does not guarantee every ARM64 device or kernel behaves the same. Older ARM boards and unusual kernels should be tested before being trusted.

⁠Security notes

  • The PHP 8.4 image: vulnerability scanning reported no findings on either architecture at validation time. That is not a guarantee of being vulnerability-free, and no release should be treated as such.
  • The PHP 7.4 image: end of life, archived as-is, no security updates, no vulnerability guarantee. Keeping it available is a preservation decision, not an endorsement.

⁠Credits

Based on j1cs/docker-lamp⁠. This fork adds domain whitelisting, docker logs friendly logging, persistent data mounts, multi-architecture images, and the 2026 security modernization (Alpine 3.24, PHP 8.4, MariaDB 11.8, phpMyAdmin 5.2.3).

⁠License

MIT

Tag summary

Content type

Image

Digest

sha256:59658cbf9…

Size

155.8 MB

Last updated

about 19 hours ago

docker pull rizkybs70/docker-lamp