Skip to content

Automated Apple Time Machine backups over Tailscale — Proxmox LXC + Samba server and macOS LaunchAgent client

Notifications You must be signed in to change notification settings

ethermachine/timemachine-tailscale

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

Time Machine over Tailscale

Automated Apple Time Machine backups to a network share accessed via Tailscale.

The Problem

macOS Time Machine relies on mDNS/Bonjour to discover network backup destinations and auto-start backups. Bonjour operates via multicast, which doesn't traverse Tailscale's point-to-point WireGuard tunnels. This means Time Machine will never automatically back up to a Tailscale-reachable SMB share — even though the share is fully accessible.

The Solution

A two-part setup:

  1. Server — A Proxmox LXC container running a Dockerized Samba server configured as a Time Machine target
  2. Client — A macOS LaunchAgent that periodically checks connectivity, mounts the share, triggers tmutil startbackup, and unmounts afterward
┌──────────────┐         WireGuard          ┌──────────────────────────────┐
│              │        (Tailscale)          │  Proxmox VE Host            │
│   macOS      │◄──────────────────────────► │                             │
│              │                             │  ┌────────────────────────┐ │
│  LaunchAgent │                             │  │ LXC Container          │ │
│  runs every  │       SMB over Tailscale    │  │                        │ │
│  2 hours     │ ◄─────────────────────────► │  │  Docker: Samba + TM    │ │
│              │                             │  │                        │ │
│  tmutil      │                             │  └──────────┬─────────────┘ │
│  startbackup │                             │             │ bind mount    │
│              │                             │  ┌──────────▼─────────────┐ │
└──────────────┘                             │  │  /mnt/usb-backup       │ │
                                             │  │  (USB disk / storage)  │ │
                                             │  └────────────────────────┘ │
                                             └──────────────────────────────┘

Prerequisites

  • Proxmox VE host with an LXC container (Debian/Ubuntu) capable of running Docker
  • Tailscale installed on both the LXC container and the Mac
  • A disk (USB, SSD, NAS mount, etc.) available on the Proxmox host for backup storage
  • macOS with Time Machine and Tailscale installed

Server Setup (Proxmox)

1. Create the LXC Container

Create an unprivileged Debian/Ubuntu LXC container with Docker support:

# Key settings for the container (in /etc/pve/lxc/YOUR_CT_ID.conf):
# - features: nesting=1,keyctl=1    (required for Docker)
# - Adequate RAM (2 GB recommended)

If you plan to run Tailscale inside the LXC, also add:

lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

2. Mount Your Backup Disk

On the Proxmox host, mount the disk and create a bind mount for the container:

# Find your disk
lsblk

# Create mount point and add to fstab (adjust UUID and path)
mkdir -p /mnt/your-disk
echo "UUID=YOUR_DISK_UUID /mnt/your-disk ext4 defaults,nofail 0 2" >> /etc/fstab

# Create the directory for Time Machine data
mkdir -p /mnt/your-disk/timemachine

# Bind mount into a path the LXC can access
mkdir -p /mnt/timemachine
echo "/mnt/your-disk/timemachine /mnt/timemachine none bind,nofail 0 0" >> /etc/fstab

mount -a

Add the mount point to the LXC config (/etc/pve/lxc/YOUR_CT_ID.conf):

mp0: /mnt/timemachine,mp=/mnt/timemachine

3. Install Docker in the LXC

# Inside the LXC container
apt update && apt install -y curl
curl -fsSL https://get.docker.com | sh

4. Deploy the Time Machine Container

# Copy the Samba config
mkdir -p /opt/timemachine-config
cp pve/smb.conf /opt/timemachine-config/smb.conf

Edit pve/docker-compose.yml — set your password and adjust volume paths if needed, then:

# Copy compose file and start
cp pve/docker-compose.yml /opt/timemachine-config/
cd /opt/timemachine-config
docker compose up -d

5. Install Tailscale in the LXC

curl -fsSL https://tailscale.com/install.sh | sh
tailscale up

Note the Tailscale hostname (e.g., your-lxc.your-tailnet.ts.net) — you'll need it for the Mac setup.

6. Verify

# Check Samba is running
docker logs timemachine

# Test SMB access from another machine
smbclient -L //localhost -U backup

Mac Setup

1. Store SMB Credentials in Keychain

Connect to the share once manually to save credentials:

  1. In Finder, press Cmd+K
  2. Enter: smb://backup@your-tailscale-hostname/TimeMachine
  3. Enter the password and check "Remember this password in my keychain"

2. Add the Time Machine Destination

sudo tmutil setdestination "smb://backup@your-tailscale-hostname/TimeMachine"

Verify:

tmutil destinationinfo

3. Install the Backup Script

# Create a directory for the script (or use any path you prefer)
mkdir -p ~/Scripts

# Copy and edit the script — update the configuration variables at the top
cp mac/timemachine-backup.sh ~/Scripts/
chmod +x ~/Scripts/timemachine-backup.sh

Edit ~/Scripts/timemachine-backup.sh and set:

Variable Description Example
SMB_URL Full SMB URL for the share smb://backup@my-tm.tail1234.ts.net/TimeMachine
TM_HOST Tailscale hostname to ping my-tm.tail1234.ts.net
BACKUP_INTERVAL Seconds between backups 86400 (24h)
VOLUME_NAME Mount name under /Volumes/ TimeMachine

4. Install the LaunchAgent

# Copy and edit the plist — update paths to match your username and script location
cp mac/com.timemachine-auto.plist ~/Library/LaunchAgents/

# Edit the plist: replace YOUR_USERNAME with your macOS username
sed -i '' "s/YOUR_USERNAME/$(whoami)/g" ~/Library/LaunchAgents/com.timemachine-auto.plist

# Load the agent
launchctl load ~/Library/LaunchAgents/com.timemachine-auto.plist

Configuration Reference

Setting File Default Description
BACKUP_INTERVAL timemachine-backup.sh 86400 (24h) Minimum seconds between backups
SMB_URL timemachine-backup.sh SMB URL matching your tmutil destination
TM_HOST timemachine-backup.sh Tailscale hostname for connectivity check
VOLUME_NAME timemachine-backup.sh TimeMachine Share name as mounted under /Volumes/
StartInterval com.timemachine-auto.plist 7200 (2h) How often the LaunchAgent triggers the script
PASSWORD docker-compose.yml Samba user password
TM_USERNAME docker-compose.yml backup Samba username
fruit:time machine max size smb.conf 1500G Maximum space for Time Machine backups

Useful Commands

Check backup status

# Is a backup running?
tmutil status

# Last backup info
tmutil destinationinfo

# View the automation log
cat ~/Library/Logs/timemachine-auto.log | tail -20

Force a backup now

# Run the script manually
bash ~/Scripts/timemachine-backup.sh

# Or trigger Time Machine directly (share must be mounted)
tmutil startbackup --block

Manage the LaunchAgent

# Stop the agent
launchctl unload ~/Library/LaunchAgents/com.timemachine-auto.plist

# Start the agent
launchctl load ~/Library/LaunchAgents/com.timemachine-auto.plist

# Check if it's loaded
launchctl list | grep timemachine

Reset backup timer

# Force the next check to trigger a backup
rm ~/.timemachine-last-backup

Server-side logs

# Samba logs inside the Docker container
docker logs timemachine

# Follow logs in real time
docker logs -f timemachine

Troubleshooting

Backup never starts

  1. Check Tailscale is connected on both sides: tailscale status
  2. Verify the host is reachable: ping your-tailscale-hostname
  3. Check the script log: cat ~/Library/Logs/timemachine-auto.log
  4. Verify the LaunchAgent is loaded: launchctl list | grep timemachine
  5. Ensure credentials are in keychain: Keychain Access > search for your Tailscale hostname

Mount fails

  • Verify the SMB URL is correct: smb://backup@your-tailscale-hostname/TimeMachine
  • Test manually: Finder > Cmd+K > paste the SMB URL
  • Check Samba is running on the server: docker logs timemachine

"Backup already in progress" in logs

This is normal — it means the LaunchAgent fired while a backup was still running. The script skips to avoid conflicts.

Backup completes but with non-zero exit code

Some exit codes from tmutil are non-fatal (e.g., minor verification warnings). Check the log for details. If backups are completing and data is being written, these can usually be ignored.

Container won't start / permission errors

  • Ensure the LXC has nesting=1,keyctl=1 in features
  • Verify the bind mount is accessible: ls -la /mnt/timemachine inside the LXC
  • Check Docker permissions: docker ps

Disk full

  • Adjust fruit:time machine max size in smb.conf and restart the container
  • Time Machine automatically prunes old backups, but only up to the configured limit

About

Automated Apple Time Machine backups over Tailscale — Proxmox LXC + Samba server and macOS LaunchAgent client

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages