Sharing Files in My Local Network with Samba, Docker and Ansible


On a daily basis, I work on Linux, but my company uses a VPN that… doesn’t support Linux. Quite simply, there’s no client for it — it exists for Windows and macOS, but not for Linux. As a result, from time to time, I’m forced to use a second machine running Windows — for example, when I need access to environments that are only available through the VPyN. This kind of work often results in various files (logs, documentation, screenshots) that I then need on my primary workstation — the Linux machine. Until now, I’ve been dealing with this by emailing the files to myself, which was extremely inconvenient and time-consuming, especially when a small change was needed in the environment and I had to regenerate logs, take new screenshots, etc.
So I decided to look for a more user-friendly solution — and to use the opportunity to practice the skills I’m currently working on. I chose Samba as a simple, fast, and well-known way to share space between Linux and Windows systems. I combined it with Ansible, which I’m currently learning, and used my thin client, which acts as a local server. Since this project is part of a larger repository where I track my Ansible learning and experiments, it also benefits from GitHub Actions that check syntax and run a linter on every commit.
Why Samba?
Samba is an open-source implementation of the SMB protocol (Server Message Block), originally developed by Microsoft. It enables file and printer sharing between machines running Windows, Linux, or macOS. At least that’s what the internet says — I actually found out that Samba exists on the very same day I decided to solve my Windows–Linux file transfer problem ;) I did a bit of research, and here are my thoughts.
Why not something like NFS or rsync?
I needed full cross-platform support, especially for Windows.
I didn’t want to install third-party tools on each machine.
I wanted a persistent share that just shows up under “Network” in Windows.
Pros of Samba:
Native support in Windows (
\\hostname\share
)Mature, widely used, well-documented
Works great and is super easy to configure in Dockerized environments
Perfect for small home or office networks
Cons:
SMB is more complex than rsync/NFS
Not encrypted by default (not an issue in a home LAN, but something to be aware of)
Requires exposing ports (139, 445), so not ideal for WAN (but I only intend to use it in my local network)
Configuration can be a bit verbose without containers (but I’m using it inside a container, so that’s not a problem)
How it is build
My thin client acts as a local server — quiet, energy-efficient, and perfect for this kind of task.
Samba runs inside a Docker container (
dperson/samba
).The entire setup is provisioned using Ansible — one playbook and the environment is ready.
The username and password are stored in an encrypted
vault.yml
file. I provide the vault password manually each time I run the playbook. This is something I could optimize — for example, by storing the password as a GitHub secret and automatically running the playbook on commits to themain
branch. However, that would require storing the private SSH key to my homelab in GitHub as well, which I’m not comfortable with. That’s why I’ve decided to keep running the playbook manually for now.
How does the dperson/samba container work?
The dperson/samba
container is a lightweight Docker image that lets you quickly spin up a Samba server without fiddling with complex configuration. Its main advantages are simplicity and flexibility:
Minimalist image — it doesn’t include unnecessary tools, which reduces the size and speeds up startup.
Configuration via
command
parameter — instead of a config file, the Samba server is dynamically configured through launch parameters.Automatic user/password mapping — you provide the user and password as a string in the format:
user;password
.Directory sharing — you define a network share with a simple format:
share_name;local_path;read_only;guest_ok;writable
.
In this specific case, it works like this:
A Samba user is added using
samba_user
with passwordsamba_pass
variables from encrypted Vault.A shared folder is created at
/srv/samba_share
(mounted as/mount
in the container).The
share
is available under that name, with write permissions (yes
forwritable
), no guest access (no
forguest_ok
), and is readable (yes
forread_only
).Ports 139 and 445 are exposed and mapped to the host, so Samba is available in the local network.
Let's take a closer look at the samba.yml
playbook
At the heart of this entire project is this small playbook, which does most of the heavy lifting in setting up the shared resource. It’s just two tasks, but quite powerful. Let’s break it down.
You can view the file directly in the repository here.
1. Create share folder for Samba
- name: Create share folder for Samba
ansible.builtin.file:
path: /srv/samba_share
state: directory
mode: "0777"
What it does:
Creates the /srv/samba_share
directory with full access permissions (777) if it doesn't exist.
Why:
This folder will be mapped as a Samba share, so it needs to exist and be writable by everyone (this can be refined later, but full permissions help during testing).
2. Create Docker container with Samba
- name: Create Docker container with Samba
community.docker.docker_container:
name: samba
image: dperson/samba
restart_policy: unless-stopped
published_ports:
- "139:139"
- "445:445"
volumes:
- "/srv/samba_share:/mount"
command:
-u "{{ vault_vars.samba_user }};{{ vault_vars.samba_pass }}"
-s "share;/mount;yes;no;yes"
What it does:
Starts (or updates) a Docker container named samba
using the dperson/samba
image.
SMB ports (139 and 445) are exposed to the host.
The volume
/srv/samba_share
is mounted into the container as/mount
.command
configures Samba with the user, password, and share.The container auto-restarts if it stops.
Why:
This gives you a ready-to-use Samba server that auto-starts with the system and shares the specified folder
3. Vault
Although not a task itself, Vault is a crucial part of this project. For Ansible to recognize and use the encrypted variables correctly, the encrypted file should be placed in the appropriate location.
There are two options:
Use group variables (
group_vars
)Use host variables (
host_vars
)
I chose the second option. Therefore, my file is located at /inventory/host_vars/node1hp.yml
. The file name must match the host name you're targeting in your playbook. (Similarly for groups, the file must match the group name.)
Before encryption, the file should look like this:
samba_user: "username"
samba_pass: "secretpassword"
To encrypt file:
ansible-vault encrypt inventory/host_vars/[name_of_your_host].yml
To edit the encrypted file later:
ansible-vault edit inventory/host_vars/[name_of_your_host].yml
How it works (from the user’s perspective)
In the end, the whole setup works seamlessly and makes my life easier when I have to switch between machines with different operating systems at work.
Before starting to work from Linux, it’s a good idea to mount the Samba folder locally for quick and easy access:
sudo mount -t cifs //192.168.1.50/share ~/samba_share -o username={enter username here}
On the Linux machine, I drop files into
/srv/samba_share
.On the Windows machine, I open
\\192.168.X.X\share
and I’m good to go.The password is configured once — inside the container.
Why Ansible?
There were several reasons for using Ansible:
Repeatability – I can redeploy this in a minute with confidence that it will always work the same way.
Practice - I'm currently learning Ansible through books and exercises, but hands-on, real-world practice adds much more value. It’s great to use both in parallel.
Documentation – The playbook also serves as documentation of my setup.
Additionallyy, I use GitHub Actions with a linter and syntax checker to ensure consistency and quality across all playbooks. You can see that here.
Result
In the end, I solved a real-world problem that had been irritatingly slowing me down at work — no more emailing files back and forth, I can switch between machines more quickly, and I always have access to the files I need regardless of which computer I'm using.
Bonus: it was a perfect excuse to dive deeper into:
Ansible
Ansible Vault
Docker
And I got to make practical use of my homelab.
Repository
You can find the complete code here.
Subscribe to my newsletter
Read articles from Przemysław Kozłowski directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Przemysław Kozłowski
Przemysław Kozłowski
I'm a software developer with over 10 years of experience in the IT industry. I began my career as a C# developer and, after a few years, had the opportunity to explore Node.js. That experience completely captivated me, and I decided to shift my focus toward JavaScript and backend development with Node.js — though I’ve continued to contribute to a long-term C# side project as well. In the past two years, I’ve also ventured into the world of DevOps. It was a completely new area for me, and I started from scratch. It's been an exciting challenge — since then, every day has been filled with learning and new experiences. This journey inspired me to document my progress and reflections by starting this blog as a learning journal. Currently, I'm particularly focused on improving my understanding of networking — an area I’ve always found challenging — as well as deepening my skills in Docker and Ansible. I’m also planning to set up a Kubernetes cluster in my home lab to begin learning container orchestration hands-on. Additionally, I’ve started learning Python, which I see as a powerful tool for automation and scripting in the DevOps toolkit. The purpose of this blog is to document my learning journey and track my progress, but also to share knowledge and support others who are just beginning their DevOps path and considering a career transition into this field. Outside of tech, I'm a happy father of two boys. I've managed to pass on my love for retro games, swimming and cycling to them. I dedicate most of my free time to being with them — and when I do have a moment to myself, I usually spend it on my road bike.