Motivation

I recently got my first iPhone after years of Android. And the first error message I received after moving my data from my old phone to the new phone was: Your iPhone can not be backed up. Huh? Why? Ah! Not enough iCloud Storage! But I’m doing all my backups myself and store them locally. With Android and e.g. LineageOS and SeedVault a setup I was used to. Now it was the challenge to find a solution for iOS. And here we are… How can I create a backup of my iPhone, WIRELESS and without further interaction? And how to monitor it?

libimobiledevice to the rescue

The awesome people from libimobiledevice implemented all necessary iOS APIs in their project. Add [usbmuxd2] (https://github.com/tihmstar/usbmuxd2) and you can use it all via network. During my search I stumbled across a blog post from valinet which gave me the necessary details to get it started.

The Setup

  • Homeassistant
  • a machine which handles your backups or other tasks
    • needs python3.12
    • needs nginx
    • needs libimobiledevice
    • needs usbmuxd2

Installation

Install libimobiledevice either from github or from your package manager e.g. apt install libimobiledevice-utils libimobiledevice-dev. Now install usbmuxd2

git clone https://github.com/tihmstar/libgeneral
cd libgeneral
./autogen.sh --prefix=/usr/local --enable-debug
make
sudo make install
cd ..
sudo apt install libusb-1.0-0-dev libavahi-client-dev
git clone https://github.com/tihmstar/usbmuxd2
cd usbmuxd2
LDFLAGS="-latomic" ./autogen.sh --prefix=/usr/local --enable-debug
make
sudo make install
cd ..

Make sure to install avahi-daemon and open the ports 5353 and 1900 (both UDP) on your backup machines firewall (iptables or ufw or whatever you’re using - you do have the firewall set up, right?).

Create your first backup

Start usbmuxd2 via systemd or from cli, connect your iPhone via USB to the backup host and make sure it’s unlocked so you can “trust” the new device. You should now be able to see your device id with idevice_id -d.

Activate the backup encryption with idevicebackup2 -i encryption on -u $YOUR-DEVICE-ID and set a password for backups (AND NOTE IT DOWN OR STORE IT IN YOUR PASSWORD MANAGER) with idevicebackup2 -i changepw -u $YOUR-DEVICE-ID. You can test the backup now while still connected via usb-cable with idevicebackup2 -i backup --full /mnt/backup-dir/iPhone/Backup -u $YOUR-DEVICE-ID. Now you will be asked for your device PIN. Apple enforces entering the device PIN whenever you create a backup outside iCloud (funny huh?).

If that was successful, you can now enable the WiFi connection with idevicepair wifi on. Unplug your iPhone from your backup machine and run ideviceinfo -n on the machine. You should now see your iPhones UUID. It might take a second and you might need to unlock it or at least activate the screen, so there is a proper network connection from the iPhone to your WiFi - we need Bonjour to work here!

Now you should also be able to trigger a backup over network via idevicebackup2 -n backup --full /mnt/backup-dir/iPhone/Backup -u $YOUR-DEVICE-ID (mind the new -n parameter). If all that worked, you can continue with the next steps.

Trigger the Backup via API

Now we want to trigger that backup via API/Web Call. So we can use an homeautomation like Homeassistant. For this I created a simple Flask app which you can download on github https://github.com/s256/ios-backup

  • clone Repo cd /opt/ && git clone https://github.com/s256/ios-backup & cd ios-backup
  • create virtual environment with virtualenv .venv & source .venv/bin/activate & pip install pipenv
  • install packages pipenv install

Test the setup with uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app running curl -XPOST http://localhost:5000/backup should now trigger the same command and your iPhone should ask for your PIN to start the backup.

If that was successful

  • copy the .service file to your systemd service folder e.g. /etc/systemd/system/
  • systemctl daemon-reload

Prod Setup

Reverse Proxy

Set up a reverse proxy, I preferr nginx so there is an NGINX example file in github.

  • install nginx
  • copy the file from reverseproxy/ to your nginx sites-availableand enable it
    • cp ./reverseproxy/*.conf /etc/nginx/site-available/ && ln -s /etc/nginx/sites-enabled/ios-backup.conf/ /etc/nginx/site-available/nginx-vhost.conf
  • adapt the nginx config file, it assumes you’re using SSL with Let’s encrypt. Set a vhost which fits your local setup.

Home-Assistant

To trigger this command from Home-Assistant, you need to add a Rest-Command in your configuration.yaml.

rest_command:
  iphone_backup:
    url: "https://iosbackup.example.com/backup"
    method: post
    content_type: "application/json"

Add a Helper of type Date so it becomes input_datetime but only accepts Date. This entity is used in the automation to check if you have a recent backup, but also from the flask app to check if there already is a backup from the current day.

Add an Automation, to start the Backup if certain criteria are met, e.g. you are at home and the device is stationary, connected to your wifi and not on focus mode.

alias: "Backup: Start iPhone backup"
description: Backup iPhone
trigger:
  - platform: state
    entity_id:
      - sensor.XXX_iphone_mini_activity
    to: Stationary
    for:
      hours: 0
      minutes: 5
      seconds: 0
condition:
  - condition: state
    entity_id: sensor.XXX_iphone_mini_connection_type
    state: Wi-Fi
  - condition: state
    entity_id: binary_sensor.XXX_iphone_mini_focus
    state: "off"
  - condition: state
    entity_id: sensor.XXX_iphone_mini_ssid
    state: MYWIFISSIDNAME
action:
  - service: rest_command.iphone_mini_backup
    metadata: {}
    data: {}
mode: single

Create an “Alert” to inform you, when there was no recent backup in the last 7 days

alias: "Alert: Old Backup"
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.old_ios_backup
    to: "True"
condition: []
action:
  - service: notify.mobile_app_XXX_iphone_mini
    metadata: {}
    data:
      title: Run a fresh Backup of your phone!
      message: Last Backup is older than 1 week. Time for a new backup of your phone!
mode: single

Config via ENV or .env

Replace all config entries in the .env file or pass them as Environmentvariables, e.g. in the systemd file.

Summary

Now when your phone is connected to your WiFi and idle, Homeassistant triggers the Webcall to your backup machine which runs the idevicebackup utility.