SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

PUID và PGID trong Docker Compose là gì?

PUID và PGID không phải setting của Docker. Tìm hiểu quy ước entrypoint của linuxserver.io, vì sao file bind mount thành 911:911 và cách sửa đúng.

PUID và PGID thực chất là gì

PUID và PGID là hai biến môi trường mà một số container image đọc khi khởi động. Bản thân Docker không bao giờ đọc chúng. Đây là một quy ước được các image của linuxserver.io và một số image khác sử dụng. Vì vậy, image không được viết để đọc các biến này sẽ âm thầm bỏ qua chúng.

Bên trong image của linuxserver.io có một user tên là abc. User này được tạo trong lúc build với UID (user ID) 911 và GID (group ID) 911. Container khởi động dưới quyền root, chạy các init script, rồi một trong các script đó đổi ID của user trước khi ứng dụng khởi động:

groupmod -o -g "${PGID}" abc
usermod -o -u "${PUID}" abc

Cờ -o cho phép sử dụng một ID đã được dùng ở nơi khác. Sau đó, init hạ quyền và chạy ứng dụng dưới user abc. Vì vậy, Docker truyền PUID=1000 vào container như mọi biến môi trường khác và không thực hiện thao tác nào với biến này. Biến này đổi ID của một user bên trong container trước khi ứng dụng khởi động. Điều đó có nghĩa là với daemon rootful tiêu chuẩn, không bật user namespace remapping, các file mới tạo thường xuất hiện trên disk với owner là 1000. Việc ghi vào một file đã tồn tại và có quyền ghi không thay đổi owner của file đó. Rootless Docker sẽ dịch số ID này, như giải thích ở phần dưới. Nếu không đặt PUID, abc vẫn giữ ID 911. Đây là lý do bind mount chưa được cấu hình thường chứa đầy các file có owner là 911:911.

Lấy hai giá trị số bằng id

Chạy lệnh này trên host, bằng user sở hữu các thư mục dữ liệu:

id
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),988(docker)

uid là PUID và gid là PGID của bạn. Trong script, id -u và id -g sẽ in ra chỉ các giá trị số. Trên hầu hết image VPS mới, tài khoản người dùng đầu tiên có ID 1000:1000, nhưng không được mặc định như vậy. Việc cấp ID phụ thuộc vào các tài khoản và cấu hình hiện có: server được dựng lại có thể cấp lại 1000, còn tài khoản được tạo sau sẽ nhận ID khả dụng cao hơn. Nếu các service của bạn chạy bằng service account riêng thay vì user đăng nhập của bạn, hãy chạy id thatuser và lấy các giá trị số từ đó.

Vì sao file của bạn hiển thị là 911:911

ls -l hiển thị ID dạng số thay vì tên khi không có account trên host khớp với ID đó. Nếu không có account trên host nào khớp với UID 911 thì không có tên để hiển thị. Dùng ls -ln để luôn hiển thị số và loại bỏ sự không rõ ràng:

ls -ln /srv/appdata/sonarr
drwxr-xr-x 2 911 911 4096 Aug  7 09:12 Backups
-rw-r--r-- 1 911 911  512 Aug  7 09:12 config.xml

Kết quả này khớp với giá trị mặc định tích hợp trong container, nhưng chỉ nhìn các file hiện có thì chưa thể xác nhận ứng dụng hiện đang chạy bằng user nào. config.xml trong kết quả đó cũng là file chứa các thiết lập xác thực. Điều này quan trọng khi bạn mở web UI lần đầu và thấy rằng Sonarr và Radarr không có username hoặc password mặc định. Hãy xác nhận từ bên trong container thay vì đoán:

docker exec sonarr id abc
docker compose logs sonarr | head -n 25

init của linuxserver in kết quả vào startup log trên 2 dòng:

User UID:    911
User GID:    911

Nếu 2 dòng đó hiển thị 911 sau khi bạn đặt PUID=1000 trong file Compose, container đang chạy không sử dụng giá trị bạn đã đặt. Nguyên nhân thường gặp là bạn sửa docker-compose.yml rồi chạy docker compose restart. Lệnh này dùng lại container hiện có cùng environment ban đầu. Thay đổi environment cần dùng docker compose up -d để tạo lại container. Nguyên nhân còn lại là có chủ ý: khi image chạy ở chế độ read-only hoặc non-root, init sẽ bỏ qua hoàn toàn việc đánh số lại, dù biến vẫn tồn tại trong container. Ở chế độ read-only, banner hiển thị ID không đổi của abc; ở chế độ non-root, banner hiển thị owner của /run.

Vì sao bạn không thể xóa file do container tạo

Kernel so sánh các con số, không so sánh tên. Shell của bạn chạy với UID 1000. File thuộc về UID 911. Thư mục chứa file là drwxr-xr-x và cũng thuộc về 911, nên group và other có quyền đọc và thực thi nhưng không có quyền ghi. Muốn xóa file, bạn cần quyền ghi trên thư mục chứa file, không phải trên chính file đó. Vì vậy lỗi này vẫn xảy ra ngay cả khi bản thân file có vẻ vô hại:

rm: cannot remove '/srv/appdata/sonarr/config.xml': Permission denied

Container đang ghi file cũng gặp đúng vấn đề này từ phía ngược lại. Nếu thư mục trên host thuộc về user của bạn và có mode 755, còn ứng dụng chạy với UID 911, lần ghi đầu tiên của nó sẽ thất bại với Permission denied và ứng dụng sẽ báo lỗi theo cách riêng của nó. Trong ứng dụng .NET như Sonarr hoặc Radarr, lỗi đó sẽ hiện thành UnauthorizedAccessException: Access to the path '/data/downloads' is denied. Chuỗi quyền ở trước tên file cho biết bạn đang bị xét theo nhóm quyền nào trong ba nhóm. Đọc đúng drwxr-xr-x sẽ biến lỗi này từ khó hiểu thành hiển nhiên.

Đây là vấn đề riêng của bind mount. Khi Docker tạo một named volume trống rồi mount volume đó lên một đường dẫn đã tồn tại trong image, Docker sẽ sao chép nội dung của đường dẫn đó vào volume, bao gồm cả ownership và các permission bit. Vì vậy ứng dụng sẽ thấy một thư mục mà nó đã có quyền sở hữu. Bind mount không được xử lý như vậy: Docker mount thư mục trên host chính xác theo trạng thái hiện tại của nó. Đây là một trong những lý do thực tế để bạn biết khi nào bind mount phù hợp hơn named volume và khi nào không phù hợp.

Xử lý thư mục đã sai quyền

Thiết lập PUID và PGID chỉ thay đổi cách ứng dụng hoạt động từ thời điểm đó trở đi. Thiết lập này không tự sửa ngược mọi file đã có trên disk, dù init sẽ sửa ownership cho các path cụ thể được mô tả bên dưới. Hãy stop stack, tự sửa ownership, rồi start lại:

docker compose down
sudo chown -R 1000:1000 /srv/appdata/sonarr
docker compose up -d

Dùng sudo chown -R "$(id -u):$(id -g)" /srv/appdata/sonarr nếu bạn không muốn tự nhập các con số. Thực hiện việc này khi container đã stopped, vì ứng dụng đang chạy và ghi file trong lúc thực hiện chown đệ quy có thể khiến cây thư mục chỉ được sửa một phần và tạo thêm một vòng lỗi khó xác định.

PUID và PGID không sửa được gì

Đây là phần thường gây lỗi cho những người đã làm đúng mọi bước. Script thiết lập user của image cơ sở linuxserver chạy chown cho ba path khi khởi động: /app, /config và /defaults. Các mount chứa media của bạn không nằm trong danh sách đó. /data, /downloads và /tv được chuyển nguyên trạng cho ứng dụng. Vì vậy, nếu phía host của các mount này có ownership mà user trong container không thể ghi, container vẫn khởi động bình thường, in đúng UID trong banner, rồi fail ngay ở lần import đầu tiên.

Đó là hành vi đúng. Chạy chown đệ quy trên thư viện media dung lượng 12 terabyte mỗi lần container khởi động sẽ là một thảm họa. Điều đó cũng có nghĩa là bạn phải tự xử lý các thư mục media. Đây là những mount thực sự dễ xảy ra lỗi permission. Vì loại lỗi này thường chỉ âm thầm xuất hiện trong application log nhiều giờ sau khi container có vẻ vẫn khỏe, một write test chạy định kỳ và tích hợp với ntfy trên VPS của bạn để đẩy alert vào điện thoại là cách đơn giản để phát hiện lỗi trước khi bạn phải nhận ra qua cả tuần bị thiếu episode.

Ba cách kiểm soát user và khi nào áp dụng từng cách

Biến môi trường PUID và PGID

Cách này chỉ hoạt động trên các image có entrypoint đọc được các biến này. Nó phổ biến vì container vẫn khởi động với root, tự thực hiện bước thiết lập, sửa /config, rồi mới hạ quyền. Docker Mods và các init script tùy chỉnh vẫn hoạt động. Đổi lại, bạn đang tin vào một quy ước thay vì một tính năng của platform, và tên biến không thống nhất giữa các project.

Khóa user: trong Compose

Đây là tính năng thực sự của Docker và hoạt động với mọi image, vì container runtime áp dụng nó trước khi code của image chạy:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    user: "1000:1000"

Process không bao giờ chạy với root, kể cả trong thời gian rất ngắn. Đây là một lợi ích bảo mật thực sự. Tuy nhiên, cách này cũng làm hỏng mọi thành phần trong entrypoint cần quyền root. Trên các image của linuxserver, project hỗ trợ cách này trên cơ sở nỗ lực hợp lý và chỉ với những image đã được kiểm thử. Các điểm cần lưu ý rất cụ thể: PUID và PGID không còn tác dụng, Docker Mods sẽ không chạy, các service tùy chỉnh sẽ không chạy, và bạn phải tự chịu trách nhiệm về quyền trên mọi volume được mount. Pattern được tài liệu hóa của họ ghép flag này với một /run có quyền ghi:

user: 1000:1000
tmpfs:
  - /run:uid=1000,gid=1000,exec
security_opt:
  - no-new-privileges=true

Một tác động chỉ mang tính hiển thị thường khiến người dùng bất ngờ. Một user: dạng số không có entry tương ứng trong /etc/passwd của container sẽ khiến các tool bên trong hiển thị whoami: cannot find name for user ID 1000. ID vẫn hợp lệ và việc truy cập file vẫn hoạt động bình thường. Chỉ bước tra cứu tên bị lỗi.

Docker rootless

Docker rootless chạy chính daemon bằng user không có đặc quyền của bạn, nên daemon và các container không chạy với quyền root trên host. Cách này thay đổi hoàn toàn phép tính ownership. Container UID 0 được ánh xạ tới UID của user đang chạy Docker rootless trên host. Container UID n đối với mọi n từ 1 trở lên được ánh xạ tới subuid + (n - 1), trong đó subuid là giá trị bắt đầu của range được cấp cho bạn trong /etc/subuid; group ID cũng tuân theo quy tắc tương tự bằng /etc/subgid. Docker yêu cầu ít nhất 65,536 subordinate ID trong đó.

Hãy đọc lại mapping này, vì nó đảo ngược khuyến nghị thông thường. Với Docker rootless, container tạo file bằng root thường sẽ tạo file có ownership thuộc về bạn. Container tạo file bằng UID 1000 thường sẽ tạo file thuộc về một subordinate ID, chẳng hạn 100999 khi range bắt đầu từ 100000. Quyền truy cập từ shell của bạn phụ thuộc vào permission và ACL; việc xóa file thường phụ thuộc vào directory chứa file, nên bạn vẫn có thể xóa file đó từ directory mà bạn kiểm soát. Vì vậy, giá trị PUID đúng trên daemon rootful lại là giá trị sai ở đây. Hai cơ chế thay đổi ownership tại các layer khác nhau. Nếu chồng chúng lên nhau mà không kiểm tra, bạn có thể mất quyền ghi vào data đã mount. Nếu chuyển sang rootless, hãy kiểm tra ownership của một file được tạo trên chính server của bạn trước khi migrate một thư viện vào đó.

Với hầu hết stack self-hosted chạy trên một VPS, PUID và PGID trên daemon rootful là lựa chọn thực tế, vì đó là cách các image được xây dựng và tài liệu hóa. Hãy dùng user: khi README của image nói image đó đã được kiểm thử với cách này, hoặc khi bạn chạy một image chính thức từ upstream hoàn toàn không hỗ trợ PUID. Một workspace tài liệu như một instance AFFiNE self-hosted trên một VPS thuộc trường hợp sau, vì không container nào của nó đọc PUID. Ownership của database directory và các file upload được runtime quyết định, không phải bởi các giá trị trong environment block. Điều tương tự cũng đúng với một support desk Chatwoot self-hosted, trong đó Rails container và worker Sidekiq cùng ghi vào một uploads directory, nhưng không container nào đọc PUID. Vì vậy directory đó phải khớp với user mà image vốn đã chạy bằng. Điều này cũng không thay đổi với stack mới hơn. Vì vậy, cấp cho mỗi người trong team một sandbox OneCLI riêng khiến các directory workspace của từng người và Postgres data directory thuộc về user mà mỗi image vốn đã chạy bằng. Đây là vấn đề về user: và chown, không phải vấn đề PUID. Nếu đặt một API self-hosted duy nhất phía trước Codex, Claude Code và Hermes, entrypoint của nó sẽ quản lý nhiều identity: container phải khởi động bằng root, console và gateway chạy bằng một user không có đặc quyền, còn mỗi agent session chạy bằng user riêng. Không thêm user: vào deployment đó; entrypoint đã tự xử lý ownership của data volume.

Trường hợp media stack: dùng chung một group giữa các container

Một media stack kiểu arr với Sonarr, Radarr và download client là nơi vấn đề này không còn chỉ là lý thuyết. Download client ghi file đã tải xong vào /data/downloads. Sau đó Sonarr tạo hardlink hoặc di chuyển file đó vào /data/media. Để hardlink hoạt động, hai container phải có quyền ghi vào cùng một cây thư mục. Nếu download client chạy với UID 1000 còn Sonarr chạy với UID 1001 mà không có quyền ghi dùng chung qua group, một container sẽ sở hữu các file mà container kia chỉ có thể đọc.

Cách xử lý là tạo một group dùng chung và cho mọi container trong stack sử dụng group đó làm PGID:

sudo groupadd -g 13000 media
sudo usermod -aG media deploy
sudo chown -R deploy:media /srv/media
sudo find /srv/media -type d -exec chmod 2775 {} +
sudo find /srv/media -type f -exec chmod 0664 {} +

2775 bắt đầu bằng 2, đây là setgid bit. Trên một thư mục, bit này có nghĩa là mọi file và thư mục con mới được tạo bên trong sẽ kế thừa group media thay vì primary group riêng của user tạo file. Nhờ đó cấu hình vẫn áp dụng cho các lượt tải mới mà không cần chạy lại chown. Hãy đăng xuất rồi đăng nhập lại, hoặc chạy newgrp media, trước khi kiểm tra quyền truy cập của bạn. Group được thêm bằng usermod -aG không xuất hiện trong một shell đã mở từ trước.

Bên trong container, groupmod -o -g 13000 abc đổi GID của group abc thành 13000, để abc ghi file với cùng GID như group media trên host. Mọi container linuxserver truy cập cây thư mục này đều giữ PUID riêng và dùng chung PGID đó. Điều này cũng áp dụng cho các container ở phía sau chỉ đọc thư viện đã hoàn tất, chẳng hạn chính Jellyfin. Front end như Halcyon, ứng dụng cung cấp thư viện đó dưới dạng một cửa hàng video thập niên 90 có thể duyệt, kết nối đến Jellyfin qua HTTP bằng HALCYON_JELLYFIN_URL. Cấu hình triển khai tiêu chuẩn của nó không cần media PGID dùng chung và cũng không cần mount thư mục media.

Tiếp theo, đặt UMASK=002 trên mọi container linuxserver trong stack. Đây là bước nhiều người bỏ sót. Nếu không đặt, ứng dụng sẽ tiếp tục dùng umask được kế thừa, trừ khi có cơ chế khác thay đổi giá trị này. Giá trị ví dụ trong README của image là UMASK=022. Với umask hiệu lực là 022, nếu ứng dụng yêu cầu 0666 khi tạo file mới thì file sẽ có 0644 nếu không có ACL mặc định. Các thành viên khác trong group vẫn đọc được file nhưng không thể sửa, làm mất phần lớn tác dụng của cấu hình dùng chung vừa thiết lập. Với 002 và không có ACL mặc định, ứng dụng yêu cầu thông thường 0666 cho file và 0777 cho thư mục sẽ tạo file 0664 và, bên trong cây thư mục có setgid, tạo thư mục 2775; group khi đó có quyền ghi. Umask chỉ loại bỏ các bit quyền. Vì vậy, ứng dụng yêu cầu 0600 vẫn nhận 0600. Thư mục có ACL mặc định thì bỏ qua umask hoàn toàn. Thêm biến này cạnh PUID và PGID:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - UMASK=002
      - TZ=Etc/UTC
    volumes:
      - /srv/appdata/sonarr:/config
      - /srv/media:/data
    restart: unless-stopped

Hai giá trị đó nên được đặt trong file .env nằm cạnh file Compose, để toàn bộ stack dùng cùng một định nghĩa:

PUID=1000
PGID=13000

Compose tự động đọc file đó để thay thế theo kiểu ${PUID}. Đây cũng là cơ chế bạn dùng cho credential. Các nguyên tắc đưa các giá trị ra khỏi docker-compose.yml và đặt vào file .env cũng áp dụng ở đây, chỉ khác là hai số này không phải secret.

Hãy kiểm tra toàn bộ quy trình thay vì chỉ tin vào config. Tạo một file mới bằng user của ứng dụng, áp dụng umask đã cấu hình, rồi đọc file đó từ host. Dùng một tên file chưa tồn tại:

docker exec --user abc sonarr sh -c 'umask "$UMASK" && touch /data/downloads/permtest'
ls -ln /srv/media/downloads/permtest

Kết quả đúng phải cho thấy PUID của bạn là owner, 13000 là group và -rw-rw-r-- là mode. Nếu group hiển thị 1000, hãy chạy ls -ldn /srv/media/downloads. Nguyên nhân là setgid bit, tức s trong drwxrwsr-x, bị thiếu trên thư mục đó; hoặc thư mục vẫn thuộc group 1000 thay vì media. Hai lệnh chown và chmod 2775 ở trên sẽ sửa cả hai vấn đề. Nếu mode hiển thị -rw-r--r--, hãy kiểm tra giá trị UMASK của container và ACL mặc định của thư mục. Nếu environment của container đã cũ, hãy tạo lại container. Bài kiểm tra này xác nhận việc tạo file bằng abc với mask đã cấu hình. Mode tạo file và umask hiệu lực của chính ứng dụng vẫn quyết định quyền của các file ứng dụng tạo ra. Khi hoàn tất, xóa file kiểm tra bằng rm /srv/media/downloads/permtest.

Ảnh nào dùng biến nào

Các image của linuxserver.io dùng PUID, PGID và UMASK. Paperless-ngx dùng tên khác cho cùng ý tưởng: USERMAP_UID và USERMAP_GID, cả hai mặc định là 1000. Tài liệu của ứng dụng này hướng dẫn đọc các giá trị đó từ id -u và id -g. Các máy chủ ảnh cũng có cách triển khai khác nhau: PhotoPrism có cặp PHOTOPRISM_UID và PHOTOPRISM_GID riêng, còn Immich không có biến tương đương mà để user trong container do khóa user: của Docker quyết định. Vì vậy, chọn PhotoPrism hay Immich cũng quyết định cơ chế nào trong số này bạn sẽ phải duy trì cho thư viện lớn nhất trên máy. Nhiều image chính thức của upstream, bao gồm các image database và web server phổ biến, dùng một user tích hợp cố định và yêu cầu bạn dùng user: hoặc giữ nguyên cấu hình đó. Các triển khai nhỏ chỉ chạy một ứng dụng cũng đặt ra câu hỏi tương tự. Vì vậy, khi dựng một trình theo dõi bài tập openGym tự host, bạn nên kiểm tra container thực sự chạy bằng user nào trước khi trỏ bind mount vào đó. Thư mục chứa database của ứng dụng sẽ tuân theo user này, bất kể bạn có đặt PUID hay không. Relay truy cập từ xa cũng thuộc cùng nhóm này. Khi tự chạy máy chủ relay RustDesk, cặp khóa Ed25519 mà hbbs ghi khi khởi động lần đầu sẽ xuất hiện trong bind mount với quyền sở hữu của user mà image đó sử dụng khi kết thúc quá trình khởi động. Bạn có thể sửa quyền này sau bằng chown trên host, hoặc chọn identity ngay từ đầu bằng khóa user:, vì image này không tự đặt user nào, miễn là thư mục được mount có quyền ghi cho ID bạn chọn. Điều tương tự áp dụng cho hạ tầng bạn bổ sung sau đó. Đưa Authentik đứng trước các ứng dụng để dùng một lần đăng nhập có nghĩa là chạy các image authentik và Postgres chính thức. Các image này không đọc PUID, nên quyền sở hữu volume phụ thuộc vào user mà process của chúng chạy bằng và các thiết lập do entrypoint thực hiện. Authentik đã loại bỏ dependency Redis từ release 2025.10.

Vì vậy, hãy kiểm tra README của từng image trước khi sao chép một block environment giữa các project. Docker truyền mọi biến môi trường bạn đặt vào container, bất kể bên trong container có đọc biến đó hay không. Một PUID không có process nào sử dụng sẽ không tạo ra lỗi, cảnh báo hoặc tác động nào. Container khởi động bằng user do thiết lập user: của Docker hoặc Dockerfile chọn. Sau đó, entrypoint có thể hạ quyền trước khi khởi động ứng dụng. Hãy kiểm tra việc này trước khi bổ sung bất kỳ thứ gì vào máy, bao gồm một stack quét bảo mật open-kritt tự host. Compose file sẽ cho biết các image có hỗ trợ PUID hay không, hoặc quyền sở hữu các thư mục bạn mount đã được cố định theo chính các image đó.

FAQ

Vì sao các file Docker của tôi có owner là 911:911?

911 là UID và GID của user abc được tích hợp sẵn trong các image của linuxserver.io. Việc thấy giá trị này khớp với mặc định tích hợp sẵn là bình thường, nhưng file vẫn có thể giữ owner đó sau khi bạn thay đổi PUID và PGID của container. ls -l hiển thị các số thô khi không có account nào trên host khớp với các ID đó, nên không có tên để hiển thị. Đặt PUID và PGID theo output của id, tạo lại container bằng docker compose up -d, rồi sửa owner của các file hiện có bằng sudo chown -R 1000:1000 trên thư mục bị ảnh hưởng.

PUID và PGID có hoạt động trên mọi Docker image không?

Không. Đây không phải là tính năng của Docker và Docker không bao giờ đọc chúng. Chúng chỉ hoạt động trên các image có entrypoint tự đọc các biến này rồi gọi usermod và groupmod trước khi khởi động ứng dụng. linuxserver.io là nhóm image dùng cách này, cùng với một số project đã sao chép pattern đó. Các project khác dùng tên khác, chẳng hạn USERMAP_UID và USERMAP_GID trong paperless-ngx. Với image không đọc các biến này, chúng được chấp nhận rồi bỏ qua mà không có cảnh báo.

Nên dùng PUID và PGID hay key user: trong Docker Compose?

Dùng PUID và PGID khi image hỗ trợ chúng, vì entrypoint vẫn chạy với root đủ lâu để xử lý /config và khởi động đúng các service của nó. Dùng user: khi tài liệu của image xác nhận hỗ trợ user đã chọn. Việc không hỗ trợ PUID không tự động có nghĩa là entrypoint của image có thể chạy mà không cần root. Trên image của linuxserver, đặt user: sẽ khiến PUID và PGID không còn tác dụng, ngăn Docker Mods và các service tùy chỉnh chạy, đồng thời khiến bạn tự chịu trách nhiệm về permission của mọi volume được mount.

Sonarr có PUID đúng nhưng vẫn không thể di chuyển file. Lỗi ở đâu?

Hãy kiểm tra lần lượt 3 điểm. Trước tiên là chính media mount: script thiết lập user của base image chạy chown cho /app, /config và /defaults, nên /data hoặc /downloads giữ nguyên owner mà chúng có trên host. Tiếp theo là shared group: cấp cho các container truy cập media tree cùng PGID và quyền group write. Cuối cùng là umask: mask hiệu dụng 022 tạo ra các file 0644 khi ứng dụng yêu cầu 0666 và không có default ACL, nên các container khác trong group có thể đọc nhưng không thể sửa chúng. Để UMASK unset không đảm bảo một mask hoặc file mode cụ thể. Đặt UMASK=002 và bật setgid bit trên các thư mục bằng chmod 2775 để file mới kế thừa group. Ứng dụng yêu cầu 0600 vẫn tạo file private, còn default ACL sẽ thay đổi cách gán permission khi tạo file.

Bài viết này có hữu ích không?