Samba File Server With POSIX ACLs in a Docker Container
This article explains how to set up a Samba file server as an Active Directory domain member in a Docker container. This newer configuration differs from my earlier setup in one essential point: it uses POSIX instead of Windows ACLs, simplifying the administration and making it possible to modify files via other protocols than SMB. This post is part of my series on home automation, networking & self-hosting that shows how to install, configure, and run a home server with dockerized or virtualized services.
This article is part of a mini-series about running Samba Active Directory and a file server service in a Docker container on a home server:
- Samba Active Directory in a Docker Container: Installation Guide
- Samba Active Directory as Authelia’s Authentication Backend
- Samba File Server With Windows ACLs in a Docker Container
- Samba File Server With POSIX ACLs in a Docker Container (this article)
- Web Access Through Filebrowser With SSO & HTTPS
- Web Access Through Filestash With Passthrough Auth
- GitHub repository with Docker files and helper scripts
Please read the previous articles of this mini-series before proceeding.
Planning
Why Not Windows ACLs?
In my initial implementation, I went to great lengths to configure ACL support that is fully compatible with Windows’ nuanced file system permission feature set. Using Windows ACLs on Linux does have a significant downside, though, that may or may not affect you: you can only ever provide write access to your files via SMB, never via an alternative protocol such as SFTP. This is because the Windows ACLs are maintained in extended file system attributes by Samba. If you create a new file on the Linux console, bypassing Samba, your file won’t have the necessary ACL info and, therefore, not be visible to Windows clients.
Another drawback of using Windows ACLs on Linux is that administration is quite complex and, therefore, error-prone. A well-architected solution should be easy to maintain.
As I realized belatedly, I don’t really need full Windows ACL support. I do, however, want to be flexible in how I can access my files and not be limited to SMB. Alternative file access methods like SFTP or a browser-based UI are high on my wish list. So I decided to rethink my file system permission strategy.
Traditional Unix UGO Permissions or POSIX ACLs?
Traditional Unix user/group/other (UGO) permissions have one significant limitation that affects almost every use case: you cannot grant different types of access to multiple groups. A common scenario where you’d want to do just that is a structure where you have one group that grants read+write permissions on a directory whereas another group only grants read permissions.
Such a structure is simple and versatile but, unfortunately, cannot be implemented with Unix UGO permissions because UGO only supports a single group. To bypass that limitation, we can turn to POSIX ACLs.
POSIX ACLs allow us to grant permissions to multiple groups as well as specify default permissions that apply to new files and directories. Exactly what is needed for most real-world use cases.
POSIX ACLs
POSIX vs. NFSv4 ACLs
POSIX ACLs are somewhat simplistic in nature. Other than NFSv4 ACLs, they cannot be used to mirror Windows ACLs in full fidelity but that isn’t necessary as long as we manage our permissions on Linux and refrain from using more exotic Windows ACL features (such as deny ACEs, which shouldn’t be used anyway).
As we’re using Linux, we’re limited to POSIX ACLs anyway, as Linux doesn’t come with NFSv4 ACLs.
Samba and POSIX ACLs
Samba supports POSIX ACLs and should apply them automatically. Frustratingly, that initially wasn’t the case. Only when I updated the container image to the August 2025 patch state of Ubuntu 24.04 and Samba 4.19.5 did POSIX ACLs work via SMB.
Contrary to popular belief, it’s not necessary to enable the acl_xattr
VFS module in order to use POSIX ACLs with Samba.
Dockerized Samba File Server Installation
If you followed my Samba Active Directory domain controller installation guide, you already have a Samba file server in a Docker container. The only thing left to do is configure it.
Supervisord Config File supervisord.conf
Create config-fs1/supervisor/supervisord.conf
with the following content:
[supervisord]
nodaemon=true
user=root
logfile=/dev/null
logfile_maxbytes=0
[program:smbd]
command=smbd --foreground --no-process-group --debug-stdout
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
startretries=1
autorestart=false
[program:winbindd]
command=winbindd --foreground --no-process-group --debug-stdout
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
startretries=1
autorestart=false
Start the Fileserver Container
Verify that when you start the Samba containers you see the following when you inspect the logs with docker compose logs fs1
:
No Samba config file found at: /etc/samba/config/smb.conf
Please exec into the container and join a domain by running the following commands:
docker exec -it samba bash
/usr/helpers/samba-join.sh
Domain Join
Exec into the FS container and run the domain join script:
docker exec -it fs1 bash
/usr/helpers/samba-join.sh
After the file server has joined the domain, restart the FS container to give my init script the chance to do its magic at container start:
docker compose stop fs1
docker compose start fs1
Inspect the container logs for errors with the command docker compose logs fs1
. You should see the following:
INFO Set uid to user 0 succeeded
INFO supervisord started with pid 7
INFO spawned: 'smbd' with pid 11
INFO spawned: 'winbindd' with pid 12
smbd version 4.19.5-Ubuntu started.
Copyright Andrew Tridgell and the Samba Team 1992-2023
winbindd version 4.19.5-Ubuntu started.
Copyright Andrew Tridgell and the Samba Team 1992-2023
INFO success: smbd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
INFO success: winbindd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Verification
Test Samba Configuration
Test the Samba config file by running testparm
.
DNS Record
Make sure that the file server’s name can be resolved on other machines on the network:
host fs1.ad.internal
Winbindd
Run the following commands to verify that Winbindd is able to connect to the AD DC:
wbinfo --ping-dc
# Expected output: checking the NETLOGON for domain[AD] dc connection to "dc1.ad.internal" succeeded
wbinfo -u
# Expected output: [list of users in the domain]
wbinfo -g
# Expected output: [list of groups in the domain]
wbinfo -i administrator
# Expected output: [passwd entry for administrator]
getent passwd administrator
# Expected output: [passwd entry for administrator]
getent group "AD\Domain Users"
# Expected output: domain users:x:10513:
Re-Join
Before you can re-join a machine to AD you need to delete its DNS record or dynamic DNS updates will fail because only the previous machine SID has permissions to update the existing record.
Run the following on the DC:
# Usage
samba-tool dns delete <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>
# Example
samba-tool dns delete localhost ad.internal fs1 A 192.168.0.6 -U administrator
Group Membership Structure
We’ll use a simple but flexible group structure to assign permissions to individual areas on the file server.
Working With Samba AD Groups
- Create and modify groups on the DC.
- Nested AD groups work correctly with POSIX ACLs.
- After making group membership changes, the file server container needs to be stopped and restarted.
Directory Structure
/srv/samba/data/ <<-- top-level directory (shared folder)
├── Family-Data/ <<-- second-level directory in shared folder
├── Pictures/ <<-- second-level directory in shared folder
└── Videos/ <<-- second-level directory in shared folder
Groups for Directory Permissions
- For each second-level directory we assign one group read+write permissions and another only read permissions, e.g.:
FS_Data_Pictures_RW
: read+writeFS_Data_Pictures_R
: read
- One “global” group to provide access to everything:
FS_Data_RW
Group Membersip
Add the global group to each second-level directory group as member, e.g.:
# Read+write
samba-tool group addmembers FS_Data_Pictures_RW FS_Data_RW
# Read only
samba-tool group addmembers FS_Data_Pictures_R FS_Data_R
Add users to the global group or to individual directory groups as needed, e.g.:
samba-tool group addmembers FS_Data_Pictures_RW userA
File Shares
Create a File Share
- Create a directory in the file system:
mkdir /srv/samba/data
- Add the share definition as a new stanza to
config/smb.conf
:
[Data]
path = /srv/samba/data
read only = no
inherit acls = yes
inherit owner = yes
- Reload the Samba configuration:
smbcontrol all reload-config
Set Unix UGO Permissions
# Change the owner and group to root
chown -R root:root /srv/samba/data
# Full access for root
chmod -R 770 /srv/samba/data
Set POSIX ACLs
Top-Level Directory
# Read permissions for everybody
setfacl -m group:"Domain Users":r-x /srv/samba/data
Second-Level Directory
# Read and read+write permissions for R and RW groups, respectively
setfacl -R -m group:"FS_Data_Pictures_RW":rwx,group:"FS_Data_Pictures_R":r-x /srv/samba/data/Pictures
# Default permissions for new files/directories: same command but with "-d"
setfacl -R -d -m group:"FS_Data_Pictures_RW":rwx,group:"FS_Data_Pictures_R":r-x /srv/samba/data/Pictures
Map (Mount) a File Share From Windows
To map a Samba file share on a Windows machine it’s not necessary for the Windows machine to be joined to the Samba domain. Run the following command to map the Data
share on any Windows PC connected to the same network:
# When prompted, enter:
# 1) The user name in the format: ad.internal\USERNAME
# 2) The user's password
# Optionally replace S: with a different drive letter
net use s: \\fs1.ad.internal\data /savecred /p:yes
Note: The password is stored securely in Windows Credential Manager (open GUI with control keymgr.dll
). The stored credentials persist reboots; they are automatically re-used when the network drive is being re-connected.
Additional Features & Optimizations
Recycle Bin
Samba comes with a recycle bin feature that moves files to a .recycle
directory instead of deleting them. This feature is independent of the Windows File Explorer recycle bin.
Notes
- With Samba’s recycle bin enabled, there is no way to “really” delete files (e.g., with
Shift+Del
) without moving them to the.recycle
directory. - Just like the Windows original, Samba’s recycle bin is not emptied automatically.
- The
.recycle
directory is created with thehidden
attribute so that’s it’s not visible in Windows File Explorer by default.
Enable Recycle Bin
To enable Samba’s recycle bin, add the following lines to a share configuration in smb.conf
:
# VFS modules (make sure to include all modules - this is not cumulative to a global definition but replaces it instead)
vfs objects = recycle
# Recycle bin configuration
recycle:directory_mode = 775
recycle:keeptree = yes
recycle:versions = yes
Set Permissions
- Directories:
- Apparently, recycle bin directories are created in the context of the user deleting a file.
- If the user who’s deleting a file doesn’t have write permissions on the recycle bin directories, files aren’t moved to the
.recycle
directory but deleted instead.
- Files:
- “Deleted” files retain their POSIX ACLs.
- Conclusion:
- All users need write permissions on the recycle bin directory hierarchy.
- The directory structure is, therefore, revealed to any user.
- The contents of files, on the other hand, remain protected by their original permissions.
Set (top-level) permissions:
# Write permissions for everybody on directories.
# The recursion is only necessary if you have existing directories in the bin.
setfacl -R -m g:"Domain Users":rwx /srv/samba/data/.recycle
setfacl -R -d -m g:"Domain Users":rwx /srv/samba/data/.recycle
Delete Files After 60 Days
To prevent the recycle bin from growing indefinitely we’ll set up a script on the Docker host that runs daily and deletes files and directories in the bin after 60 days.
Create the file /usr/local/bin/samba-recycle-cleanup.sh
with the following content:
#!/bin/bash
RecyclePath=/rpool/encrypted/docker/samba/shares-fs1/data/.recycle
MaxDays=60
# Delete all files created earlier than MaxDays
find $RecyclePath -name "*" -ctime +$MaxDays -type f -delete
# Delete empty directories
find $RecyclePath -name "*" -empty -type d -delete
Make the script executable:
chmod +x /usr/local/bin/samba-recycle-cleanup.sh
Create a cron job to run the script daily one minute after midnight:
crontab -e
Paste the following into the file that opens:
1 0 * * * /usr/local/bin/samba-recycle-cleanup.sh
Access-Based Enumeration (ABE)
What is Access-Based Enumeration (ABE)?
Access-based enumeration is a popular Microsoft technology that has existed in Windows Server since 2003. ABE displays only those files and folders a user has permission to access. It does this by filtering directory listings when a network share is accessed via SMB, removing files or folders the user doesn’t have read permissions for.
Enabling Access-Based Enumeration (ABE) in Samba
Samba has an equivalent to ABE that can be enabled by adding the following to the share definition stanza in smb.conf
:
# Enable access-based enumeration
hide unreadable = yes
Disable the Print Service
To disable print server functionality, add the following to the [global]
stanza of the machine’s config/smb.conf
file:
load printers = no
printing = bsd
printcap name = /dev/null
disable spoolss = yes
Note: this is also a useful configuration for domain controllers.
Backup
My backup solution based on restic works with this Samba file server setup very well, indeed.
Running Samba in an Unprivileged Container
This configuration doesn’t require a privileged Docker container because it doesn’t use Windows permissions (which are stored in the security.NTACL
extended attribute, which is only accessible as root
).
Note: As of Samba 4.18, an alternative location can be specified via the acl_xattr:security_acl_name
configuration option (docs).
Migration from Windows to POSIX ACLs
This section lists the changes for those of you who’re migrating from my earlier setup with Windows ACL.
Remove Settings from smb.conf
global Stanza
map acl inherit
: change fromyes
tono
(default) or remove the line altogether.- With this setting enabled, Samba would attempt to map Windows ACL protection flags to
user.SAMBA_PAI
extended attributes.
- With this setting enabled, Samba would attempt to map Windows ACL protection flags to
Per-Share Stanza
vfs objects
: removeacl_xattr
- We’re not storing Windows ACLs anymore but rely solely on POSIX ACLs.
acl_xattr:ignore system acls = yes
- Remove this line. It’s not honored when the
acl_xattr
VFS module is disabled.
- Remove this line. It’s not honored when the
Add Settings to smb.conf
We’re adding settings the either are not necessary or automatically enabled if the acl_xattr
VFS module is enabled.
Per-Share Stanza
inherit acls = yes
- Always use and propagate default directory ACLs.
- This sets the Unix mode to
0777
on new files and directories.
inherit owner = yes
- The owner of new files and directories is set to the owner of the parent directory.
inherit permissions = yes
- The Unix UGO permissions of new files and directories are inherited from the parent directory.
Remove Samba’s Windows ACL Extended Attributes
find /path/to/samba/share -exec setfattr -x security.NTACL {} \;