Strapi 5 CMS image for the SelfRail app catalogue. Multi-arch, no baked secrets.
110
Strapi publishes no official container image — their own documentation says so — so the catalogue entry cannot pin a vendor image the way Ghost or Directus do. This Dockerfile is ours: built from Strapi's documented production example, pinned to a released version, and auditable in-tree.
Strapi is a framework, not a stock service: a Strapi install is a generated project.
Their Dockerfile assumes you already have one. The build therefore runs
create-strapi-app and compiles the admin bundle, so the image contains a real,
buildable Strapi rather than an empty directory.
Database connection details come from the environment at runtime; the scaffold only
fixes which driver is installed (--dbclient postgres puts pg in the dependency tree).
.envcreate-strapi-app generates a .env at scaffold time containing secrets it invented on
the spot — APP_KEYS, ADMIN_JWT_SECRET, JWT_SECRET and the three salts. Those are
baked at build time, so every pull of a published image would carry the same ones, and
dotenv would quietly fall back to them whenever a deployment forgot to inject its own.
A shared ADMIN_JWT_SECRET in a public image means anyone can forge an admin session.
The build therefore deletes that file. config/server.js reads env.array('APP_KEYS')
with no default, so a container started without secrets fails to boot instead of coming
up on public keys. SelfRail generates all seven per install — see configFields and
secretEnv in packages/core/src/apps/catalog/strapi.json.
Running it outside SelfRail means supplying them yourself:
docker run --rm -p 1337:1337 \
-e APP_KEYS="$(openssl rand -base64 32),$(openssl rand -base64 32)" \
-e API_TOKEN_SALT="$(openssl rand -base64 32)" \
-e ADMIN_JWT_SECRET="$(openssl rand -base64 32)" \
-e TRANSFER_TOKEN_SALT="$(openssl rand -base64 32)" \
-e JWT_SECRET="$(openssl rand -base64 32)" \
-e ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-e DATABASE_CLIENT=postgres -e DATABASE_HOST=... \
selfrail/strapi:5.52.3
HOST and PORT are the exceptions — those do have defaults (0.0.0.0, 1337).
docker build -t selfrail/strapi:5.52.3 -t selfrail/strapi:5 \
--build-arg STRAPI_VERSION=5.52.3 docker/apps/strapi
Bumping Strapi is a one-line change to STRAPI_VERSION, a rebuild, and a matching
image bump in packages/core/src/apps/catalog/strapi.json.
node_modules, which is what Strapi's own example does. Selective copies of
dist/build/, config/, public/ and src/ plus a production-only install would
cut this substantially; correctness first, size second.NODE_ENV=production, and
Strapi disables the builder there by design — content types are code. Model them in a
project and deploy it from Git rather than editing a running server.Content type
Image
Digest
sha256:93b865079…
Size
383.6 MB
Last updated
about 2 months ago
docker pull selfrail/strapi:5