You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker化Next.js应用上传文件至卷报错:EACCES权限被拒绝

解决Docker化Next.js应用上传文件EACCES权限拒绝问题

问题核心

Docker命名卷默认由root用户创建并拥有权限,当你将storage卷挂载到/usr/src/app/public/uploads后,容器内该目录的权限会被卷的权限覆盖——尽管你在Dockerfile中用--chown=node:node设置了public目录的权限,但挂载卷的操作会完全替代镜像中该目录的内容和权限,最终导致node用户无法写入uploads目录。

解决方案

方案1:容器启动时自动修正权限

直接在compose.yaml的app-prod服务中修改启动命令,先修改uploads目录权限再启动应用:

# compose.yaml
services:
  app-prod:
    build:
      context: .
    links:
      - app-database
    environment:
      NODE_ENV: production
    ports:
      - 3000:3000
    env_file:
      - .env.production
      - .env
    volumes:
      - storage:/usr/src/app/public/uploads
    # 添加启动前权限修正命令
    command: sh -c "chown node:node /usr/src/app/public/uploads && yarn start"

说明:第一次启动时会修改卷的权限,后续启动由于卷是持久化的,权限会保持为node:node,重复执行命令无负面影响。

方案2:在镜像中预创建uploads目录并设置权限

修改Dockerfile的final阶段,提前创建uploads目录并赋予node用户权限,这样当挂载空的命名卷时,卷会继承挂载点目录的权限:

# Dockerfile final阶段修改
FROM base as final

ENV NODE_ENV production

# 临时切换root创建目录并设置权限
USER root
RUN mkdir -p /usr/src/app/public/uploads && chown node:node /usr/src/app/public/uploads
USER node

COPY --from=build /usr/src/app/node_modules ./node_modules
COPY --from=build --chown=node:node /usr/src/app/public ./public
COPY --from=build /usr/src/app/.next ./.next
COPY --from=build /usr/src/app/package.json ./

CMD yarn start

说明:重新构建镜像后,挂载空卷时,卷的初始权限会自动设为node:node,无需每次启动修改。

方案3:用初始化容器一次性修正权限

添加一个临时的初始化容器,专门负责修改存储卷的权限,完成后再启动应用:

# compose.yaml
services:
  init-storage:
    image: alpine:latest
    volumes:
      - storage:/usr/src/app/public/uploads
    # 执行权限修改命令
    command: sh -c "chown node:node /usr/src/app/public/uploads"
  
  app-prod:
    build:
      context: .
    links:
      - app-database
    environment:
      NODE_ENV: production
    ports:
      - 3000:3000
    env_file:
      - .env.production
      - .env
    volumes:
      - storage:/usr/src/app/public/uploads
    # 等待初始化容器完成后再启动
    depends_on:
      init-storage:
        condition: service_completed_successfully

  app-database:
    image: mongo:6
    volumes: 
     - database:/data/db
    ports:
      - 27017:27017

volumes:
  database:
  storage:

说明:初始化容器仅在第一次启动或需要重置权限时运行一次,不会常驻占用资源。

验证方法

修改完成后启动容器,进入容器查看权限:

docker exec -it <app-prod-container-id> sh
ls -l /usr/src/app/public/

确认uploads目录的所有者为node:node即可。

内容的提问来源于stack exchange,提问作者buga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 23:27:03