Early in my sysadmin career, I ran into a frustrating situation: I needed the deploy user to read application logs, but the files were owned by www-data, and I didn’t want to add deploy to the www-data group for security reasons. Use chmod 644? Not an option, because other users weren’t supposed to read those files either. This is exactly where ACL (Access Control List) steps in to solve problems that chmod/chown simply can’t handle.
We still have a few servers running CentOS 7, and migrating them to AlmaLinux is something I’ve dealt with firsthand. Every migration, ACL is one of the first things to verify — standard rsync doesn’t preserve ACLs, and that can cause permission errors that are surprisingly hard to debug after the move.
What Is ACL and Why Do You Need It?
Traditional Linux permissions only recognize three entities: owner, group, and others. Simple, but not flexible enough as the number of users grows in an enterprise environment.
ACL lets you assign permissions to any specific user or group, independent of the file’s current owner or group. The system still runs standard POSIX permissions — ACL is simply an additional layer on top.
Some real-world scenarios where ACL is the right tool:
- The
/var/www/htmldirectory needs read/write access for the frontend team, but not for the entirewheelgroup - Log files need to be readable by a monitoring agent without exposing them to other users
- A shared project directory requires different permission levels for devs, QA, and PMs
Core Concepts to Understand
Two Main Tools
getfacl— view the current ACL of a file or directorysetfacl— set ACL entries
What Is the Mask?
The mask defines the maximum permissions that named users, named groups, or the owning group can have. It does not affect the owner or others. When you run chmod on a file with ACL entries, it updates the mask rather than removing the ACL — this is a common point of confusion for newcomers.
Hands-On: Step-by-Step ACL Management on CentOS Stream 9
Step 1: Install and Verify ACL Support
On CentOS Stream 9, XFS (the default filesystem) has ACL support enabled by default. You just need to install the acl package:
sudo dnf install acl -y
# Confirm the installation
getfacl --version
To verify the filesystem is mounted with ACL support:
mount | grep -E "^/dev"
# XFS typically doesn't show 'acl' because it's enabled by default
Step 2: View the Current ACL of a File
# Create a test environment
mkdir -p /tmp/acl-demo
touch /tmp/acl-demo/testfile.txt
# View the ACL
getfacl /tmp/acl-demo/testfile.txt
Output when no extended ACL is set:
# file: tmp/acl-demo/testfile.txt
# owner: root
# group: root
user::rw-
group::r--
other::r--
Step 3: Add ACL Entries for Specific Users and Groups
# Syntax: setfacl -m u:<username>:<permissions> <file>
sudo setfacl -m u:alice:rw /tmp/acl-demo/testfile.txt
# Add an entry for a group
sudo setfacl -m g:developers:r /tmp/acl-demo/testfile.txt
# Check the result
getfacl /tmp/acl-demo/testfile.txt
Output after adding ACL entries:
# file: tmp/acl-demo/testfile.txt
# owner: root
# group: root
user::rw-
user:alice:rw-
group::r--
group:developers:r--
mask::rw-
other::r--
A + sign will appear when running ls -la: -rw-rw-r--+ — this is a quick way to spot files with ACL entries without having to run getfacl.
Step 4: Default ACL — The Most Useful Feature
Default ACL is what I use most in practice: new files created inside a directory automatically inherit its ACL, so you don’t have to set permissions every time.
mkdir /tmp/acl-demo/shared
# The -d flag sets a default ACL
sudo setfacl -d -m u:alice:rwx /tmp/acl-demo/shared
sudo setfacl -d -m g:developers:rx /tmp/acl-demo/shared
# View the configuration
getfacl /tmp/acl-demo/shared
The default: section in the output will automatically apply to any new files and subdirectories created inside.
Step 5: Apply ACL Recursively
# -R = recursive
sudo setfacl -R -m u:alice:rx /var/www/html
# Combine recursive + default to cover the entire directory tree and future files
sudo setfacl -R -d -m u:alice:rx /var/www/html
Step 6: Remove ACL Entries
# Remove the ACL entry for a specific user
sudo setfacl -x u:alice /tmp/acl-demo/testfile.txt
# Remove all extended ACL entries (keep only basic POSIX permissions)
sudo setfacl -b /tmp/acl-demo/testfile.txt
# Remove the default ACL from a directory
sudo setfacl -k /tmp/acl-demo/shared
Real-World Example: Multi-Team Development Environment
Suppose you have a directory /opt/webapp with the following permission requirements:
- User
deploy: full read/write/execute access - Group
dev: read/write access to code, no arbitrary script execution - Group
qa: read-only access - User
monitor: read-only access to thelogsdirectory
# Set permissions on the root directory
sudo setfacl -R -m u:deploy:rwx /opt/webapp
sudo setfacl -R -m g:dev:rw /opt/webapp
sudo setfacl -R -m g:qa:r /opt/webapp
# Set separate permissions for the logs directory
sudo setfacl -R -m u:monitor:rx /opt/webapp/logs
# Set default ACL so new files inherit permissions
sudo setfacl -d -m u:deploy:rwx /opt/webapp
sudo setfacl -d -m g:dev:rw /opt/webapp
sudo setfacl -d -m g:qa:r /opt/webapp
# Verify the full configuration
getfacl /opt/webapp
ls -la /opt/webapp
Backing Up and Restoring ACL During Server Migration
I learned this lesson the hard way during a CentOS 7 to AlmaLinux migration — after the rsync, several services failed because their ACL entries were gone. Since then, I always back up ACLs before any migration:
# Back up all ACL entries under /var/www
getfacl -R /var/www > /backup/www-acl-backup.txt
# Restore from backup
setfacl --restore=/backup/www-acl-backup.txt
# Use rsync with the -A flag to preserve ACLs
rsync -aAX /source/ /destination/
If you rely on rsync for real-time file synchronization, make sure the -A flag is part of your sync command — otherwise ACL entries will silently disappear on the destination.
Conclusion
ACL doesn’t replace chmod/chown — it complements them by adding a layer of control when traditional POSIX permissions aren’t flexible enough. Use ACL when:
- You need to grant permissions to multiple users or groups on the same file without changing ownership
- You want new files in a directory to automatically inherit permissions via default ACL
- You’re working in a multi-team environment with overlapping permission requirements
If you’re managing a CentOS Stream 9 or AlmaLinux server, run getfacl to check whether any ACL entries are already active on the system — previous administrators sometimes leave ACL configurations undocumented, and those can be the hidden cause of permission errors that seem impossible to explain. Pairing ACL audits with Linux auditd for security event monitoring gives you a complete picture of who is accessing which files and when.

