- Shell 89%
- Dockerfile 11%
| .forgejo/workflows | ||
| deploy/kubernetes | ||
| rootfs/app | ||
| secrets | ||
| .cursorignore | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| renovate.json | ||
docker-smb
Samba file share in Docker (Alpine).
License: GPL-3.0.
Quick start
cp .env.example .env
cp secrets/smb_password.example secrets/smb_password
# edit .env (SMB_USER, …) and secrets/smb_password
docker compose up -d --build
Share path on the host: ./data → /data in the container.
Connect with any SMB client to //<host>/<SHARE_NAME> using SMB_USER and the password in secrets/smb_password.
Compose mounts ./secrets/smb_password as SMB_PASSWORD_FILE (not an env var). Do not put the password in .env.
Environment
| Variable | Required | Default | Description |
|---|---|---|---|
SMB_USER |
yes | — | Linux + Samba username ([A-Za-z0-9._-]+) |
SMB_PASSWORD |
one of | — | Password in env (prefer file) |
SMB_PASSWORD_FILE |
one of | — | Path to password file (Compose/K8s default) |
SMB_UID |
no | 1000 |
UID for files on disk |
SMB_GID |
no | 1000 |
GID for files on disk |
SHARE_NAME |
no | share |
SMB share name ([A-Za-z0-9._-]+) |
SHARE_PATH |
no | /data |
Absolute directory served by Samba |
SMB_READ_ONLY |
no | no |
yes or no |
SMB_WORKGROUP |
no | WORKGROUP |
SMB workgroup ([A-Za-z0-9._-]+) |
SMB_ENCRYPT |
no | desired |
SMB encryption: off, desired, or required |
SMB_DEBUG |
no | — | set to yes/1/true/on to send smbd debug logs to stdout (--debuglevel=3) |
If both password vars are set, SMB_PASSWORD_FILE wins.
SMB_ENCRYPT=required rejects clients that do not support SMB encryption.
Match SMB_UID / SMB_GID to the host user that owns ./data when you care about host-side permissions.
Security notes
- Prefer
SMB_PASSWORD_FILEoverSMB_PASSWORD(Compose and Kubernetes examples use a file). - Do not commit
.envorsecrets/smb_password. - Guests are disabled; minimum protocol is SMB2; NetBIOS (
nmbd) is not started. SMB_USER,SHARE_NAME, andSMB_WORKGROUPare validated to blocksmb.confinjection.- The container runs as root so the entrypoint can create the share user and
smbdcan bind TCP 445. Compose and the Kubernetes example useno-new-privileges/allowPrivilegeEscalation: falseand drop all capabilities except those needed for user/share setup and binding. A read-only root filesystem is not used because runtimeuseradd/smb.confwrites need a writable/etc. - Compose publishes
445:445on all host interfaces. Restrict with a host firewall, or bind locally, e.g.127.0.0.1:445:445, unless clients must reach the host from the LAN. - Intended for a trusted LAN or cluster. Do not expose TCP 445 to the internet. For Kubernetes, prefer ClusterIP and a NetworkPolicy; treat NodePort/LoadBalancer as an explicit network-trust decision.
Kubernetes
Example manifests under deploy/kubernetes/:
| File | Role |
|---|---|
configmap.yaml |
Settings (smb) |
secret.yaml |
smb_password (change before apply) |
deployment.yaml |
Pod + PVC for /data |
service.yaml |
ClusterIP on TCP 445 |
# edit secret.yaml (password) and settings in configmap.yaml
kubectl apply -f deploy/kubernetes/
SMB clients reach //smb.<namespace>.svc.cluster.local/<SHARE_NAME> (or expose the Service as NodePort / LoadBalancer if needed — only with network controls).
Healthcheck
Every 30s the image checks that smbd is running and TCP 127.0.0.1:445 accepts connections. This does not verify authentication or share contents.
Build only
docker build -t docker-smb .
printf 'changeme' > /tmp/smb_password
docker run --rm -p 445:445 \
-e SMB_USER=smbuser \
-e SMB_PASSWORD_FILE=/run/secrets/smb_password \
-v /tmp/smb_password:/run/secrets/smb_password:ro \
-v "$(pwd)/data:/data" \
docker-smb