Skip to main content

在 Docker 容器中运行 Strapi

🌐 Running Strapi in a Docker container

Page summary:

本页面将指导你在开发和生产环境中使用 Docker 容器运行 Strapi,包括 Dockerfile 示例、Docker Compose 配置以及常见问题的排查方法。

Caution

Strapi 不会构建任何官方容器镜像。以下说明是作为对社区的友好提供。如果你有任何问题,请在 Discord联系我们。

将 Strapi 容器化可以使运行时环境在不同机器之间可重现,并简化部署的依赖管理。本页面介绍为现有 Strapi 5 项目构建自定义 Docker 镜像的内容,分别提供 开发生产 环境的说明,包含一个 故障排除 部分,以及一个 社区工具 列表。如果你不想自己编写 Dockerfile,请参见 社区工具和镜像 获取打包好的替代方案。

🌐 Containerizing Strapi makes the runtime environment reproducible across machines and simplifies dependency management for deployment. This page covers building custom Docker images for an existing Strapi 5 project, with separate instructions for development and production environments, a troubleshooting section, and a list of community tools. If you would rather not write your own Dockerfile, see Community tools and images for packaged alternatives.

Prerequisites

开发环境

🌐 Development environment

开发镜像使用 npm run develop 并挂载你的本地源代码以实现热重载。在创建 Dockerfile 之前,先设置两个必需的文件:.dockerignore.env

🌐 Development images use npm run develop and mount your local source code for hot-reload. Before creating the Dockerfile, set up 2 required files: .dockerignore and .env.

创建一个 .dockerignore 文件

🌐 Create a .dockerignore file

一个 .dockerignore 文件可以防止本地文件被复制到 Docker 镜像中。没有它,你的本地 node_modules 目录会被包括在构建上下文中,这会导致架构不匹配(例如,在 ARM 上运行 x64 二进制文件)并增加镜像大小。

🌐 A .dockerignore file prevents local files from being copied into the Docker image. Without it, your local node_modules directory gets included in the build context, which causes architecture mismatches (e.g., x64 binaries on ARM) and increases the image size.

在你的 Strapi 项目的根目录下创建一个 .dockerignore 文件:

🌐 Create a .dockerignore file at the root of your Strapi project:

./.dockerignore
node_modules/
.tmp/
.cache/
.git/
build/
.env

创建 Dockerfile

🌐 Create the Dockerfile

以下 Dockerfile 可用于为 Strapi 项目构建非生产 Docker 镜像。

🌐 The following Dockerfile can be used to build a non-production Docker image for a Strapi project.

./Dockerfile
FROM node:22-alpine
# Installing libvips-dev for sharp compatibility
RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev bash vips-dev git
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}

WORKDIR /opt/
COPY package.json package-lock.json ./
RUN npm install -g node-gyp
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm ci
ENV PATH=/opt/node_modules/.bin:$PATH

WORKDIR /opt/app
COPY . .
RUN chown -R node:node /opt/app
USER node
EXPOSE 1337
CMD ["npm", "run", "develop"]
Optional: pre-build the admin panel

你可以在 EXPOSE 行之前添加 RUN ["npm", "run", "build"] 来预构建管理面板,从而加快首次启动速度。这不是必须的,因为 npm run develop 会在观察模式下重建它。

🌐 You can add RUN ["npm", "run", "build"] before the EXPOSE line to pre-build the admin panel and speed up the first start. This is not required since npm run develop rebuilds it in watch mode.

Optional: reduce image size with virtual packages

对于像这种开发镜像的单阶段 Dockerfile,你可以在 npm ci 之后使用 --virtual 标志来清理构建依赖,从而生成更精简的镜像:

🌐 For single-stage Dockerfiles like this dev image, you can use the --virtual flag to clean up build dependencies after npm ci, producing a leaner image:

RUN apk add --no-cache --virtual .build-deps \
build-base gcc autoconf automake zlib-dev libpng-dev bash vips-dev git \
&& npm ci \
&& apk del .build-deps

在生产环境的 Dockerfile 中不需要这样做,因为它已经通过多阶段构建丢弃了构建依赖。

🌐 This is not needed in the production Dockerfile, which already discards build dependencies through its multi-stage build.

Alternative base image for restricted networks

如果你的 CI 环境网络访问受限(例如,DNS 限制阻止从 GitHub 下载 Sharp 预构建二进制文件),请考虑使用 node:22-slim 而不是 node:22-alpine。基于 Debian 的瘦身镜像避免了从源代码编译像 libvips 这样的本地依赖的需求,而且 Sharp 的预构建二进制文件可开箱即用:

🌐 If your CI environment has limited network access (e.g., DNS restrictions that prevent downloading Sharp prebuilt binaries from GitHub), consider using node:22-slim instead of node:22-alpine. The Debian-based slim image avoids the need to compile native dependencies like libvips from source, and Sharp's prebuilt binaries work out of the box:

FROM node:22-slim
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

这以略大一点的镜像换取更少的构建依赖和更少的网络需求。

设置环境变量

🌐 Set up environment variables

在你的 Strapi 项目根目录下创建一个 .env 文件。Docker Compose 在启动容器时会自动读取此文件,因此无需在你的 shell 中 export 它们。

🌐 Create a .env file at the root of your Strapi project. Docker Compose reads this file automatically when starting containers, so there is no need to export them in your shell.

为了在 Docker 容器中运行 Strapi,需要以下环境变量:

🌐 The following environment variables are required in order to run Strapi in a Docker container:

变量名描述
NODE_ENV应用运行的环境。
DATABASE_CLIENT要使用的数据库客户端。
DATABASE_HOST数据库主机。
DATABASE_PORT数据库端口。
DATABASE_NAME数据库名称。
DATABASE_USERNAME数据库用户名。
DATABASE_PASSWORD数据库密码。
JWT_SECRET用于为 Users-Permissions 插件签署 JWT 的密钥。
ADMIN_JWT_SECRET用于为管理面板签署 JWT 的密钥。
APP_KEYS用于签署会话 Cookie 的密钥。
API_TOKEN_SALT用于生成 API 令牌的盐值。
TRANSFER_TOKEN_SALT用于生成传输令牌的盐值。
ENCRYPTION_KEY用于加密存储在数据库中的秘密(例如,通过管理面板配置的提供程序凭证)的密钥。

你也可以设置一些可选环境变量

🌐 You can also set some optional environment variables.

以下示例包含占位符值。在启动容器之前,请将它们替换为你自己的值:

🌐 The following example contains placeholder values. Replace them with your own values before starting the containers:

terminal
./.env
# Server
HOST=0.0.0.0
PORT=1337

# Database
# Use 'mysql' for MySQL or MariaDB, and change DATABASE_PORT to 3306
DATABASE_CLIENT=postgres
DATABASE_HOST=strapiDB
DATABASE_PORT=5432
DATABASE_NAME=strapi
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strapi

# Secrets
APP_KEYS=toBeModified1,toBeModified2
API_TOKEN_SALT=tobemodified
ADMIN_JWT_SECRET=tobemodified
TRANSFER_TOKEN_SALT=tobemodified
JWT_SECRET=tobemodified
ENCRYPTION_KEY=tobemodified

# Environment
NODE_ENV=development

为数据库添加 Docker Compose

🌐 Add Docker Compose for the database

以下 docker-compose.yml 会在共享网络上启动一个数据库容器和一个 Strapi 容器。

🌐 The following docker-compose.yml starts a database container and a Strapi container on a shared network.

Note

有关 Docker Compose 及其命令的更多信息,请参阅 Docker Compose documentation

./docker-compose.yml
services:
strapi:
container_name: strapi
build: .
image: strapi:latest
restart: unless-stopped
env_file: .env # All variables from .env are injected into the container
volumes:
- ./config:/opt/app/config
- ./src:/opt/app/src
- ./package.json:/opt/package.json
- ./package-lock.json:/opt/package-lock.json
- ./.env:/opt/app/.env # Needed because Strapi uses dotenv to read .env in development
- ./public/uploads:/opt/app/public/uploads
ports:
- "1337:1337"
networks:
- strapi
depends_on:
strapiDB:
condition: service_healthy

strapiDB:
container_name: strapiDB
# platform: linux/amd64 # Uncomment if you encounter platform errors on Apple Silicon
restart: unless-stopped
image: postgres:16-alpine
environment:
POSTGRES_USER: ${DATABASE_USERNAME}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_NAME}
volumes:
- strapi-data:/var/lib/postgresql/data/
#- ./data:/var/lib/postgresql/data/ # if you want to use a bind folder
ports:
- "5432:5432" # Exposed for local debugging tools; remove if not needed
networks:
- strapi
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USERNAME} -d ${DATABASE_NAME}"]
interval: 10s
timeout: 5s
retries: 5

volumes:
strapi-data:

networks:
strapi:
name: strapi
driver: bridge

构建并运行

🌐 Build and run

  1. 构建并启动所有容器:

    terminal
    docker compose up --build
  2. 在浏览器中打开 http://localhost:1337/admin 以访问 Strapi 管理面板。

要停止容器,请运行 docker compose down。添加 -v 标志以同时删除数据库卷。

🌐 To stop the containers, run docker compose down. Add the -v flag to also remove the database volume.

生产环境

🌐 Production environment

生产镜像与开发镜像在三个关键方面有所不同:它们使用多阶段构建来减小镜像大小,在最终阶段仅安装生产依赖,并运行 npm run start 而不是开发命令。这确保镜像只包含服务应用所需的内容,没有开发工具或源映射。在生产环境中,反向代理应该位于 Strapi 容器之前(参见部署文档)。

🌐 Production images differ from development images in 3 key ways: they use multi-stage builds to reduce image size, they install only production dependencies in the final stage, and they run npm run start instead of the develop command. This ensures the image contains only what is needed to serve the application, without development tooling or source maps. A reverse proxy should sit in front of the Strapi container in production (see deployment documentation).

创建生产环境 Dockerfile

🌐 Create the production Dockerfile

以下 Dockerfile.prod 使用了多阶段构建。第一阶段安装所有依赖,包括构建步骤所需的开发依赖,并构建管理面板。第二阶段仅将生产资源复制到最终镜像中。

🌐 The following Dockerfile.prod uses a multi-stage build. The first stage installs all dependencies, including devDependencies needed for the build step, and builds the admin panel. The second stage copies only production assets into the final image.

Caution

不要在 npm ci 之前设置 NODE_ENV=production。这样做会导致 npm 跳过 devDependencies,而 Strapi 需要它来编译管理面板。构建可能看起来成功,但会生成损坏或不完整的管理面板包。

🌐 Do not set NODE_ENV=production before npm ci. Doing so causes npm to skip devDependencies, which Strapi needs to compile the admin panel. The build may appear to succeed but produce a broken or incomplete admin bundle.

./Dockerfile.prod
# Build stage
FROM node:22-alpine AS build
RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev bash vips-dev git > /dev/null 2>&1

WORKDIR /opt/
COPY package.json package-lock.json ./
RUN npm install -g node-gyp
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm ci
ENV PATH=/opt/node_modules/.bin:$PATH

WORKDIR /opt/app
COPY . .
# Uncomment the following lines to set the admin panel URL at build time.
# Without this, the admin panel defaults to localhost:1337.
# ARG STRAPI_ADMIN_BACKEND_URL
# ENV STRAPI_ADMIN_BACKEND_URL=${STRAPI_ADMIN_BACKEND_URL}
ENV NODE_ENV=production
RUN npm run build

# Production stage
FROM node:22-alpine
RUN apk add --no-cache vips-dev
ENV NODE_ENV=production

WORKDIR /opt/
COPY --from=build /opt/package.json /opt/package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force # --omit=dev replaces the deprecated --only=production
ENV PATH=/opt/node_modules/.bin:$PATH

WORKDIR /opt/app
COPY --from=build /opt/app ./

RUN chown -R node:node /opt/app
USER node
EXPOSE 1337
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:1337/_health || exit 1
CMD ["npm", "run", "start"]
Optimize image size

COPY --from=build /opt/app ./ 行会复制整个应用目录,包括源文件。为了生成更精简的镜像,你可以将其替换为有选择的复制(例如,dist/build/config/public/src/)。Strapi 5 管理员包会放在 dist/build/,所以确保该路径被包含。这是可选的,因为 Strapi 在运行时需要其中的大部分文件。

🌐 The COPY --from=build /opt/app ./ line copies the entire application directory, including source files. For a leaner image, you can replace it with selective copies (e.g., dist/build/, config/, public/, src/). The Strapi 5 admin bundle lands in dist/build/, so make sure that path is included. This is optional since Strapi needs most of these files at runtime.

Key difference from the development Dockerfile

构建阶段会安装所有依赖(包括开发依赖),因为 npm run build 步骤需要它们来编译管理面板。生产阶段随后只安装生产依赖,从而保持最终镜像精简。

🌐 The build stage installs all dependencies (including devDependencies) because the npm run build step needs them to compile the admin panel. The production stage then installs only production dependencies, keeping the final image lean.

为生产添加 Docker Compose

🌐 Add Docker Compose for production

以下 docker-compose.prod.yml 适用于生产部署。它使用 PostgreSQL 并包含健康检查。Strapi 端口绑定到 127.0.0.1,因此只有本地反向代理可以访问它。

🌐 The following docker-compose.prod.yml is suitable for production deployments. It uses PostgreSQL and includes healthchecks. The Strapi port binds to 127.0.0.1 so that only a local reverse proxy can reach it.

./docker-compose.prod.yml
services:
strapi:
container_name: strapi
build:
context: .
dockerfile: Dockerfile.prod
image: strapi:latest
restart: always
env_file: .env
environment:
NODE_ENV: production # Overrides the development value from .env
ports:
- "127.0.0.1:1337:1337"
networks:
- strapi
depends_on:
strapiDB:
condition: service_healthy

strapiDB:
container_name: strapiDB
restart: always
image: postgres:16-alpine
environment:
POSTGRES_USER: ${DATABASE_USERNAME}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_NAME}
volumes:
- strapi-data:/var/lib/postgresql/data/
networks:
- strapi
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USERNAME} -d ${DATABASE_NAME}"]
interval: 10s
timeout: 5s
retries: 5

volumes:
strapi-data:

networks:
strapi:
name: strapi
driver: bridge
生产清单

构建并发布

🌐 Build and publish

要构建生产用的 Docker 镜像,请运行以下命令:

🌐 To build a production Docker image, run the following command:

terminal
docker build \
-t mystrapiapp:latest \
-f Dockerfile.prod .

构建完成后,你可以将镜像发布到 Docker 注册表。对于生产环境使用,请使用私有注册表,因为你的 Docker 镜像可能包含敏感配置。

🌐 After building, you can publish the image to a Docker registry. For production usage, use a private registry since your Docker image may contain sensitive configuration.

流行的容器注册表包括:

🌐 Popular container registries include:

社区工具和图片

🌐 Community tools and images

Strapi 不提供官方的 Docker 镜像(见 FAQ)。以下社区维护的工具和镜像可以帮助你入门。

🌐 Strapi does not provide official Docker images (see FAQ). The following community-maintained tools and images can help you get started.

如果你想将你的工具添加到此列表中,请在 Strapi documentation repository上提交拉取请求。

@strapi-community/dockerize 命令行工具

🌐 The @strapi-community/dockerize CLI

@strapi-community/dockerize 包是一个 CLI 工具,它为 Strapi 项目生成 Dockerfiledocker-compose.yml 文件。

🌐 The @strapi-community/dockerize package is a CLI tool that generates a Dockerfile and docker-compose.yml file for a Strapi project.

要开始,请在现有的 Strapi 项目文件夹中运行 npx @strapi-community/dockerize@latest,然后按照 CLI 提示操作。

🌐 To get started, run npx @strapi-community/dockerize@latest within an existing Strapi project folder and follow the CLI prompts.

欲了解更多信息,请参阅官方 GitHub repositorynpm package

社区维护的 Docker 镜像

🌐 Community-maintained Docker images

社区成员维护的 Strapi 5 预构建 Docker 镜像可用。这些镜像让你无需编写自己的 Dockerfile 就能运行 Strapi。

🌐 Pre-built Docker images maintained by community members are available for Strapi 5. These images let you run Strapi without writing your own Dockerfile.

Caution

这些图片由社区维护,并非 Strapi 官方支持。在生产环境中使用它们之前,请查看他们的文档和源代码。

🌐 These images are community-maintained and not officially supported by Strapi. Review their documentation and source code before using them in production.

故障排除

🌐 Troubleshooting

以下部分详细说明了在搭载 Apple Silicon 的机器上使用 Sharp 和 ARM 构建时的一些常见问题。

🌐 The following section details some common issues with Sharp and ARM builds on Apple Silicon-powered machines.

Info

本页面上的 Dockerfile 在 Alpine 软件包列表中未包含 nasm。它在本指南的较早版本中曾被包含,但对 Sharp 或 libvips 的编译并不是必需的。

🌐 The Dockerfiles on this page do not include nasm in the Alpine package list. It was previously included in older versions of this guide but is not required for Sharp or libvips compilation.

Sharp 和 libvips 错误

🌐 Sharp and libvips errors

Sharp 是 Strapi 使用的图片处理库。它依赖于 libvips,该库在基于 Alpine 的镜像上需要本地编译。常见的错误信息包括 Cannot find module 'sharp'Error: sharp: Installation error

🌐 Sharp is the image processing library used by Strapi. It depends on libvips, which requires native compilation on Alpine-based images. Common error messages include Cannot find module 'sharp' or Error: sharp: Installation error.

为了解决锐角问题:

🌐 To resolve Sharp issues:

  1. 运行 docker exec <container> node -e "require('sharp')"。如果出现缺少库的错误,则运行时阶段缺少上述 Alpine 软件包。如果出现 glibc/musl 不匹配的错误,请切换到 node:22-slim(参见步骤 2)。

  2. 验证你的 Dockerfile 是否安装了所需的 Alpine 软件包:

    RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev bash vips-dev git
  3. 如果问题仍然存在,请切换到 node:22-slim(基于 Debian 的)以避免本地库兼容性问题 :

    FROM node:22-slim
    RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
  4. 对于 ARM 构建(见下文),在安装依赖之前添加以下环境变量:

    ENV SHARP_IGNORE_GLOBAL_LIBVIPS=1

苹果硅和 ARM 构建

🌐 Apple Silicon and ARM builds

docker-compose 文件中的 platform: linux/amd64 标志强制容器在基于 ARM 的机器(Apple M1/M2/M3)上以 x86 模拟运行。这可以工作,但比原生 ARM 构建要慢。

🌐 The platform: linux/amd64 flag in docker-compose files forces containers to run under x86 emulation on ARM-based machines (Apple M1/M2/M3). This works but is slower than native ARM builds.

针对原生 ARM 性能:

🌐 For native ARM performance:

  • 从你的 docker-compose 文件中移除 platform: linux/amd64 行。
  • 使用 node:22-alpinenode:22-slim 作为你的基础镜像。两者都原生支持 ARM64。
  • 确保 Sharp 依赖已正确安装(请参阅 Sharp 和 libvips 错误)。
Note

上面的 docker-compose 示例 中,platform: linux/amd64 标志被注释掉了。如果你的数据库镜像没有提供 ARM64 版本,请取消注释它。

🌐 The platform: linux/amd64 flag is commented out in the docker-compose examples above. Uncomment it if your database image does not provide an ARM64 variant.

数据库连接问题

🌐 Database connection issues

Warning

Strapi 应用必须使用由 Strapi 应用创建的数据库。不支持连接到预先存在的非 Strapi 数据库或 Strapi v3 数据库,并且可能导致数据丢失,例如表被删除。

🌐 Strapi applications must use a database created by a Strapi application. Connecting to a pre-existing non-Strapi database, or to a Strapi v3 database, is not supported and may result in lost data such as dropped tables.

如果 Strapi 无法在 Docker 中连接到数据库,请检查以下内容:

🌐 If Strapi cannot connect to the database in Docker, check the following:

  1. 确认 DATABASE_HOST 与你的 docker-compose 文件中的服务名称匹配(例如,strapiDB),而不是 localhost127.0.0.1。容器通过 Docker 网络使用服务名称进行通信。

  2. 检查本地数据库实例的端口冲突。如果数据库已经在本地的同一端口上运行:

    • 停止本地数据库,
    • 或者在你的 docker-compose 文件中更改主机端口映射(例如,"5433:5432")。
  3. 在你的数据库配置中将连接池 min 的值设置为 0,因为 Docker 可能会终止空闲连接:

    ./config/database.js
    module.exports = ({ env }) => ({
    connection: {
    client: env('DATABASE_CLIENT'),
    // ...
    pool: {
    min: 0,
    max: 10,
    },
    },
    });
  4. 如果数据库容器在一段时间不活动后变得无法访问,请在你的数据库配置中的连接池配置中添加超时设置:

    pool: {
    min: 0,
    max: 10,
    acquireTimeoutMillis: 60000,
    idleTimeoutMillis: 30000,
    },

接下来做什么?

现在 Strapi 正在 Docker 容器中运行,你可以:

🌐 Now that Strapi is running in a Docker container, you can:

设置管理面板并使用内容类型构建器创建你的第一个内容类型。
配置反向代理并部署到生产环境(参见部署文档)。
探索环境配置以微调你的 Strapi 实例。