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
- needs
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 nginxsites-available
and enable itcp ./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.