3v-Hosting Blog

Configuring ACLs in Linux

Administration

9 min read


In the previous article, we discussed how file and directory access permissions work in Linux, what the chmod and chown commands are used for, and how to manage read, write, and execute permissions. In most cases, the standard model - where each file has an owner, a group, and a set of permissions for other users - is sufficient.

But what if multiple users are working with a single directory and need different levels of access? For example, a developer should be able to edit website files, a backup system should only be able to read them, and other users shouldn’t be able to see the directory’s contents at all. Solving this problem using the standard Linux tools described in the previous article can be quite difficult - or, more accurately, inconvenient - especially if changing the owner or group composition is undesirable for one reason or another.

For situations like this, Linux provides ACLs (Access Control Lists). They allow you to assign individual permissions to users and groups while preserving the existing owners of files and directories.

In this article, we’ll walk through how to configure ACLs and set up permission inheritance for new files, as well as explore how to verify exactly which permissions a user has actually been granted.

 

 

 

 

What Are ACLs and How Do They Differ from chmod

Standard permissions for files and directories in Linux use the designations r (read), w (write), and x (execute). These are assigned to the file owner, its group, and other users.

For example, if we run the following command, specifying any directory:

ls -ld /var/www/project

, we’ll see a result similar to this:

drwxr-x--- 2 www-data www-data 4096 Oct 20 12:00 /var/www/project

In this example, we can see that the directory is owned by the system user www-data. This user has full access to the directory, the group can read the directory’s contents, and other users have no access at all.

 

Now let’s assume that a developer with the username developer needs to be granted access to edit the files in this project. Of course, we could add them to the www-data group, but then they would also receive group permissions for other objects where that group is used.

ACLs, however, allow us to grant permissions directly to the user developer and directly on the target directory or file.

Below, we’ve compiled a clear table showing the differences between chmod/chown and the ACL tool.

Feature

chmod/chown

ACL

Owner and primary group permissions

Yes

Yes

Individual permissions for other users

No

Yes

Permissions for additional groups

No

Yes

Permission inheritance

No

Yes

Permission restrictions through a mask

No

Yes

It turns out that ACLs complement standard Linux permissions, and both mechanisms work together. Therefore, changing permissions via chmod can affect ACLs - something you need to be prepared for and always keep in mind.

 

 

 

 

Installing ACLs in Linux

In modern ext4 and XFS file systems, which run on most servers and workstations, POSIX ACL support is usually enabled by default. To manage permissions, you need the setfacl and getfacl utilities.

In Debian and Ubuntu, run the following commands to install them:

sudo apt update
sudo apt install acl

 

In Rocky Linux and AlmaLinux:

sudo dnf install acl

 

To check if the utility is present on your system, run the following command:

getfacl --version

If this command runs and returns a result, the tools are installed. However, it’s best to verify ACL support in the file system itself separately, especially if the files are located on network storage.

 

 

 

 

How to View and Change ACL Permissions

Let’s create a directory and set restricted access for it:

sudo mkdir -p /srv/shared
sudo chmod 750 /srv/shared

 

Now let’s view the current permissions for this directory using the utility we installed earlier:

getfacl /srv/shared

Sample output:

# file: srv/shared
# owner: root
# group: root
user::rwx
group::r-x
other::---

 

Here we see standard Linux permissions, and there are no additional entries yet.

 

Assigning Permissions to a User

Now it’s time to grant additional permissions. Suppose the user developer needs full access to the directory. In that case, we need to add the corresponding entry:

sudo setfacl -m u:developer:rwx /srv/shared

In this command, the -m parameter modifies the ACL, u:developer specifies the user, and rwx sets the permissions.

 

After that, let’s check what has changed:

getfacl /srv/shared
user::rwx
user:developer:rwx
group::r-x
mask::rwx
other::---

We can see that now the user with the login developer can view the directory’s contents and create files in it. Note, however, that permissions on the directory itself do not automatically grant access to edit all files inside it.

 

Let’s check whether our user can create a file by running the following command on their behalf:

sudo -u developer touch /srv/shared/test.txt

If there are no errors, it means the permissions are working.

 

Assigning Permissions to a Group

As we recall, we have a group backup that needs read-only access to create backups. To grant these permissions, we use a similar command, but instead of specifying the user u:developer, we specify the group g:backup:

sudo setfacl -m g:backup:rx /srv/shared

 

If this permission needs to be applied to the entire existing directory tree, then we use the -R option :

sudo setfacl -R -m g:backup:rX /srv/shared

 

The uppercase X in the setfacl command works slightly differently than the lowercase x. It grants execute permission to all directories, and to regular files only if they already have execute permission for at least one user group.

For directories, the x permission is necessary so that a user can enter them and access the files inside.

 

However, for regular files, such as .txt, .html, or .jpg, this permission is usually not required.

Therefore, when configuring ACLs recursively, it is more convenient to use X: this ensures that directories receive the necessary access rights, existing executable scripts remain executable, and regular files do not accidentally become executable.

 

 

 

 

Inheriting Permissions via Default ACLs

Standard ACLs apply to specific files and directories. But if, for example, a new file appears tomorrow in the /srv/shared directory, the developer user might not have access to it.

To solve this problem, there are so-called Default ACLs - inherited permissions. They are set using the command we’re already familiar with, but with the -d option:

sudo setfacl -d -m u:developer:rwx /srv/shared

Now, new files created inside our directory, as well as its subdirectories, will inherit the entry created for the developer user.

 

You can verify the inheritance settings with the following command:

getfacl -d /srv/shared

Example:

default:user::rwx
default:user:developer:rwx
default:group::r-x
default:mask::rwx
default:other::---

 

However, ACL inheritance has several peculiarities. Suppose we’ve configured the developer user with rwx permissions by default:

sudo setfacl -d -m u:developer:rwx /srv/shared

Obviously, all new files and subdirectories within /srv/shared will now inherit this entry. However, the actual permissions depend on the type of object being created.

For example, when a program creates a regular text file, it most often requests permissions 0666 - read and write for all user categories, without execute permission. Therefore, even if rwx is present in the Default ACL, the developer user will only receive rw- for such a file.

The situation is different with directories. They are usually created with the requested permissions 0777, which include execute permissions, so a new subdirectory can inherit the full set of rwx permissions.

 

What is umask and how is it related to ACLs

In Linux, there is another mechanism for managing permissions - umask (user file-creation mode mask). This is a mask that restricts access permissions when creating new files and directories.

By default, programs typically request permissions of 0666 for files and 0777 for directories. However, granting all these permissions to every user is insecure, so Linux applies the umask, which removes certain access bits.

You can view the current mask using the command:

umask

For example, if the result is 0022, new objects will typically be granted the following permissions:

Object

Requested Permissions

umask

Final Permissions

File

0666

0022

0644 (rw-r--r--)

Directory

0777

0022

0755 (rwxr-xr-x)

In other words, the file owner can read and modify it, while other users can only read it. For directories, the ability to enter the directory is additionally preserved.

 

You might ask, how does this relate to Default ACL? We’ll explain.

If the parent directory has Default ACLs configured, Linux uses inherited rules and the mode requested by the program. The usual umask is not applied separately in this case.

Therefore, a file created in a directory with Default ACLs may have broader permissions than the usual 0644. It all depends on the configured inheritance rules and the creation mode.

And one last detail you shouldn’t forget: Default ACLs apply only to new objects. Existing files retain their original permissions, so to change them, you’ll need the standard command setfacl -m, with the -R option for recursive configuration if necessary.

 

 

 

 

ACL Mask and Effective Permissions

Earlier, we discussed umask, which limits permissions when creating new files and directories. But ACLs also have their own mask - mask - which works differently.

The ACL mask defines the maximum permissions that users and groups can receive through ACL entries. It affects actual access to existing files and directories, not just the permissions set at creation.

For example, the user developer has been assigned rwx permissions, but for some reason, they cannot modify the file. Let’s check the ACL:

user:developer:rwx       #effective:r-x
mask::r-x

Here, the entry user:developer:rwx grants read, write, and execute permissions. However, the mask mask::r-x denies write access, so the user’s actual (effective) permissions are limited to r-x. This is exactly what the comment #effective indicates.

 

The ACL mask applies to additional user entries, the file’s primary group, and additional groups. It does not apply to the file owner (user::) or other users (other::).

 

You can change the mask using the command:

sudo setfacl -m m::rwx /srv/shared

After that, the mask will grant all rwx permissions, but each user will still be limited by the permissions of their own ACL entry.

However, there is a caveat here as well. Expanding the mask can simultaneously increase the actual permissions of multiple users and groups. Therefore, it’s best to review the entire list using getfacl before making any changes.

 

Another difference from umask relates to the chmod command. If a file has extended ACLs configured, changing group permissions via chmod typically modifies the ACL mask itself. For example:

sudo chmod g-w /srv/shared

This command will remove write permission from the directory’s ACL mask if it has extended ACLs. As a result, users who were previously allowed to write via ACLs may lose that ability.

 

You can check the final permissions with the command:

getfacl /srv/shared

So, let’s summarize: umask limits permissions when creating objects, while the ACL mask (mask) limits the effective permissions granted by ACL entries.

 

 

 

 

Removing ACLs and Backing Up

You can remove a specific user’s permissions using the command:

sudo setfacl -x u:developer /srv/shared

 

To remove additional ACL entries, use:

sudo setfacl -b /srv/shared

 

To remove all inherited Default ACL rules:

sudo setfacl -k /srv/shared

 

In fact, before making any bulk changes to ACLs, we can protect against errors by saving the current ACLs - for example, to a plain text file acl-backup.txt - using the command:

sudo getfacl -R -p /srv/shared > acl-backup.txt

 

Restoring from this file is even easier:

sudo setfacl --restore=acl-backup.txt

 

The backup file contains the original paths, so before restoring, make sure they match the correct directories.

 

 

 

 

How to Preserve ACLs When Transferring Files

Unfortunately, additional permissions may be lost when copying files. Therefore, when transferring files - for example, using rsync - use the -A option:

sudo rsync -aA /var/www/project/ /backup/project/

In this example, the -aoption preserves the basic file attributes, while the -Aoption preserves the ACL lists.

 

If you need to preserve extended file system attributes, add the -Xoption:

sudo rsync -aAX /var/www/project/ /backup/project/

Both the source and destination must support these attributes. After transferring the files, check their permissions using the getfacl command, which we’re already familiar with.

 

 

 

 

Why ACLs Might Not Work

Even if the setfacl command is executed without errors, the user does not always gain the expected access to files or directories. The reason may lie, for example, in the ACL mask, insufficient permissions on parent directories, or file system-specific characteristics. Sometimes access is blocked by additional security mechanisms, such as SELinux or AppArmor.

Let’s break down the most common problems you might encounter when configuring ACLs and how to diagnose them, but only in a clear, tabular format:

Problem

Possible Cause

Check

Permission denied

Insufficient effective permissions

getfacl

Cannot access directory

Missing x permission on the path

namei -l

Operation not supported

ACL not supported

findmnt -T /path

Permissions are restricted

ACL mask

getfacl

New files have incorrect permissions

Incorrect Default ACL configuration

getfacl -d

ACL lost after migration

File attributes were not preserved

Copy options

 

Check SELinux or AppArmor separately if they are enabled on your server, as these mechanisms may deny access even with correct ACLs.

There is also a quirk when moving files within the same filesystem. In this case, the file usually retains its original ACLs, and the inherited permissions from the destination directory are not reapplied.

 

 

 

In summary, we’ve found that ACLs are a very useful tool for managing servers where multiple users or services access the same files but require different permissions.

However, if all users have the same privileges, then it’s certainly easier to use a standard Linux group.

As for day-to-day ACL management, you’ll only need two commands: the getfacl command, which displays existing permissions, and the setfacl command, which modifies them.

Most importantly, when working with ACLs, you should always check effective permissions, configure inheritance carefully, and preserve ACLs when transferring data.

3v-Hosting Team

Author

3v-Hosting Team

The 3v-Hosting Team is made up of a dedicated group of engineers and operators who are all about building and maintaining the backbone of our services. Every day, we dive into the world of virtual and dedicated servers, handling everything from deployment and monitoring to troubleshooting real-world issues that pop up in production environments. Most of our articles stem from hands-on experience rather than just theory. We share insights on the challenges we face: performance hiccups, configuration missteps, networking intricacies, and architectural choices that impact stability and reliability. Our mission is straightforward – we want to share knowledge that empowers you to manage your projects with fewer surprises and a lot more predictability.

How to Check File Permissions in Linux
How to Check File Permissions in Linux

How to Check File and Directory Permissions in Linux. We'll explore the ls, stat, chmod, and chown commands, the causes of the "Permission denied" error, and wa...

8 min