Practical tools for system, network, security, and operations administrators.

SYS-C0001 · Linux Users & Permissions

Linux File Permissions Explained

Read Linux modes, umask, and ownership, then set a directory tree without chmod 777.

Updated 25 October 2026 · Pillar guide

This is an original planning guide. It is not a vendor manual, an official standard, or legal advice. Example addresses use documentation ranges. Review every command before you paste it.

What a mode actually says

A Linux mode is three decisions: who owns the file, which group owns it, and what the owner, the group, and everyone else may do. chmod changes the last of those. chown changes the first two. A mode of 644 with the wrong owner is still the wrong file. Read ls -l as owner, group, then the nine letters, and only then as an octal number.

The nine letters are read, write, and execute, repeated for owner, group, and other. Execute on a file means the kernel may run it. Execute on a directory means a person may enter it and reach a file whose name they already know. Write on a directory means they may create or delete names inside it, even when they cannot write the files themselves. That is why a sticky bit on /tmp matters, and why a group-writable directory without a plan becomes a shared scratch space you did not mean to publish.

Umask is the mask subtracted when a program creates a file. A umask of 022 turns a program's request for 666 into 644 for a file and a request for 777 into 755 for a directory. A umask of 027 keeps the new file off the world and leaves it readable by the group. The umask is a property of the process, not of the directory. A service that starts with a different umask will not match the files you created from your shell.

Special bits are separate from the nine letters. Setuid and setgid on an executable run it with the file owner's authority. Setgid on a directory makes new files inherit the directory's group. The sticky bit on a directory limits deletion to the owner of the name. You almost never need a new setuid program. If a vendor binary already has the bit, leave it alone and do not copy that bit onto a script you just wrote.

A web root that is readable and not writable by the world

The lab tree is /srv/www/edge on a host you can rebuild. The owner is root. The group is web. Directories are 755. Files are 644. The service account is in the group web only if it must read files the world must not see. A public site does not need that. 755 and 644 already let the web server read the tree when the server runs as a user that is not the owner, because other has read and, on directories, execute.

Create the directory as root, set the group, then set the modes. Check with ls -ld and with one file, not with a recursive listing you will not read. If the application must write uploads, give it one directory, such as /srv/www/edge/uploads, owned by the service account, mode 750, and do not make the rest of the tree writable. The uploads directory is the exception you can point at. The whole tree being writable is the incident.

A umask of 022 on the admin shell produces 644 and 755, which matches this tree. A deploy user whose umask is 077 will create files the web server cannot read. Fix the deploy user's umask or the deploy tool's mode, then correct the files that were already created. Do not open the tree to the world to hide a umask mismatch.

The chmod calculator and the ls -l decoder on this site turn 644 into rw-r--r-- and the reverse. The umask calculator shows what a new file becomes. They do not change the host. Paste a result into the ticket, then run the command yourself and read the listing back.

ModeLettersUse it for
644rw-r--r--Ordinary files the world may read
755rwxr-xr-xDirectories and programs the world may enter or run
640rw-r-----Files only the owner and group may read
750rwxr-x---Directories only the owner and group may enter
600rw-------A key or a secret file
700rwx------A private directory, such as a home directory or .ssh
# Review before you paste. Lab tree only.
# Do not chmod 777. Do not setuid a script.
ls -ld /srv/www/edge
# want: drwxr-xr-x root web
umask
# 0022 matches 644 files and 755 directories

A change you can finish

Write the path, the owner, the group, and the mode in the ticket before the window. If any of those four are blank, you are not ready to type chmod. Include the umask of the account that creates new files, because tomorrow's deploy will not remember today's chmod.

Change one tree. Read it back. Fetch one page or open one file as the service account, not as root. Root can read a mode that the service cannot, so a test as root does not prove the site works.

  1. Name the path and confirm it is the tree you mean, not a parent that contains other sites.
  2. Record the current owner, group, and mode with ls -ld.
  3. Set the owner and group, then the mode, and read both back.
  4. Confirm a new file created by the deploy account lands on the mode you wrote down.
  5. Open the file as the service account, or fetch the page, and keep that result.
  6. Leave uploads, keys, and sockets on their own lines in the ticket if they differ.
  7. Do not recurse over a tree you have not listed when the tree contains a secret or a socket.

Mistakes that outlive the command

Linux file permissions fails in the same few ways. Each one looks finished on the day you type it. The list is here so the ticket can forbid them before the window, not so you can recognise them in an incident review.

Decisions to write down before the window

One decision for Linux file permissions: Public files are 644 and public directories are 755 unless the ticket names a tighter mode. 777 is not a temporary state you will remember to undo. The web tree owner is root and the group is web. The service account writes only in the uploads directory the ticket names. Secrets are 600 and owned by the account that reads them. A backup of a secret keeps that mode. A world-readable copy in /tmp is a new secret incident. The deploy account's umask is 022 for this public tree, or 027 if the tree is group-readable and not world-readable. Setgid on a shared directory is a choice you make so new files inherit the group. You do not set it on a home directory to be tidy. Setuid stays on the vendor binaries that already have it. A script you wrote does not get the bit. If a job needs another user's files, give the job a user that already may read them. ACLs are a second layer. Use them when a mode cannot say the thing, and record the getfacl output in the ticket. Do not add an ACL and also chmod 777. A recursive change lists the top of the tree and excludes secrets, sockets, and other mount points. If you cannot list the exclusion, you do not recurse. The service account is not a member of every group because that was faster. Membership is a line in the ticket with a reason. And the rollback is the owner, group, and mode you recorded, applied to the same path. It is not a second recursive chmod from memory.

Permission checks before you leave the window

Confirm this before you call the change done: ls -ld on the tree matches the ticket's owner, group, and mode. A sample file is 644, or the tighter mode the ticket named. The uploads directory, if it exists, is the only writable exception and is not 777. A private key on this host is 600 and owned by the account that uses it. umask of the deploy account matches the decision. A file created after the change received the expected mode without a follow-up chmod. The service account can read the public file. Root was not the account you tested with. No setuid bit was added to a script or a path you created today. getfacl is empty of surprises, or the ACL is pasted into the ticket. The previous mode is written down so the rollback does not depend on memory. The change did not walk above the path in the ticket. A second person read the path aloud before a recursive command ran. The hostname in the prompt matches the hostname in the ticket for Linux file permissions. The result line includes the time and the person, not only the command. You can point at the rollback value without searching a chat history. And done is a sentence a second person can repeat: the proof for Linux file permissions happened, and the next host is not started early. If one of those fails, stop.

Tools for this guide

These tools run in the browser on this site. They do not log into your machines.

Guides in this cluster

These supporting pages belong to this pillar.

Companion: Security: Linux Server Hardening Checklist.