Samba / SMB File Sharing
- What Samba is
- Installation
- smb.conf structure
- The [global] section
- Defining a share
- Share types: public, authenticated, admin-only
- Linux filesystem permissions
- Samba users and passwords
- SELinux
- firewalld
- Starting and enabling the service
- Testing the share
- Mounting from a client
- Troubleshooting
- Ansible role pattern
What Samba is
Samba is the Linux implementation of the SMB (Server Message Block) protocol — the same protocol Windows uses for file and printer sharing. It lets Linux hosts share directories that Windows, macOS, and other Linux machines can mount as network drives.
You will encounter Samba when:
- Setting up a shared file store that Windows and Linux clients both need to access
- Providing a home directory server for domain users
- Replacing a Windows file server with a Linux host
- Sharing media or configuration files across a mixed-OS environment
The key packages are samba (the server) and samba-client (the smbclient tool for testing). The main daemon is smbd (handles file and print services) supported by nmbd (handles NetBIOS name resolution) and winbindd (if joining an AD domain).
Installation
# RHEL / Rocky / AlmaLinux
dnf install -y samba samba-client samba-common
# Debian / Ubuntu
apt install -y samba samba-common-bin
The main config file is /etc/samba/smb.conf. Back it up before editing: cp /etc/samba/smb.conf /etc/samba/smb.conf.orig
smb.conf structure
smb.conf uses an INI-style format. Each section header [name] defines either a global setting or a share. The [global] section is special — all other sections define shares.
[global]
workgroup = WORKGROUP
server string = File Server
...
[sharename]
path = /srv/share
...
[homes] # special: per-user home directory shares
...
[printers] # special: printer sharing
...
Lines starting with # or ; are comments. Parameters are name = value. Whitespace around = is ignored. Parameter names are case-insensitive.
The [global] section
[global]
# The Windows workgroup or domain name
workgroup = WORKGROUP
# Displayed in Windows network browser
server string = Linux File Server %v
# Security mode:
# user = require authentication (standard for file servers)
# ads = join Active Directory domain
security = user
# Map unknown users to guest (none = reject them)
map to guest = bad user
# Logging
log file = /var/log/samba/log.%m # %m = client machine name
max log size = 50 # KB before rotating
# Performance
socket options = TCP_NODELAY
# Disable printing if you are not sharing printers
load printers = no
printing = bsd
printcap name = /dev/null
disable spoolss = yes
Defining a share
Each share section defines one directory exported over SMB:
[docs]
comment = Team Documentation
path = /srv/samba/docs # filesystem path to share
browseable = yes # visible in network browser
read only = no # allow writes
writable = yes # same as read only = no
create mask = 0664 # permissions for new files
directory mask = 0775 # permissions for new dirs
valid users = @teamdocs # only this group can connect
write list = @teamdocs # only this group can write
Key parameters explained:
- path — the real filesystem directory being shared. Must exist.
- browseable — show in Windows network browser; set to
nofor hidden admin shares - valid users — comma/space-separated list of users or
@groupnamefor Linux groups; only these identities can connect - write list — subset of valid users who can write even if share is read-only
- create mask — AND mask applied to new file permissions (0664 = rw-rw-r--)
- force group — all files created in the share belong to this group, regardless of the user's primary group
Share types: public, authenticated, admin-only
Public read-only share (no login required)
[public]
comment = Public Files
path = /srv/samba/public
browseable = yes
read only = yes
guest ok = yes # allow unauthenticated access
Authenticated share (login required, everyone in group can write)
[teamshare]
comment = Team Share
path = /srv/samba/team
browseable = yes
writable = yes
create mask = 0664
directory mask = 0775
force group = smbteam # all created files owned by smbteam group
valid users = @smbteam
Admin-only share (hidden, full access)
[admin$]
comment = Admin Share
path = /srv/samba/admin
browseable = no # hidden from browser
writable = yes
valid users = smbadmin
Linux filesystem permissions
Samba enforces both Samba-level access (smb.conf) and Linux filesystem permissions. A user who has Samba permission to write but not Linux write permission on the directory will fail.
# Create the share directory
mkdir -p /srv/samba/team
# Create the Linux group that will own the share
groupadd smbteam
# Set ownership — owned by root, group-owned by smbteam
chown root:smbteam /srv/samba/team
# Permissions: rwxrwsr-x
# setgid bit (s) means new files inherit the group
chmod 2775 /srv/samba/team
# Verify
ls -ld /srv/samba/team
# drwxrwsr-x. 2 root smbteam 6 Apr 10 10:00 /srv/samba/team
The setgid bit (chmod 2775 or chmod g+s) on a directory means new files and subdirectories inherit the directory's group automatically. This is essential for shared team directories — without it, files created by different users end up with different groups and permissions become inconsistent.
Samba users and passwords
Samba maintains its own password database separate from /etc/shadow. A Samba user must:
- Exist as a Linux system user (in
/etc/passwd) - Have a Samba password set with
smbpasswd
# Create a Linux user for Samba (no login shell, no home dir needed if just for file sharing)
useradd -M -s /sbin/nologin alice
# Add alice to the smbteam group
usermod -aG smbteam alice
# Set alice's Samba password
smbpasswd -a alice # adds and sets password
# Enter password: ...
# Enable the account (enabled by default after -a)
smbpasswd -e alice
# Disable an account
smbpasswd -d alice
# Delete a Samba user
smbpasswd -x alice
# List all Samba users
pdbedit -L
pdbedit -Lv # verbose — shows SID, flags, expiry
usermod -aG groupname user), then use valid users = @groupname in smb.conf. This way you manage access by adding/removing group members rather than editing smb.conf.
SELinux
On RHEL/Rocky, SELinux will block Samba from accessing directories unless they are labelled correctly and the right booleans are set.
Label the share directory
# Label with samba_share_t (Samba can read/write these)
semanage fcontext -a -t samba_share_t "/srv/samba(/.*)?"
restorecon -Rv /srv/samba/
# Verify
ls -dZ /srv/samba/team/
# system_u:object_r:samba_share_t:s0 /srv/samba/team/
SELinux booleans for Samba
# List all Samba booleans
getsebool -a | grep samba
# Allow Samba to share any directory under /home
setsebool -P samba_enable_home_dirs on
# Allow Samba to export NFS-mounted directories
setsebool -P samba_share_nfs on
# Allow Samba to act as a domain controller (rarely needed)
setsebool -P samba_domain_controller on
ls -Z on the share directory and look for AVC denials in /var/log/audit/audit.log.
firewalld
Samba uses TCP 445 (SMB direct) and UDP 137/138 + TCP 139 (NetBIOS). The samba firewalld service covers all of these.
# Open the firewall for Samba
firewall-cmd --permanent --add-service=samba
firewall-cmd --reload
# Verify
firewall-cmd --list-services
If you only need file sharing (no NetBIOS name resolution), port 445/tcp alone is sufficient for modern clients. The samba service opens all required ports.
Starting and enabling the service
# Validate config before starting
testparm # syntax check smb.conf
testparm -s # show effective config (no prompts)
# Start and enable
systemctl enable --now smb # RHEL: smb and nmb
systemctl enable --now nmb # NetBIOS name service
# On Debian/Ubuntu the service names differ:
systemctl enable --now smbd
systemctl enable --now nmbd
# Check status
systemctl status smb nmb
Testing the share
# List shares on the local server (as a specific user)
smbclient -L localhost -U alice
# Connect to a specific share interactively
smbclient //localhost/teamshare -U alice
# smb: \> ls (list files)
# smb: \> put file (upload)
# smb: \> get file (download)
# smb: \> quit
# Test as the guest/anonymous user
smbclient //localhost/public -N # -N = no password
The smbclient -L output shows all shares the user can see:
Sharename Type Comment
--------- ---- -------
teamshare Disk Team Share
IPC$ IPC IPC Service
Mounting from a client
Linux client — one-time mount
# Install the client package
dnf install -y cifs-utils # RHEL
apt install -y cifs-utils # Debian
# Mount a share
mount -t cifs //fileserver/teamshare /mnt/team \
-o username=alice,password=secret,uid=1000,gid=1000
# Mount with a credentials file (safer — keeps password out of shell history)
echo "username=alice" > /etc/samba/alice.creds
echo "password=secret" >> /etc/samba/alice.creds
chmod 600 /etc/samba/alice.creds
mount -t cifs //fileserver/teamshare /mnt/team \
-o credentials=/etc/samba/alice.creds,uid=1000,gid=1000
Linux client — persistent mount via /etc/fstab
# Add to /etc/fstab for automatic mounting at boot
//fileserver/teamshare /mnt/team cifs credentials=/etc/samba/alice.creds,uid=1000,gid=1000,_netdev 0 0
_netdev tells the system this filesystem requires the network and should be mounted after the network is up. Without it, a boot-time mount failure can cause the system to hang at boot.
Windows client
# In Windows Run dialog or Explorer address bar:
\\fileserver\teamshare
# Map as a drive letter via command line
net use Z: \\fileserver\teamshare /user:WORKGROUP\alice password
macOS client
Finder → Go → Connect to Server (⌘K): smb://fileserver/teamshare
Troubleshooting
Cannot connect at all
# Is smbd running?
systemctl status smb
# Is port 445 open and listening?
ss -tlnp | grep 445
# Is the firewall allowing it?
firewall-cmd --list-services | grep samba
# Test from another host
smbclient -L fileserver -U alice
"Permission denied" on a file/directory
# Check Linux permissions on the share directory
ls -la /srv/samba/teamshare/
# Check SELinux label
ls -dZ /srv/samba/teamshare/
# Check for SELinux denials
ausearch -m avc -ts recent | grep samba | audit2why
"NT_STATUS_LOGON_FAILURE" — bad credentials
# Is the user in the Samba database?
pdbedit -L | grep alice
# Reset the Samba password
smbpasswd alice
# Is the Linux user enabled?
id alice
"NT_STATUS_ACCESS_DENIED" — connected but cannot read/write
# Check valid users in smb.conf
testparm -s | grep -A 10 "\[teamshare\]"
# Is the user in the required group?
id alice # shows groups
# Add user to group if missing
usermod -aG smbteam alice
Samba log files
# Logs per-client (based on log file = /var/log/samba/log.%m)
ls /var/log/samba/
# Watch the main log
tail -f /var/log/samba/log.smbd
# Increase logging verbosity temporarily (in [global])
# log level = 3
# Then restart: systemctl restart smb
Ansible role pattern
---
# roles/samba/tasks/main.yml
- name: Install Samba
ansible.builtin.package:
name:
- samba
- samba-client
- samba-common
state: present
- name: Create share directories
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
owner: root
group: "{{ item.group }}"
mode: "{{ item.mode | default('2775') }}"
loop: "{{ samba_shares }}"
- name: Deploy smb.conf
ansible.builtin.template:
src: smb.conf.j2
dest: /etc/samba/smb.conf
owner: root
group: root
mode: '0644'
validate: testparm -s %s
notify: Restart Samba
- name: Configure SELinux labels on share paths
community.general.sefcontext:
target: "{{ item.path }}(/.*)?"
setype: samba_share_t
state: present
loop: "{{ samba_shares }}"
notify: Restore SELinux contexts
- name: Open firewall for Samba
ansible.posix.firewalld:
service: samba
permanent: true
state: enabled
notify: Reload firewalld
- name: Enable and start Samba
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: true
loop:
- smb
- nmb
# Example group_vars variable definition
samba_shares:
- path: /srv/samba/team
group: smbteam
comment: Team Share
valid_users: "@smbteam"
writable: "yes"