Standard POSIX file permissions (owner/group/other with read/write/execute) cover most use cases, but sometimes you need finer-grained control. Access Control Lists (ACLs) extend the permission model to allow per-user and per-group permissions on individual files and directories.
Standard POSIX Permissions Review
# Permission bits: rwx (read=4, write=2, execute=1)
ls -la /var/www/
# -rw-r--r-- 1 www-data www-data 1234 Jan 15 index.html
# drwxr-x--- 2 deploy www-data 4096 Jan 15 config/
# Three permission groups:
# Owner (u): rw- (6) — file owner
# Group (g): r-- (4) — file group
# Other (o): r-- (4) — everyone else
# Common permission patterns for web servers:
chmod 644 index.html # Owner read/write, everyone else read
chmod 755 /var/www # Owner full, group/other read+execute
chmod 600 .env # Owner read/write only (secrets)
chmod 750 config/ # Owner full, group read+execute, no other
Limitations of Standard Permissions
Standard permissions only support one owner and one group per file. What if you need:
- User A has read access, User B has read/write, User C has no access
- Group X can read, Group Y can write, other groups have no access
- A deployment user needs write access without being in the web server group
This is where ACLs come in.
Access Control Lists (ACLs)
# Check if ACLs are supported (most modern filesystems support them)
mount | grep acl
# Or check fstab — most filesystems enable ACLs by default
# Install ACL tools if not present
sudo apt install acl
Viewing ACLs
# View ACLs on a file
getfacl /var/www/html/index.html
# Output:
# # file: var/www/html/index.html
# # owner: www-data
# # group: www-data
# user::rw-
# group::r--
# other::r--
Setting ACLs
# Give a specific user read/write access
setfacl -m u:deploy:rw /var/www/html/index.html
# Give a specific group read access
setfacl -m g:developers:r /var/www/html/index.html
# Verify
getfacl /var/www/html/index.html
# Now shows additional entries:
# user:deploy:rw-
# group:developers:r--
# Note: ls -la shows a + sign indicating ACLs are present
ls -la /var/www/html/index.html
# -rw-rw-r--+ 1 www-data www-data 1234 Jan 15 index.html
Recursive ACLs
# Apply ACLs to all files in a directory
setfacl -R -m u:deploy:rwx /var/www/html/
# Set default ACLs (applied to new files created in the directory)
setfacl -d -m u:deploy:rwx /var/www/html/
setfacl -d -m g:developers:rx /var/www/html/
# View default ACLs
getfacl /var/www/html/
# Shows "default:" entries for new files
Removing ACLs
# Remove a specific ACL entry
setfacl -x u:deploy /var/www/html/index.html
# Remove all ACLs (revert to standard permissions)
setfacl -b /var/www/html/index.html
# Remove default ACLs from a directory
setfacl -k /var/www/html/
Practical Examples
Web Development Team Setup
# Scenario: www-data owns files, deploy user needs write access,
# developers group needs read access
# Set base permissions
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
# Add ACLs for deploy user
setfacl -R -m u:deploy:rwx /var/www/html
setfacl -d -m u:deploy:rwx /var/www/html
# Add ACLs for developers group
setfacl -R -m g:developers:rx /var/www/html
setfacl -d -m g:developers:rx /var/www/html
Shared Log Directory
# Multiple services write to /var/log/myapp
sudo mkdir /var/log/myapp
sudo chown root:root /var/log/myapp
sudo chmod 750 /var/log/myapp
# Give specific services write access
sudo setfacl -m u:www-data:rwx /var/log/myapp
sudo setfacl -m u:mysql:rwx /var/log/myapp
sudo setfacl -m g:monitoring:rx /var/log/myapp
# Set defaults for new log files
sudo setfacl -d -m u:www-data:rw /var/log/myapp
sudo setfacl -d -m g:monitoring:r /var/log/myapp
ACL Mask
# The mask limits the maximum permissions for ACL entries
setfacl -m m::rx /var/www/html/
# Even if deploy has rwx ACL, effective permissions are limited to rx
# View effective permissions
getfacl /var/www/html/index.html
# user:deploy:rwx #effective:r-x ← masked!
When to Use ACLs vs Standard Permissions
- Use standard permissions when owner/group/other is sufficient (most cases)
- Use ACLs when you need per-user or multi-group permissions
- Combine both — Standard permissions as the base, ACLs for exceptions
- Document ACLs — They are invisible in normal ls output; document them for your team