SSD Nodes Learn 🎉 VPS mula $5.50/buwan
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-13

Ano ang PUID at PGID sa Docker Compose?

Alamin kung bakit napupunta bilang 911:911 ang bind-mount files: convention ito ng linuxserver.io images, hindi Docker setting, at inaayos sa PUID at PGID.

Ano talaga ang PUID at PGID

Ang PUID at PGID ay dalawang environment variable na binabasa ng ilang container image sa startup. Hindi kailanman tinitingnan ng Docker ang mga ito. Convention lamang ang mga ito na ginagamit ng linuxserver.io images at ng iilang iba pa. Kaya tahimik na binabalewala ang mga ito ng image na hindi ginawa para basahin ang mga ito.

Sa loob ng linuxserver.io image, may user na tinatawag na abc. Ginagawa ito sa build time na may UID (user ID) na 911 at GID (group ID) na 911. Nagsisimula ang container bilang root at pinapatakbo nito ang init scripts. Bago mangyari ang iba pang operasyon, nire-renumber ng isa sa mga script na ito ang user:

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

Pinapayagan ng -o flag ang paggamit ng ID na ginagamit na sa ibang lugar. Pagkatapos nito, ibinababa ng init ang privileges at pinapatakbo ang application bilang abc. Kaya hindi kailanman nakakarating sa Docker ang PUID=1000. Nire-renumber ng variable ang user sa loob ng container bago magsimula ang application. Dahil dito, ang bawat file na isinusulat ng application ay napupunta sa disk mo na pagmamay-ari ng 1000. Kapag hindi nakatakda ang PUID, nananatili sa 911 ang abc. Ito ang dahilan kung bakit napupuno ng mga file na pagmamay-ari ng 911:911 ang isang hindi na-configure na bind mount.

Kunin ang dalawang numero gamit ang id

Patakbuhin ito sa host bilang user na nagmamay-ari ng mga data directory:

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

Ang uid ang iyong PUID at ang gid ang iyong PGID. Para sa script, ang id -u at id -g ay nagpi-print ng mga numero lamang. Sa karamihan ng bagong VPS image, 1000:1000 ang unang human account, pero huwag itong ipagpalagay. Kapag ni-rebuild ang server o nagdagdag ka ng pangalawang account, maaaring 1001 o mas mataas ang numero. Ang maling numero rito ang buong sanhi ng bug. Kung tumatakbo ang iyong mga serbisyo sa ilalim ng dedicated service account sa halip na sarili mong login user, patakbuhin ang id thatuser at kunin ang mga numero mula roon.

Bakit lumalabas bilang 911:911 ang iyong mga file

Ang ls -l ay nagpi-print ng numeric ID sa halip na pangalan kapag walang host account na tumutugma sa ID na iyon. Walang UID 911 sa iyong server, kaya walang pangalang mai-print. Gamitin ang ls -ln para palaging makita ang mga numero at alisin ang kalituhan:

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

Ipinapakita ng output na iyon na tumakbo ang container gamit ang built-in defaults. Kumpirmahin ito mula sa loob ng container sa halip na manghula:

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

Ini-print ng linuxserver init ang resulta nito sa startup log bilang dalawang linya:

User UID:    911
User GID:    911

Kung 911 ang nakalagay sa mga linyang iyon matapos mong itakda ang PUID=1000 sa iyong Compose file, hindi nakarating ang variable sa container. Karaniwang sanhi nito na in-edit mo ang docker-compose.yml at pagkatapos ay pinatakbo ang docker compose restart, na muling gumagamit ng kasalukuyang container kasama ang orihinal nitong environment. Kailangan ng mga pagbabago sa environment ang docker compose up -d, na muling gumagawa ng container.

Bakit hindi mo ma-delete ang file na isinulat ng container

Mga numero, hindi mga pangalan, ang ikinukumpara ng kernel. Tumatakbo ang iyong shell bilang UID 1000. Pagmamay-ari ng UID 911 ang file. Ang directory na naglalaman nito ay drwxr-xr-x at pagmamay-ari rin ng 911, kaya may read at execute permission ang group at others pero walang write permission. Para mag-delete ng file, kailangan ang write permission sa directory nito, hindi sa file. Kaya lumalabas ito kahit mukhang walang problema ang file mismo:

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

Nararanasan din ng container na nagsusulat ang parehong limitasyon mula sa kabilang panig. Kung pagmamay-ari ng iyong user ang host directory at nasa mode 755 ito, habang tumatakbo ang application bilang 911, mabibigo ang unang write nito sa Permission denied at iuulat ito ng app gamit ang sarili nitong mensahe. Sa isang .NET application gaya ng Sonarr o Radarr, lalabas ito bilang UnauthorizedAccessException: Access to the path '/data/downloads' is denied. Ipinapakita ng permission string bago ang file kung alin sa tatlong permission set ang aktuwal na ginagamit para suriin ang access mo. Ang tamang pagbasa sa drwxr-xr-x ang nagpapalinaw sa error na ito.

Partikular itong problema sa bind mount. Kapag gumawa ang Docker ng empty named volume at ini-mount ito sa path na umiiral sa image, kinokopya nito sa volume ang laman ng path, kasama ang ownership at permission bits. Dahil dito, makakahanap ang application ng directory na pagmamay-ari na nito. Walang ganitong pagproseso sa bind mount: ini-mount ng Docker ang host directory nang eksakto sa kasalukuyang anyo nito. Isa ang pagkakaibang ito sa mga praktikal na dahilan para malaman kung kailan mas angkop ang bind mount kaysa named volume at kung kailan hindi.

Pag-aayos ng directory na mali na ang configuration

Binabago ng pagtatakda ng PUID at PGID ang gagawin ng application mula sa puntong iyon. Hindi nito awtomatikong inaayos ang mga file na nasa disk na. Ihinto ang stack, ikaw mismo ang mag-correct ng ownership, at pagkatapos ay simulan itong muli:

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

Gamitin ang sudo chown -R "$(id -u):$(id -g)" /srv/appdata/sonarr kung ayaw mong i-type ang mga numero. Gawin ito habang naka-stop ang container, dahil maaaring magkaroon ng bahagyang naitama lamang na directory tree at panibagong serye ng mga nakalilitong error kapag may application na kasalukuyang nagsusulat habang isinasagawa ang recursive na chown.

Ano ang hindi inaayos ng PUID at PGID

Ito ang bahaging kadalasang nagdudulot ng problema kahit tama ang lahat ng ginawa mo. Sa pagsisimula, eksaktong tatlong path ang ina-update ng linuxserver init gamit ang chown: /app, /config at /defaults. Wala sa listahang iyon ang iyong media mounts. Direktang ipinapasa sa application ang /data, /downloads at /tv nang walang pagbabago. Kaya kung ang ownership sa host side ng mga mount na iyon ay hindi maaaring sulatan ng container user, maayos na magsisimula ang container, ipapakita nito ang tamang UID sa banner, at pagkatapos ay mabibigo sa unang import.

Tamang behavior ito. Magiging problema ang recursive na chown sa isang media library na labindalawang terabyte sa bawat pagsisimula ng container. Ibig sabihin, ikaw ang kailangang mag-manage ng media directories. Ang mga mount na ito ang talagang pinagmumulan ng permission issue.

Tatlong paraan para kontrolin ang user, at kung kailan ginagamit ang bawat isa

PUID at PGID environment variable

Gumagana lamang ito sa mga image na binabasa ang mga ito ng entrypoint. Sikat ito dahil nagsisimula pa rin ang container bilang root, ginagawa nito ang sariling setup, inaayos ang /config, at saka lamang nagda-drop ng privileges. Patuloy na gumagana ang Docker Mods at mga custom init script. Ang kapalit nito ay umaasa ka sa isang convention sa halip na sa feature ng platform, at hindi standard ang mga pangalan ng variable sa lahat ng project.

Ang user: key sa Compose

Tunay na Docker feature ito at gumagana sa lahat ng image dahil inilalapat ito ng container runtime bago patakbuhin ang sariling code ng image:

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

Hindi kailanman tumatakbo bilang root ang process, kahit sandali, kaya tunay itong security gain. Ngunit sinisira rin nito ang anumang bahagi ng entrypoint na nangangailangan ng root. Sa linuxserver images, sinusuportahan ito ng project batay sa reasonable endeavours at para lamang sa mga image na nasubukan nito. Partikular ang mga caveat: wala nang epekto ang PUID at PGID, hindi tatakbo ang Docker Mods, hindi tatakbo ang mga custom service, at ikaw ang responsable sa permissions ng bawat naka-mount na volume. Ang documented pattern nila ay ginagamit ang flag kasama ng writable na /run:

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

May isang cosmetic side effect na nakapagtataka sa ilang user. Walang katumbas na entry ang numeric na user: sa /etc/passwd ng container, kaya nagrereport ang mga tool sa loob ng whoami: cannot find name for user ID 1000. Valid ang ID at normal na gumagana ang file access. Ang name lookup lamang ang nabibigo.

Rootless Docker

Pinapatakbo ng Rootless Docker ang daemon mismo bilang unprivileged user mo, kaya walang tumatakbo sa machine bilang tunay na root. Lubos nitong binabago ang ownership arithmetic. Ang container UID 0 ay mina-map sa host UID ng user na nagpapatakbo ng rootless Docker, at ang container UID n para sa anumang n na 1 o higit pa ay mina-map sa subuid + (n - 1), kung saan ang subuid ang base ng range na inilaan sa iyo sa /etc/subuid at /etc/subgid. Nangangailangan ang Docker ng hindi bababa sa 65,536 subordinate ID doon.

Basahin muli ang mapping na iyon dahil kabaligtaran ito ng karaniwang payo. Sa rootless Docker, ang container na sumusulat bilang root ay lumilikha ng mga file na pagmamay-ari mo. Ang container na sumusulat bilang UID 1000 ay lumilikha ng mga file na pagmamay-ari ng isang subordinate ID na nasa bandang 100999, na hindi maa-access ng shell mo. Kaya ang PUID value na tama sa rootful daemon ay mali rito. Parehong nilulutas ng dalawang mechanism ang parehong problema, ngunit magkaiba ang layer na ginagamit nila. Kapag pinagsama ang mga ito nang hindi sinusuri, maaaring mauwi ka sa isang directory na kailangan mo ng sudo upang maalis. Kung gagamit ka ng rootless, subukan muna ang ownership ng isang file na isinulat sa sarili mong server bago mo ilipat dito ang isang library.

Para sa karamihan ng self-hosted stack sa iisang VPS, praktikal na piliin ang PUID at PGID sa rootful daemon dahil ito ang setup na pinagbasehan ng pagkakagawa at dokumentasyon ng mga image. Gamitin ang user: kapag sinasabi ng README ng image na nasubukan ito para sa image na iyon, o kapag gumagamit ka ng official upstream image na walang PUID support. Kasama sa huling sitwasyong ito ang isang document workspace gaya ng isang self-hosted AFFiNE instance sa isang VPS, dahil wala sa mga container nito ang bumabasa ng PUID. Ang ownership ng database directory at uploaded files nito ay itinatakda ng runtime, hindi ng anuman sa environment block.

Ang media stack case: iisang group na ginagamit ng lahat ng container

Ang isang arr media stack na may Sonarr, Radarr, at download client ang aktuwal na halimbawa nito. Nagsusulat ang download client ng natapos na file sa /data/downloads. Pagkatapos, hina-hardlink o inililipat ng Sonarr ang file na iyon sa /data/media. Para gumana ang hardlink, kailangang may write access ang dalawang container sa iisang tree. Kung tumatakbo ang download client bilang 1000 habang tumatakbo ang Sonarr bilang 1001, pagmamay-ari ng isa sa kanila ang mga file na read-only lang para sa isa pa.

Ang solusyon ay isang shared group na ginagamit ng bawat container sa stack bilang PGID nito:

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 {} +

Ang nauunang 2 sa 2775 ay ang setgid bit. Sa isang directory, nangangahulugan itong mamanahin ng bawat bagong file at subdirectory na ginawa sa loob nito ang group na media sa halip na sariling primary group ng gumawa. Kaya magpapatuloy ang setup sa mga bagong download nang hindi mo kailangang muling patakbuhin ang chown. Mag-log out at mag-log in muli, o patakbuhin ang newgrp media, bago suriin ang sarili mong access. Ang group na idinagdag gamit ang usermod -aG ay hindi lumilitaw sa kasalukuyang bukas na shell session.

Sa loob ng container, nire-renumber ng groupmod -o -g 13000 abc ang abc group bilang 13000. Dahil dito, nagsusulat ang abc gamit ang parehong GID ng host media group. Pinananatili ng bawat container sa stack ang sarili nitong PUID at ginagamit nito ang iisang PGID.

Pagkatapos, itakda ang UMASK=002 sa bawat linuxserver container sa stack. Ito ang hakbang na madalas nakakaligtaan. Ang default sa mga image na ito ay UMASK=022. Inaalis nito ang group write bit sa bawat bagong file, kaya nagiging 0644 ang mga file at nawawalan ng saysay ang sharing na kak-configure mo lang. Lumilikha ang 002 ng mga file na 0664 at mga directory na 0775, kaya makakasulat ang group:

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

Ilagay ang dalawang value na iyon sa isang .env file na nasa tabi ng Compose file. Sa ganitong paraan, iisang definition ang binabasa ng buong stack:

PUID=1000
PGID=13000

Awtomatikong binabasa ng Compose ang file na iyon para sa ${PUID} style substitution. Ito rin ang mekanismong ginagamit para sa credentials. Nalalapat dito ang mga kasanayan sa paglalagay ng mga value sa labas ng docker-compose.yml at sa isang .env file. Ang kaibahan ay hindi secret ang dalawang numerong ito.

I-verify ang setup mula simula hanggang dulo sa halip na umasa lang sa configuration. Magsulat ng file mula sa loob ng isang container at basahin ito mula sa host:

docker exec sonarr touch /data/downloads/permtest
ls -ln /srv/media/downloads/permtest

Sa maayos na resulta, makikita ang iyong PUID bilang owner, 13000 bilang group, at -rw-rw-r-- bilang mode. Kung 1000 ang nababasang group, wala ang setgid bit sa directory na iyon. Kung -rw-r--r-- ang nababasang mode, hindi nag-take effect ang UMASK variable. Tiyaking ni-recreate mo ang container at hindi lang ito ni-restart. Kapag tapos ka na, alisin ang test file gamit ang rm /srv/media/downloads/permtest.

Aling images ang gumagamit ng aling variable

Ang mga linuxserver.io image ay gumagamit ng PUID, PGID at UMASK. Gumagamit ng ibang pangalan para sa parehong konsepto ang Paperless-ngx: USERMAP_UID at USERMAP_GID, na parehong may default na 1000, at sinasabi ng documentation nito na basahin ang mga ito mula sa id -u at id -g. Ipinapakita rin ng mga photo server ang parehong pagkakaiba: may sarili nitong pares na PHOTOPRISM_UID at PHOTOPRISM_GID ang PhotoPrism, samantalang walang katumbas na variable ang Immich at iniiwan nito sa Docker ang user ng container sa user: key. Kaya ang pagpili sa pagitan ng PhotoPrism at Immich ay tumutukoy rin kung alin sa mga mekanismong ito ang pananatilihin mo para sa pinakamalaking library sa server. Maraming opisyal na upstream image, kabilang ang mga karaniwang database at web server image, ang may nakapirming built-in user at inaasahang gagamit ka ng user: o hindi mo ito babaguhin. Ganoon din ang mga infrastructure na idaragdag mo sa hinaharap. Kaya ang paglalagay ng Authentik sa harap ng iyong mga app para sa iisang login ay nangangahulugang gagamit ka ng mga opisyal na server, Postgres at Redis image na walang binabasang PUID. Sa halip, ang runtime ang nagtatakda ng ownership ng kanilang volume, hindi isang entrypoint na maaari mong i-configure.

Kaya suriin ang README ng bawat image bago mong kopyahin ang environment block sa ibang project. Ipinapasa ng Docker sa anumang container ang bawat environment variable na ise-set mo, kahit walang binabasa nito sa loob. Ang PUID na walang gumagamit ay walang ibinibigay na error, warning o epekto. Tatakbo ang container bilang user na itinakda ng sarili nitong Dockerfile. Malalaman mo ito batay sa ownership ng mga file na isinusulat nito.

FAQ

Bakit pagmamay-ari ng 911:911 ang mga Docker file ko?

Ang 911 ang UID at GID ng abc user na kasama sa linuxserver.io images. Kapag nakikita mo ito, nangangahulugang nagsimula ang container nang hindi naka-set ang PUID at PGID, kaya nanatili ang built-in defaults sa init script nito. Ipinapakita ng ls -l ang raw numbers dahil walang account sa host mo na may ID na 911, kaya walang pangalan na maipapakita. Itakda ang PUID at PGID sa output ng id, muling likhain ang container gamit ang docker compose up -d, pagkatapos ay ayusin ang mga kasalukuyang file gamit ang sudo chown -R 1000:1000 sa apektadong directory.

Gumagana ba ang PUID at PGID sa lahat ng Docker image?

Hindi. Hindi ito Docker feature at hindi ito binabasa ng Docker. Gumagana lamang ang mga ito sa mga image na binabasa ng sariling entrypoint ang mga ito at tumatawag sa usermod at groupmod bago simulan ang application. Kabilang dito ang linuxserver.io family at ilang project na gumamit ng parehong pattern. Gumagamit ang ibang project ng ibang pangalan, gaya ng USERMAP_UID at USERMAP_GID sa paperless-ngx. Sa image na wala sa mga ito ang binabasa, tinatanggap at binabalewala ang mga variable nang walang warning.

Dapat ko bang gamitin ang PUID at PGID o ang user: key sa Docker Compose?

Gamitin ang PUID at PGID kapag sinusuportahan ito ng image, dahil patuloy na tumatakbo bilang root ang entrypoint nang sapat na tagal upang ayusin ang /config at simulan nang tama ang sarili nitong mga serbisyo. Gamitin ang user: kapag walang suporta sa PUID ang image, o kapag sinasabi ng README ng image na nasubukan ito para sa non-root operation. Sa linuxserver image, kapag itinakda ang user:, nagiging inert ang PUID at PGID, hindi tumatakbo ang Docker Mods at custom services, at ikaw ang responsable sa permissions ng bawat mounted volume.

Tama ang PUID ng Sonarr pero hindi pa rin nito mailipat ang mga file. Ano ang mali?

Suriin ang 3 bagay sa ganitong pagkakasunod. Una, ang media mount mismo: chown lamang ng init ang /app, /config at /defaults, kaya nananatili sa /data o /downloads ang ownership na itinakda sa host. Ikalawa, ang shared group: kung magkaiba ang GID na ginagamit ng download client at Sonarr, hindi mababago ng alinman ang mga file ng isa pa. Bigyan ang bawat container sa stack ng parehong PGID. Ikatlo, ang umask: isinusulat ng image default na UMASK=022 ang mga file bilang 0644 nang walang group write bit, kaya hindi magagamit ang shared group. Itakda ang UMASK=002 at itakda ang setgid bit sa mga directory gamit ang chmod 2775 upang mamana ng mga bagong file ang group.