Skip to content

WordPress-NGINX

A production-ready WordPress stack for Kubernetes, built on NGINX and PHP-FPM. Developed by IO ANALYTICA.

Documentation: wordpress-nginx.ioanalytica.com

Components

Deploys WordPress with NGINX on Kubernetes. Supports Memcached, Redis, and Dragonfly for caching, plus an optional wordpress-idx sidecar for full-text search, whose image is built here as well, from the wordpress-idx submodule.

kubectl create secret generic my-wordpress-db --from-file=mariadb-password=./db-password.txt

helm install my-wordpress oci://ghcr.io/ioanalytica/charts/wordpress-nginx \
  --set mariadb.enabled=false \
  --set externalDatabase.host=mydb.example.com \
  --set externalDatabase.existingSecret=my-wordpress-db \
  --set ingress.enabled=true \
  --set ingress.hostname=blog.example.com

This example uses a database server of your own: mariadb.enabled=false switches the bundled MariaDB off, and the externalDatabase.* values are read only then. The database password comes from a Secret with the key mariadb-password, here created from a file that holds nothing but the password, so that it appears neither on the command line nor in the release's values. Without the three database values the chart deploys its own MariaDB next to WordPress.

The chart version is also the image tag. It names the WordPress release the chart ships and the chart's build on it: 7.1.408 is build 8 on WordPress 7.1.4 (see Chart versions).

To see the chart run before you point it at a cluster of your own, follow Try it locally: a throwaway k3d cluster on one machine, with the search sidecar and file-integrity monitoring switched on, in about two minutes.

See chart/README.md for full documentation and values reference.

Custom WordPress image based on shinsenter/php with PHP 8.4 FPM, NGINX, and Alpine Linux. Multi-arch (linux/amd64, linux/arm64).

Registry Image
GitHub Container Registry ghcr.io/ioanalytica/wordpress-nginx

Includes WordPress, NGINX with optimised configuration, PHP extensions (imagick, memcache, redis), WP-CLI, and a health check endpoint at /healthz.php. A PHP execution allowlist restricts PHP execution to known WordPress entry points, so PHP files planted in writable locations such as wp-content/uploads are never executed (see the chart README).

Verify a release

Releases after 7.1.408 sign both images and the chart with Sigstore cosign, keyless: the certificate is issued to this repository's release.yml running for the release tag, and each signature is recorded in the public Rekor log. Every platform of an image also carries an SPDX SBOM and SLSA provenance. Both are attestation manifests listed in the image index, so the index's signature covers them.

A release sets its tags only once the signatures are in place: until then the images and the chart are in the registry under their digests alone, so no tag names an artifact that is not signed yet.

Resolve the tag once and use the digest from then on, so that what you read afterwards belongs to what you verified. The identity names the release's tag, so the check also fails for a tag that was pointed at the image of another release. With cosign 3:

# Signed: ghcr.io/ioanalytica/wordpress-nginx, ghcr.io/ioanalytica/wordpress-idx
# and ghcr.io/ioanalytica/charts/wordpress-nginx
version=<version>
repo=ghcr.io/ioanalytica/wordpress-nginx
digest=$(docker buildx imagetools inspect "$repo:$version" --format '{{json .Manifest}}' | jq -r .digest)
cosign verify "$repo@$digest" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity "https://github.com/ioanalytica/wordpress-nginx/.github/workflows/release.yml@refs/tags/$version"

The version in the identity is the release's, the chart version, also where an image has another tag: latest, or a 1.x.y tag of the sidecar (below). For those, --certificate-identity-regexp with the same address up to @refs/tags/, written as a regular expression, accepts any release of this project, and the output names the release that signed.

The SBOM and the provenance of an image, per platform:

docker buildx imagetools inspect "$repo@$digest" --format '{{json .SBOM}}'
docker buildx imagetools inspect "$repo@$digest" --format '{{json .Provenance}}'

The image of the search sidecar, ghcr.io/ioanalytica/wordpress-idx, is built and signed by the same release, from the wordpress-idx source this repository pins as a submodule, and carries the chart version as its tag. Its labels org.opencontainers.image.version and org.opencontainers.image.revision name the wordpress-idx version and commit it was built from. The first release that builds a new wordpress-idx version also gives its image that version as a tag, which then stays on that build. The tags 1.x.y up to 1.3.7 were published by the wordpress-idx repository before that and are not signed.

Related Projects

  • wordpress-idx — FlexSearch-based full-text search sidecar for WordPress

Contributing

Issues, questions in Discussions and pull requests are welcome; see CONTRIBUTING.md. Report security issues privately, as SECURITY.md describes.

License

Copyright © 2024-2026 IO ANALYTICA.

Licensed under the Apache License, Version 2.0: see LICENSE, and NOTICE for what the license covers.

WordPress itself, which the image contains and the chart deploys, is licensed under the GNU General Public License, version 2 or later.

Releases

Packages

Used by

Contributors

Languages