Samba Server
Samba is a free software re-implementation of the SMB networking protocol.
This integration provides a wrapper around the upstream nixpkgs module to create and manage
a Samba server declaratively, providing some easy to configure features such as:
- define default options to set on all shares
- define shares declaratively
- configure and provision users with samba credentials
- integration to emulate use of openFirewall
options in upstream nixpkgs module, but on a per interface + source IP basis
Example Configurations
Samba Module Options Reference
Basic Public Share
This shows a simple Samba server with a single public share.
provision.fs.samba.server = {
enable = true;
firewall.enable = true; # open firewall for interfaces defined in `interfaces1
interfaces = {
localhost.subnet = "lo";
eth0.subnet = "eth0"; # add external ethernet devices
};
global = {
workgroup = "WORKGROUP";
"bind interfaces only" = "yes";
"server string" = "Samba %v on (%L)";
"netbios name" = "SMBNIX";
"security" = "user";
};
shares.public = {
path = "/pool/public";
browseable = true;
read.only = false;
guest.ok = true;
create.mask = "0644";
directory.mask = "0755";
# force user permissions to a user we create inline below, you can set your own existing user in `users.users` instead
force.user = "smb-public";
force.group = "users";
};
# you can optionally generate a user in `users.users` inline here
users.smb-public = {
uid = 7991; # only required if user doesn't already exist in `users.users`
configureUser = true; # only required if user doesn't already exist in `users.users`
group.name = "users"; # optional
};
};
You can then connect to the server by running
# on samba server
nix shell nixpkgs#cifs-utils
mount.cifs //localhost/public /mnt -o guest
# optionally force the local user/group to a local user on the guest mount
mount.cifs //localhost/public /mnt -o guest,uid=1000,gid=100
# or with username/group
mount.cifs //localhost/public /mnt -o guest,uid=myuser,gid=users
# on another machine accessible via network on eth0
mount.cifs //<samba-ip>/public /mnt -o guest
User Authentication + Generated Passwords
You can also configure samba users, and their access to files.
You can also optionally provision samba users automatically by setting provisionSamba
to true and sambaPasswordFile
to a location
that is readable on the host (like /root/samba-password
) or provisioned by a secrets management framework
like agenix and setting the value to config.agenix.secrets.samba-password.path
.
If you don’t use this option, then you will need to create your own samba users for users in valid.users
with:
# on the samba server
smbpasswd -a smb-user
Example Configuration
users.users.media = {
uid = 2000;
group = "media";
};
users.grousp.media.gid = 2000;
provision.fs.samba.server = {
enable = true;
firewall.enable = true; # open firewall for interfaces defined in `interfaces1
interfaces = {
localhost.subnet = "lo";
eth0.subnet = "eth0"; # add external ethernet devices
};
global = {
workgroup = "WORKGROUP";
"bind interfaces only" = "yes";
"server string" = "Samba %v on (%L)";
"netbios name" = "SMBNIX";
"security" = "user";
};
shares.media = {
path = "/media";
browseable = true;
read.only = false;
create.mask = "0644";
directory.mask = "0755";
# force user permissions to a user we create inline below, you can set your own existing user in `users.users` instead
force.user = "media";
force.group = "media";
valid.users = [ "smb-media" ];
};
users.smb-media = {
uid = 7991; # only required if user doesn't already exist in `users.users`
configureUser = true; # only required if user doesn't already exist in `users.users`
group.name = "users"; # optional
# choose to automatically provision samba
provisionSamba = true;
sambaPasswordFile = "/root/smb-media-password";
};
};
You can then connect to the server by running
# on samba server
nix shell nixpkgs#cifs-utils
mount.cifs //localhost/media /mnt -o user=media,password=mypassword
Define Shared Options
This is configuration equivalent with the above Basic Public Share configuration
provision.fs.samba.server = {
enable = true;
firewall.enable = true; # open firewall for interfaces defined in `interfaces1
interfaces = {
localhost.subnet = "lo";
eth0.subnet = "eth0"; # add external ethernet devices
};
global = {
workgroup = "WORKGROUP";
"bind interfaces only" = "yes";
"server string" = "Samba %v on (%L)";
"netbios name" = "SMBNIX";
"security" = "user";
};
default.opts = {
browseable = true;
read.only = false;
guest.ok = true;
create.mask = "0644";
directory.mask = "0755";
# force user permissions to a user we create inline below, you can set your own existing user in `users.users` instead
force.user = "smb-public";
force.group = "users";
hosts.allow = [ "127.0.0.1" "localhost" ];
};
shares.public.path = "/pool/public";
# optionally override the default options from `default.opts`
shares.public.force.user = "media";
shares.public.force.group = "media";
# NOTE: changing array values like `hosts.allow` doesn't merge the lists, but overrides
shares.public.hosts.allow = [ "10.98.1.0/24" ]; # this would not allow localhost access from the samba server itself
# you can optionally generate a user in `users.users` inline here
users.smb-public = {
uid = 7991; # only required if user doesn't already exist in `users.users`
configureUser = true; # only required if user doesn't already exist in `users.users`
group.name = "users"; # optional
};
};
Samba with Wireguard
I had some issues getting the Samba daemons to listen on wireguard interfaces when using the global bind interfaces only = yes
setting.
Apparently this is due to Wireguard not supporting broadcast and not automatically listening on these interfaces.
You can get around this issue without setting bind interfaces only = no
(so listening on all interfaces) by setting the global interfaces
to include the subnet of your wireguard network, I tend to use the exact wireguard IP for the samba server like 10.8.0.7/24
and it works
well.
A shorthand is provided via the interfaces.<interface-name>.subnet
configuration which sets these values for you.
provision.fs.samba.server = {
enable = true;
firewall.enable = true; # open firewall for interfaces defined in `interfaces1
interfaces = {
localhost.subnet = "lo";
eth0.subnet = "eth0"; # add external ethernet devices
# use the exact wireguard interface name and set the subnet to the samba server's wireguard IP (with mask)
vpn.subnet = "10.8.0.7/24";
};
default.opts = {
# allow VPN subnet by default to shares
hosts.allow = [ "10.8.0.0/24" "127.0.0.1" "localhost" ];
# you can also whitelist specific IPs only if you wish
# hosts.allow = [ "10.8.0.91" "10.8.0.103" "127.0.0.1" "localhost" ];
};
};
Test Configuration
The server + client integrations are tested in tests/samba/basic.nix
..
Troubleshooting
The below is a miscellaneous list of tools you can use to debug issues, or comments on configurations:
- Use
testparm
on the Samba server to show config warnings. smbclient -L localhost --user=smb-user
to list sharessmbstatus
to list current active connections- WARNING: setting guest account to an existing user can create numerous weird permission issues that are hard to debug