- Shell 94%
- Dockerfile 6%
| .forgejo/workflows | ||
| config | ||
| deploy/kubernetes | ||
| rootfs | ||
| secrets | ||
| .cursorignore | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| renovate.json | ||
docker-smb-rclone
Samba file share in Docker (Alpine), with optional per-remote rclone jobs (sync or FUSE mount) under /data.
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.
Without job files in config/jobs/, the container runs Samba only.
Rclone jobs
- Create config from the example (or
rclone config):
cp config/rclone.conf.example config/rclone.conf
# edit remotes / run: rclone config --config config/rclone.conf
- Add one env file per remote/path under
config/jobs/(copy an*.env.example):
cp config/jobs/photos.env.example config/jobs/photos.env
Each job uses a dedicated local directory (default /data/<job-name>) exposed through the single SMB share.
Job fields
| Field | Required | Description |
|---|---|---|
MODE |
yes | sync or mount |
REMOTE |
yes | rclone remote path, e.g. gdrive:Photos |
LOCAL |
no | local path (default /data/<filename-without-.env>) |
DIRECTION |
if MODE=sync |
pull, push, or bisync |
INTERVAL |
no | seconds between sync cycles (default 300) |
EXTRA_ARGS |
no | extra rclone flags |
Modes
| Mode | Behavior |
|---|---|
sync + pull |
rclone sync REMOTE LOCAL (cloud → disk) |
sync + push |
rclone sync LOCAL REMOTE (disk → cloud) |
sync + bisync |
rclone bisync LOCAL REMOTE with --resilient --recover; first run adds --resync |
mount |
long-running rclone mount with --allow-other and SMB uid/gid |
Bisync is an advanced rclone command: conflicts and deletions can cause data loss if misused. Read the rclone bisync docs before enabling it.
Mount needs FUSE on the host (modprobe fuse) and the compose privileges (/dev/fuse, SYS_ADMIN, AppArmor unconfined). Without mount jobs those privileges are unused but harmless.
Layout
config/
rclone.conf # remotes / credentials (gitignored)
jobs/
photos.env # one file per job (gitignored)
data/
photos/ # LOCAL for photos.env
notes/
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 / rclone mount |
SMB_GID |
no | 1000 |
GID for files on disk / rclone mount |
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) |
RCLONE_CONFIG |
no | /config/rclone.conf |
rclone config path |
RCLONE_JOBS_DIR |
no | /config/jobs |
directory of *.env job files |
RCLONE_DEBUG |
no | — | set to yes/1/true/on to enable rclone debug logs and progress during sync/mount |
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
.env,secrets/smb_password,config/rclone.conf, or realconfig/jobs/*.env. - 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, binding, and FUSE (SYS_ADMIN). 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-rclone) + job files (smb-rclone-jobs) |
secret.yaml |
smb_password + rclone.conf (change before apply) |
deployment.yaml |
Pod + PVC for /data, FUSE/SYS_ADMIN/appArmorProfile: Unconfined for mount jobs |
service.yaml |
ClusterIP on TCP 445 |
# edit secret.yaml (password + rclone.conf) and jobs in configmap.yaml
kubectl apply -f deploy/kubernetes/
SMB clients reach //smb-rclone.<namespace>.svc.cluster.local/<SHARE_NAME> (or expose the Service as NodePort / LoadBalancer if needed — only with network controls). Nodes that run mount jobs need the FUSE device (/dev/fuse).
Healthcheck
Every 30s the image checks that smbd is running and TCP 127.0.0.1:445 accepts connections. This does not verify authentication, share contents, or rclone jobs.
Build only
docker build -t docker-smb-rclone .
printf 'changeme' > /tmp/smb_password
docker run --rm -p 445:445 \
--cap-add SYS_ADMIN --device /dev/fuse \
--security-opt apparmor:unconfined --security-opt no-new-privileges \
-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" \
-v "$(pwd)/config:/config:ro" \
docker-smb-rclone