# Strapi Dockerfile Generator

URL: /dockerizer/strapi

Generate a production Dockerfile for Strapi 5 — the admin panel is compiled during the build and dev dependencies are pruned before the runtime image copies the app.

## Default configuration

- `appName` (App name): strapi — Used for the image tag, the compose service and the OCI labels.

- `port` (Port): 1337 — The port the app listens on inside the container. Keep it above 1024 so the process can bind it without root.

- `nodeVersion` (Node version): 24 — Node 24 is the active LTS line. Node 20 goes end-of-life in April 2026.

- `packageManager` (Package manager): npm — pnpm and Yarn are installed through Corepack, which reads the `packageManager` field in your package.json.

- `baseVariant` (Base image): slim — Alpine is the smallest. Debian slim is safest if you compile native modules such as sharp, canvas or bcrypt.

- `database` (Database service): none — Adds the database to docker-compose.yml with a healthcheck, a named volume and a DATABASE_URL wired into the app.

- `redis` (Redis service): false — Adds Redis to docker-compose.yml and exposes REDIS_URL to the app.

- `cacheMounts` (BuildKit cache mounts): true — Persists the package manager store between builds. Repeat builds skip the download entirely.

- `multiArch` (Multi-architecture build): false — Adds BUILDPLATFORM/TARGETARCH so `docker buildx build --platform linux/amd64,linux/arm64` cross-compiles natively.

- `healthcheck` (Healthcheck): true — Adds a HEALTHCHECK so orchestrators can restart an unresponsive container.

- `tini` (tini init): false — Runs the app under tini so signals and zombie processes are handled properly.

- `ociLabels` (OCI labels): false — Adds org.opencontainers.image.* metadata to the final image.

- `buildSecret` (Build secret mount): false — Reads a private registry token via --mount=type=secret so it never lands in an image layer.

## Generated files

### Dockerfile

Multi-stage build: dependencies, compilation and the runtime image are separate, so only what the app needs at runtime ships.

```docker
# syntax=docker/dockerfile:1
# Generated by Easypanel Dockerizer — https://easypanel.io/dockerizer

# --- Base ---------------------------------------------
FROM node:24-slim AS base
WORKDIR /app

# --- Dependencies -------------------------------------
FROM base AS deps
RUN apt-get update \
 && apt-get install -y --no-install-recommends python3 build-essential libvips-dev pkg-config \
 && rm -rf /var/lib/apt/lists/*

# Manifests first: source changes must not bust the dependency cache
COPY package.json package-lock.json* ./
RUN --mount=type=cache,id=npm-store,target=/root/.npm,sharing=locked \
    npm ci --include=dev

# --- Build --------------------------------------------
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NODE_ENV=production
RUN npm run build
RUN npm prune --omit=dev

# --- Runtime ------------------------------------------
FROM node:24-slim AS runtime
WORKDIR /app
RUN apt-get update \
 && apt-get install -y --no-install-recommends libvips42 \
 && rm -rf /var/lib/apt/lists/*
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=1337
COPY --from=build --chown=node:node /app/. ./
USER node
EXPOSE 1337
STOPSIGNAL SIGTERM

# Lets Docker, Compose and Easypanel see when the app is wedged
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD ["node", "-e", "fetch('http://127.0.0.1:1337/_health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
CMD ["node", "node_modules/@strapi/strapi/bin/strapi.js", "start"]

```

### .dockerignore

Keeps the build context small and stops secrets and local dependencies from reaching an image layer.

```bash
# Version control
.git
.gitignore
.github

# Secrets — never bake these into an image layer
.env
.env.*
!.env.example
*.pem
*.key

# Editor and OS noise
.vscode
.idea
.DS_Store
Thumbs.db

# Docs and local tooling
README.md
LICENSE
docs
.editorconfig
docker-compose*.yml
Dockerfile*
.dockerignore

# Dependencies — reinstalled inside the image from the lockfile
node_modules
**/node_modules
.pnpm-store
.yarn/cache
.yarn/unplugged
npm-debug.log*
yarn-error.log*
pnpm-debug.log*

# Test and coverage output
coverage
.nyc_output
**/*.test.ts
**/*.spec.ts

```

### docker-compose.yml

Runs the image locally with its backing services, wired together and health-gated.

```yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "1337:1337"
    environment:
      NODE_ENV: production
      HOST: 0.0.0.0
      PORT: 1337

```

## Frequently asked questions

### Why does the build need libvips and a compiler?

Strapi's media library depends on sharp, which binds to libvips. On Debian slim the prebuilt binary works once libvips is present; on Alpine it usually has to compile, which is why slim is the default here.

### Which database should I use?

Anything other than the SQLite default in production — SQLite lives inside the container and is lost on redeploy. Pick PostgreSQL in the database field above and the compose file wires it up for you.

### Do I need to run the admin build separately?

No. `strapi build` compiles the admin panel during the image build, so the container starts serving immediately instead of building on first boot.

## Related generators

- [Payload CMS](/dockerizer/payload)

- [Directus](/dockerizer/directus)

- [Node.js](/dockerizer/nodejs)

- [Medusa](/dockerizer/medusa)