phpMyAdmin as a php-fpm image plus the nginx in front of it, rebuilt daily so the base underneath the application stays current.
The upstream phpmyadmin/phpmyadmin image is rebuilt when phpMyAdmin itself is
released, not when its base picks up fixes. Measured on 2026-08-08, with
trivy against the published images:
| image | size | findings | with a fix | CRITICAL+HIGH with a fix |
|---|---|---|---|---|
phpmyadmin/phpmyadmin:5.2.3 (built 2025-10-08) |
708 MB | 4623 | 3396 | 562 |
phpmyadmin-php-fpm (pinned) |
157 MB | 18 | 18 | 10 |
phpmyadmin-php-fpm (rolling) |
157 MB | 0 | 0 | 0 |
The application code is the same in all three. What differs is the age of the
Debian base — and, for the rolling variant, of phpMyAdmin's own bundled PHP
libraries. :latest upstream is byte-identical to :5.2.3, so waiting for an
upstream rebuild is not a plan.
Pinned (default) ships the libraries exactly as the phpMyAdmin release did. Reproducible, and identical to upstream in everything but the base image.
Rolling (ROLLING_DEPS=true) refreshes those libraries within the
constraints phpMyAdmin's own composer.json declares — twig/twig moves from
the released 3.11.3 to 3.28.0, for instance. That is where the last 18 findings
go. It is a deliberate deviation from the released tarball, so it is opt-in.
cp .env.example .env # set MARIADB_ROOT_PASSWORD for the demo database
make up # app + web + a MariaDB to look atphpMyAdmin then answers on http://localhost:8080.
Against a database you already run, leave the demo out and point at it:
PMA_HOST=your-db-host docker compose up -d app-assets app web| Image | What it is |
|---|---|
ghcr.io/netresearch/phpmyadmin-php-fpm |
php-fpm on 9000, serves no HTTP |
ghcr.io/netresearch/phpmyadmin-nginx |
nginx on 8080 with the configuration and the document root baked in, running as an unprivileged user |
Deploy both at the same tag. They share the document root, which is copied from one build stage into both, so mixing tags means running two phpMyAdmin versions against each other. Both are built in the same workflow run and carry the same tag set for that reason.
Two containers, no mounted files:
services:
pma-fpm:
image: ghcr.io/netresearch/phpmyadmin-php-fpm:latest
environment:
PMA_HOST: db
pma:
image: ghcr.io/netresearch/phpmyadmin-nginx:latest
environment:
PMA_FPM_UPSTREAM: pma-fpm:9000
ports:
- "8080:8080"Anyone who already runs a web server can take the php-fpm image alone. It
listens on 9000, and the web server needs the application tree to serve static
files, which the app-assets service copies into a shared volume on every
start. See
docs/using-the-image-standalone.md.
Everything is environment-driven and the variable names match the upstream
image, so an existing deployment can switch without rewriting its environment.
.env.example documents each one. Two are worth calling out:
PMA_BLOWFISH_SECRET— exactly 32 characters, encrypts the auth cookie. Without it the container generates one into itstmpvolume and warns; lose that volume and everyone is logged out.PMA_ABSOLUTE_URI— needed when phpMyAdmin is served under a path or a public hostname the container itself never sees.
A config.inc.php you mount yourself is left alone; one this image generated
is rewritten on each start, so a changed environment takes effect.
setup/, examples/ and test/ are removed. The setup wizard writes
configuration through the browser, which in a container is both pointless — the
configuration comes from the environment — and a way in.
/ping and /status are php-fpm's own endpoints. The shipped nginx config
answers them on loopback only: in Docker every request through a published port
arrives from the bridge gateway, so allowing "the private ranges" would publish
them to anyone who can reach the port.
make lint runs hadolint and a compose validation, make test builds and runs
the container-structure tests, make scan runs trivy against the built image.
The daily CI rebuild is what keeps the promise in the table above true;
Renovate bumps the base versions and the release pin.
MIT for everything in this repository (see LICENSE-MIT), documentation under
CC-BY-SA-4.0. phpMyAdmin itself is GPL-2.0-only and is downloaded at build
time, not vendored here.