Sửa lỗi 'EACCES: permission denied' trong Docker: Hướng dẫn về quyền hạn Node.js

intermediate🐳 Docker2026-07-27| Docker, Node.js (Alpine/Debian), Linux, macOS, hoặc Windows WSL2

Error Message

Error: EACCES: permission denied, mkdir '/app/node_modules/.cache'
#docker#nodejs#devops#bảo mật

Ngữ cảnhChạy container dưới quyền root là một rủi ro bảo mật lớn. Để khắc phục điều này, hầu hết các image Node.js chính thức đều bao gồm một người dùng non-root có sẵn tên là node. Tuy nhiên, việc chuyển sang người dùng này thường dẫn đến một trở ngại gây ức chế: lỗi quyền truy cập (permission errors). Bạn có thể sẽ thấy lỗi này khi lệnh npm install chạy, hoặc khi các framework như Next.js hoặc Vite cố gắng ghi vào thư mục .cache trong quá trình khởi động.

Lỗi này thường xuất hiện ngay sau khi bạn thêm USER node vào Dockerfile của mình. Quá trình build hoặc runtime sẽ bị treo với một thông báo cụ thể:

Error: EACCES: permission denied, mkdir '/app/node_modules/.cache'

Nguyên nhân gốc rễVấn đề nằm ở quyền sở hữu (ownership). Khi Docker thực hiện các lệnh như WORKDIR hoặc COPY, nó mặc định sử dụng người dùng root (UID 0). Nếu các lệnh này tạo thư mục /app, thì root sẽ sở hữu nó. Khi sau đó bạn chuyển sang người dùng node (thường là UID 1000), người dùng đó không có quyền chỉnh sửa các tệp do root tạo ra.

Các nguyên nhân phổ biến bao gồm:

  • Lệnh COPY mặc định: Chạy COPY . . mà không có cờ (flag) sẽ khiến root trở thành chủ sở hữu của mọi tệp trong container.- Ghi đè Volume: Gắn (mount) một thư mục cục bộ đè lên node_modules có thể đồng bộ hóa quyền từ máy host vốn không khớp với người dùng nội bộ của container.- Tự động tạo thư mục: Chỉ dẫn WORKDIR mặc định sẽ tạo các đường dẫn còn thiếu dưới quyền root.## Từng bước khắc phục### 1. Sử dụng cờ --chown trong DockerfileCách khắc phục đáng tin cậy nhất là đảm bảo người dùng node sở hữu thư mục trước khi bạn sao chép mã nguồn. Bạn cũng phải yêu cầu Docker thay đổi quyền sở hữu trong quá trình sao chép bằng cách sử dụng cờ --chown.
# Sử dụng phiên bản cụ thể để đảm bảo tính ổn định
FROM node:18-alpine

# Tạo trước thư mục app với quyền hạn chính xác
RUN mkdir -p /home/node/app && chown -R node:node /home/node/app

WORKDIR /home/node/app

# Chuyển sang người dùng non-root sớm
USER node

# Sao chép các tệp package trước để tận dụng Docker cache
COPY --chown=node:node package*.json ./

RUN npm install

# Sao chép toàn bộ mã nguồn còn lại
COPY --chown=node:node . .

CMD ["npm", "start"]

2. Xử lý Volume trong Docker ComposeViệc phát triển ở môi trường local thường làm hỏng quyền hạn vì máy host của bạn (Mac/Windows/Linux) có User ID khác với container. Để ngăn node_modules của máy host ghi đè lên phiên bản của container, hãy sử dụng một anonymous volume. Điều này giúp thư mục phía container được quản lý bởi engine nội bộ của Docker.

services:
  web:
    build: .
    user: "node"
    volumes:
      - .:/home/node/app
      - /home/node/app/node_modules # Volume ẩn danh này bảo vệ các quyền hạn nội bộ
    environment:
      - NODE_ENV=development

3. Cách sửa nhanh cho Container đang chạyNếu bạn cần sửa một container đang chạy, bạn có thể ép buộc thay đổi quyền sở hữu bằng cách sử dụng docker exec với quyền root. Đây là một giải pháp tạm thời nhưng hiệu quả trong tình huống khẩn cấp:

docker exec -u root -it <container_id> chown -R node:node /home/node/app/node_modules

Xác minh kết quảKiểm tra xem các thay đổi của bạn có hoạt động hay không bằng cách kiểm tra quyền sở hữu thư mục bên trong container. Chạy lệnh sau:

docker exec -it <container_id> ls -la /home/node/app

Trong kết quả trả về, hãy tìm dòng node_modules. Nó sẽ trông như thế này:

drwxr-xr-x 100 node node 4096 Oct 20 10:00 node_modules

Nếu các cột vẫn hiển thị root root, nghĩa là lệnh chown của bạn đã bị bỏ sót hoặc một volume mount đang ghi đè lên nó.

Phòng ngừa và mẹo nhỏQuyền hạn trong Linux có thể gây đau đầu, đặc biệt là khi UID không khớp giữa máy tính của bạn và container. Việc hình dung các bit quyền hạn sẽ giúp tránh sai lầm.

Tôi thường sử dụng Trình tính toán quyền Unix (Unix Permissions Calculator) trên ToolCraft để xác minh logic chmod của mình. Đây là một công cụ trình duyệt đơn giản giúp chuyển đổi các ô tích (Read/Write/Execute) thành mã số chính xác mà bạn cần. Nó chạy cục bộ trong trình duyệt, vì vậy rất an toàn để kiểm tra các cấu hình nhạy cảm. Các điểm chính cần nhớ:

  • Luôn sử dụng --chown: Không bao giờ sử dụng COPY mà không có --chown=node:node nếu bạn đang dùng người dùng non-root.- Thứ tự quan trọng: Tạo WORKDIR và thiết lập quyền hạn trước khi bạn chuyển đổi USER.- Bảo vệ node_modules: Sử dụng anonymous volumes trong Compose để ngăn chặn xung đột quyền hạn từ phía máy host.- Tránh dùng 777: Không bao giờ sử dụng chmod 777 để sửa lỗi. Đó là một lỗ hổng bảo mật cực lớn. Hãy kiên trì với chown để chỉ cấp quyền truy cập cho người dùng thực sự cần nó.

Related Error Notes