docker-timemachine: a container that gives macOS Time Machine a network share
Docker image to run Samba (compatible Time Machine for macOS)
At a glance
- What is it?
- mbentley/docker-timemachine packages Samba, and formerly Netatalk, into a container that macOS can treat as a Time Machine destination. The SMB image is the one that matters now, the AFP variant is deprecated, and the images are published with multi-arch tags plus daily dated snapshots you can pin for six months.
- Who is it for?
- docker-timemachine fits a small lab or a homelab that wants macOS Time Machine backups over the network without a NAS and without installing a file server on the host. It does not fit a fleet that needs management, and it does not fit a setup that already runs Samba or Avahi on the host.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the image actually provides
The repository is a Docker image that runs Samba, or AFP through Netatalk, to provide a compatible Time Machine for macOS.
The Dockerfile shows the shape of it. The base is mbentley/alpine, described as a rebased and repackaged base image that only updates existing packages, and the maintainer label names Matt Bentley. On top of that the image installs attr, avahi, avahi-compat-libdns_sd, avahi-tools, dbus, samba-common-tools, s6 and samba-server. It touches the Samba host file, removes the default smb.conf, clears the Avahi service definitions and creates the dbus run directory, because the container owns its own Samba and Avahi configuration rather than inheriting the host's.
The s6 directory is copied to /etc/s6 and the entrypoint script to the root, with the entrypoint set to the script and the command to s6-svscan over the service directory. That is the s6 supervision model, where each service has its own directory and lifecycle, and it is why the health check script and the supervisord configuration for the AFP variant both exist as separate files at the top level.
The health check is a shell script of its own, and there is a password.txt file for the generated credentials and a util directory, which is where the helper scripts live. The project is AGPL-3.0 licensed, the primary language is Shell, the last push was on 2026-04-07 and there are no GitHub releases, so the images on Docker Hub are the artefacts.
The tag scheme and why dated tags exist
The tag structure is the most useful thing in the documentation, and it answers a question every container project has to answer: how do you pin a version of something that is rebuilt daily.
The multi-arch tags are latest and smb, and they support amd64 and arm64 with the correct tag pulled automatically for the system's architecture. The afp tag has been deprecated in terms of new feature updates and is only available for amd64.
The smb tags also get unique manifests generated daily, in the format smb-YYYYMMDD, for example smb-20210730. Each is a point in time snapshot of the smb tag's manifest that you can pin. The important caveat is stated plainly: these tags remain available on Docker Hub for six months and will not receive security fixes, so you have to move to newer tags as they are published to keep getting updated images. The author's own advice, for anyone who does not care about pinning specific image digests, is simply to use the smb tag.
The explicit architecture tags pull the image for the listed architecture and are bit for bit identical to the multi-arch images. The amd64 ones are latest-smb-amd64 and smb-amd64, based on alpine:latest, and the afp and afp-amd64 images, based on debian:jessie, which the documentation flags as deprecated, still available, not regularly built, and possibly carrying unpatched security vulnerabilities. There are armv7l variants, with a note that new armv7l images are no longer being built because the architecture has been deprecated, and arm64 variants based on alpine:latest.
So the tag list is really a changelog of the project's decisions, and it records a migration from AFP to SMB, a drop of armv7l, and a broadening to arm64.
Running the SMB image with host networking
The example invocation with host networking is the one to understand, because the reason for --net=host is discovery rather than convenience.
docker run -d --restart=always \
--name timemachine \
--net=host \
-e TM_USERNAME="timemachine" \
-e TM_GROUPNAME="timemachine" \
-e PASSWORD="timemachine" \
-e TM_UID="1000" \
-e TM_GID="1000" \
-e SET_PERMISSIONS="false" \
-e VOLUME_SIZE_LIMIT="0" \
-v /path/on/host/to/backup/to/for/timemachine:/opt/timemachine \
--tmpfs /run/samba \
mbentley/timemachine:smbThe environment variables are the whole configuration surface. TM_USERNAME and TM_GROUPNAME set the share identity, PASSWORD sets the credential, TM_UID and TM_GID set the ownership of the files the container writes, SET_PERMISSIONS controls whether it fixes ownership on the mounted volume, and VOLUME_SIZE_LIMIT is set to zero here, which the documentation presents as the default value rather than a limit.
The volume mount is where the backups land, and the note above the example is important: if you change the TM_USERNAME value, that changes the path for the persistent volume, so the existing backups appear to vanish. The tmpfs for /run/samba keeps the Samba runtime state out of the persistent mount, which is the right arrangement because that state is per-run.
The alternative invocation, without host networking, publishes the discovery and service ports explicitly instead:
docker run -d --restart=always \
--name timemachine \
--hostname timemachine \
-p 137:137/udp \
-p 138:138/udp \
-p 139:139 \
-p 445:445 \
-e TM_USERNAME="timemachine" \
-e TM_GROUPNAME="timemachine" \
-e PASSWORD="timemachine" \
-e TM_UID="1000" \
-e TM_GID="1000" \
-e SET_PERMISSIONS="false" \
-e VOLUME_SIZE_LIMIT="0" \
-v /path/on/host/to/backup/to/for/timemachine:/opt/timemachine \
--tmpfs /run/samba \
mbentley/timemachine:smbPort 445 is SMB itself, 137 and 138 are the mDNS discovery ports, and 139 is the NetBIOS session port, which is why the discovery tips section says that without host networking you have to map the share manually in Finder by opening Finder, clicking Shared, and connecting as smb://hostname-or-ip/TimeMachine with your Time Machine credentials.
Discovery, host conflicts and the Kubernetes example
The section on automatic discovery with Avahi explains the trade-off precisely. It works best with --net=host so that discovery can be broadcast. Otherwise you need the ports exposed and the share mapped manually in Finder. Using --net=host only works if you do not already run Samba or Avahi on the host, and there is an alternative where Avahi is configured on the host to act as a reflector so the container advertisements are broadcast to the host network without host networking, and the SMB_PORT option changes the port Samba uses if you would rather not move it.
The conflict warning is expanded in the known issues section and is specific about the Raspberry Pi case: if you are already running Samba or Avahi on the Docker host, or you want to run this on your NAS, using --net=host causes a conflict with that install, and Raspberry Pi users should be aware that there is already an mDNS responder running on the stock Raspberry Pi OS image that will conflict with the one in the container.
There is Kubernetes support as well, with a timemachine-k3s.yaml file as the example for running a Time Machine backup server on a single-node k3s cluster, described as running on a Raspberry Pi 4. The compose files in the repository cover several combinations, including a general one, an SMB one, an SMB armv7l one and an AFP one.
The known issues that will bite you
Two known issues are documented in enough detail to be useful.
The first is a container that fails to start with high CPU usage. The symptom is logs like Failed to start message bus: Failed to bind socket, and the cause is hitting the nofile ulimit. The fix is to make sure your compose file or docker run command has the nofile ulimits adjusted to increase the defaults, and the README points at its own examples for the values to use. This is a container that opens a lot of file descriptors, because Samba watches the shared directory for changes, and the default limit on a container is lower than a Samba install on a host would want.
The second is the armv7l image failing to start with a warning:
s6-svscan: warning: unable to iopause: Operation not permittedThe cause is an issue with the libseccomp2 package, and there are two options. You can disable seccomp for the container by adding the --security-opt seccomp=unconfined argument, which the documentation notes has security implications, or install a backported version of libseccomp2 with wget and dpkg.
The issue was observed on Raspberry Pi OS based on Debian 10 Buster, but the documentation says it may be found on other distributions that commonly use the libseccomp2 version 2.3.3-4. Since new armv7l images are no longer built, this is a historical note for anyone with an existing deployment.
Where docker-timemachine is the wrong choice
The first limitation is that this is a file server in a container, not a backup product. It gives macOS a network share that Time Machine will talk to, and it does nothing about retention, encryption at rest, monitoring of whether backups actually ran, or restoring anything. A NAS with a proper backup application, or a hosted backup service, gives you those. This gives you a destination.
The second is the AFP situation, and the project is direct about it. The AFP variant is deprecated, based on debian:jessie, not regularly built, and possibly carrying unpatched security vulnerabilities, and the documentation strongly suggests migrating to the SMB image because AFP is being deprecated by Apple and the author found SMB much more stable. The default in the latest tag was switched to the SMB variant in October 2020. If you are still running the AFP image, you are running an unmaintained build of a deprecated protocol, and the armv7l images are no longer built at all.
The third is the operational shape. Host networking is the easiest path to automatic discovery and it conflicts with anything else on the host that speaks SMB or mDNS, which on a Raspberry Pi is the default. Publishing the ports manually works but then every Mac needs the share mapped by hand. And a container that is not really managed, no image signing, no release tags in GitHub, a Docker Hub tag that moves daily, is a different risk profile from a package you can pin in a lockfile.
The fair comparison is with running Samba directly on the host, or with a small NAS. Running Samba on the host removes the container layer, the ulimit problem and the port conflict, at the cost of installing and maintaining it on the system. This image is the better choice when the machine is already a container host and you want the file server to be disposable.
Editorial conclusion
docker-timemachine fits a small lab or a homelab that wants macOS Time Machine backups over the network without a NAS and without installing a file server on the host. It does not fit a fleet that needs management, and it does not fit a setup that already runs Samba or Avahi on the host. Before deploying it, use the SMB image rather than AFP, since the AFP variant is deprecated and its documentation warns of unpatched vulnerabilities, check the nofile ulimit if the container fails to start with a message bus bind error, and remember that the dated snapshot tags stop receiving security fixes after six months.
Frequently asked questions
What does the mbentley/docker-timemachine image provide?
It runs Samba, and formerly AFP through Netatalk, in an Alpine based container so macOS can use it as a network Time Machine destination. The image installs avahi for discovery, dbus, s6 for service supervision and the Samba server, with the entrypoint script and the s6 service tree copied into place.
Which image tag should I use?
The smb tag, and it is multi-arch for amd64 and arm64. The afp tag is deprecated, only available for amd64, and its documentation warns it may have unpatched security vulnerabilities. New armv7l images are no longer built, and the default in the latest tag has been the SMB variant since October 2020.
What are the smb-YYYYMMDD tags for?
They are daily generated unique manifests of the smb tag, in the format smb-20210730, that you can pin to for a point in time. They remain available on Docker Hub for six months and will not receive security fixes after that, so you need to move to newer tags to keep getting updated images.
How do I configure the container's user and storage?
Through environment variables. TM_USERNAME and TM_GROUPNAME set the share identity, PASSWORD sets the credential, TM_UID and TM_GID set the ownership of written files, SET_PERMISSIONS controls ownership fixing on the mount, and VOLUME_SIZE_LIMIT sets the limit. The persistent path is mounted at /opt/timemachine, and changing TM_USERNAME changes that path.
What should I do if the container will not start?
Logs like Failed to start message bus: Failed to bind socket together with high CPU usage usually mean the nofile ulimit is too low, so raise the nofile ulimits in your compose file or run command. On armv7l, a warning that s6-svscan cannot iopause comes from the libseccomp2 package and is worked around either with --security-opt seccomp=unconfined or by installing a backported libseccomp2.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mbentley-docker-timemachine)Was this useful?