rclone iCloud Drive on a Cloud VM: AI Agents for My Obsidian Vault

Table of Contents
Yes, you can use iCloud Drive from a Linux server with rclone’s iclouddrive backend. It is unofficial, it needs an interactive re-login about every 30 days (according to the rclone docs), and if you run it from a datacenter IP it can end with a locked Apple ID, which is what happened to me.
I wanted a small team of AI bots to read and write my Obsidian vault, which lives in iCloud Drive and is used on my iPhone and on two Macs. Apple has no Linux client and no official API, so the bots reach the vault from a shared cloud Linux VM through rclone. This is another episode of my self-hosting series: the Raspberry Pi and Tailscale come from my self-hosting setup.
Short version. rclone’s iclouddrive backend works from a Linux VM with your regular Apple ID password and 2FA (app-specific passwords are not accepted). The session lasts 30 days, then you must log in again by hand.
From a datacenter IP my Apple ID got locked, so now rclone’s traffic leaves through a proxy on my home Raspberry Pi, a guard in my script refuses to run if the IP is wrong, and the bots can only do a few safe things to the vault.
Last verified: November 2026, rclone v1.76.0. The iCloud backend is a reverse-engineered web API and Apple changes it often, so check the rclone docs before you copy anything.
What am I connecting: a vault in iCloud and a few bots? #
My Obsidian vault is synced by iCloud Drive across my iPhone, my work Mac and my personal Mac. I chose iCloud because I already have the storage and it is configured on all my hardware, and I didn’t want another paid service when this one is mine already.
The bots run on a shared cloud Linux VM. They never touch iCloud directly: they use a local mirror of the vault and a helper script, vault.sh, which is the only thing that calls rclone.
bots -> vault.sh -> local mirror -> rclone -> Tailscale tunnel -> proxy on the Pi at home -> iCloud Drive
Can I use iCloud Drive on Linux with rclone? #
Yes. The backend logs in with SRP (Secure Remote Password), the same protocol the iCloud web interface uses, with your regular Apple ID password plus 2FA from a trusted device or an SMS. The docs say that the trust token is valid for 30 days, after which you reauthenticate with rclone config reconnect.
It is a reverse-engineered web API, not an interface supported by Apple, and Apple changes it. Two examples from the rclone repository: Apple blocked the old plaintext sign-in, so the backend moved to SRP (PR #9209), and in mid-2026 Apple’s 2FA validation started returning HTTP 409 even when the code is valid (PR #9660).
This is the remote created by rclone config, with values replaced (the real file holds an encrypted password, cookies and a trust token, which don’t belong in a blog post):
[icloud]
type = iclouddrive
apple_id = <apple-id>
password = *** ENCRYPTED ***
cookies = ***
trust_token = ***
What does “HTTP error 421 Invalid global session” mean in rclone? #
It means iCloud doesn’t accept the session anymore and a new authentication is needed. In rclone’s code a 401 or a 421 is treated as an expired session (a 423 means missing PCS cookies), and rclone tries to authenticate again by itself. If that needs 2FA, it fails with “trust token expired, please reauth” (client.go). The fix is to run the interactive reconnect yourself and approve the 2FA prompt.
On an expired session you can see the 421 with rclone lsf <remote>: -vv. It is the only error in this article I suggest you reproduce on purpose.
| Error | What it means | What I did |
|---|---|---|
HTTP error 421 Invalid global session | Session expired, fresh authentication needed | Interactive rclone config reconnect |
trust token expired, please reauth | rclone tried to log in by itself and 2FA is required | Same, by hand, in a terminal |
authSRPInit error -900007 | In my case, the very first login step, together with the lock on my Apple ID | Unlock the account, wait, don’t retry |
I haven’t found a document from Apple that explains -900007, so the last row is only what happened to me.
What broke, in order? #
On the evening of 9 November, Nota (my archivist bot, more on it later) told me that the session had expired. iCloud was answering with 421 Invalid global session. My scheduled jobs weren’t retrying with a dead token: the synchronization had simply stopped working.
Then rclone config reconnect failed with a wrong-password error. I didn’t save the output (rclone wasn’t logging to a file and I didn’t keep the terminal), so I can’t give you the exact text, and I don’t know whether the lock was already in place at that moment. I redid rclone config in a terminal on the VM, trying two different Apple ID addresses. Both times I got -900007 at the very first step, authSRPInit, before the password was even checked.
That same evening I found out that Apple had locked my Apple ID. I unlocked it myself and decided to wait one day, and to log in again from an IP that Apple already knows.
Why did Apple lock my Apple ID when I ran rclone from a cloud VM? #
My best answer is that Apple saw a few login attempts in a row from a datacenter IP, probably unfamiliar to it. I can’t prove it, and Apple doesn’t publish its rules, so read the following as reports and not as documented behaviour.
In a Xcodes issue about accounts locked after signing in, one person says that both of their Apple IDs were locked when they tried to sign in from a build server in a cloud data center, and that this could be the reason. In an old InflatableDonkey issue from 2017, about a different project, the maintainer lists the usual triggers as repeated re-authentication with the Apple ID password, access from a new IP, and blacklisted IPs or proxies, and says that the real algorithm is not public. My case matches two of them: several password logins in a row, from a new IP.
The long rclone issue about Invalid Session Token contains user-agent workarounds. They are unreliable, I didn’t use them, and I don’t recommend trying to disguise rclone.
Your job should stop at the first authentication failure and not retry, because every retry is another login attempt. If you get -900007, don’t try to reproduce it: check the state of your Apple ID and wait.
How do I send only rclone’s traffic through my home IP? #
Run a small HTTP proxy at home, reachable only over your Tailscale network, and set HTTPS_PROXY for the rclone process only. Apple then sees your residential IP, and nothing else on the VM changes.
The path is: the VM, the Tailscale tunnel to the Pi, tinyproxy on the Pi, my home connection, and then Apple. Only rclone uses it, because the helper script sets HTTPS_PROXY on the rclone command. Everything else on the VM still leaves from the datacenter. I didn’t use an exit node for the whole VM, because all the traffic of all the bots would go through my home line. An SSH SOCKS tunnel didn’t work: from the tailnet the VM can only reach hosts over HTTP and HTTPS.
The setup #
The VM joined my personal tailnet as a normal device. The platform my bots run on has a Tailscale integration, so it took one click and Tailscale’s OAuth consent, and I didn’t install a client by hand. From the tailnet the VM reaches other hosts by their MagicDNS name, but only over HTTP and HTTPS, and it sees only one host: the Raspberry Pi at home, a normal Tailscale node that already runs my other services, like Immich.
On the Pi runs tinyproxy, an HTTP proxy that supports CONNECT, the method used to forward HTTPS without modifying the traffic. I configured it to accept connections only from the tailnet’s address range. This is the redacted shape of the configuration:
# tinyproxy.conf (values replaced)
Port <proxy-port>
Allow <tailnet-address-range>
The variable is set on the rclone command only, not for the whole shell or for a service:
HTTPS_PROXY=http://<proxy-host>:<proxy-port> rclone lsf icloud:Obsidian/<vault> --max-depth 1
The guard that stops before Apple sees the wrong IP #
Before any rclone call, my script asks a public “what is my IP” service for its IPv4 address twice: directly, and through the proxy. It proceeds only if the two answers differ and the proxied one is inside the residential range of my ISP. Otherwise it exits without contacting Apple. My home IP is dynamic, so the check is a range and not a fixed address.
I added the guard because a broken proxy configuration would send the logins out from the datacenter IP without any error, and that is what got me locked.
How do I stop an agent from deleting or overwriting my notes? #
Give it a script with a very small set of allowed actions and not direct access to the files. This is what vault.sh does:
- It never runs
rclone synctoward iCloud, because a sync can delete files on the destination. The onlysyncin the script goes the other way, from iCloud to the local mirror, to refresh it. newcreates a note and refuses to overwrite one that exists already.appenddownloads the note fresh, appends, and checks that size and modification time on iCloud haven’t changed in the meantime. If they did (for example because I edited the note on my phone), it saves the addition as a new note.trashcopies the note to a_Cestino(trash) folder, checks the size of the copy, and only then removes the original. Without--yesit only shows what it would do and the links that point to the note.- Moves and deletions need my approval: the bots propose them, and I decide.
This is a shortened and anonymized excerpt from the real script (in_isp_range stands for a check against the range I’m not publishing, and remote_stat for an lsjson call):
export HTTPS_PROXY="http://<proxy-host>:<proxy-port>" # only this script
# Guard: refuse to touch iCloud unless the exit IP is my residential range
direct=$(env -u HTTPS_PROXY curl -4 -s --max-time 10 https://api.ipify.org || true)
via_pi=$(curl -4 -s --max-time 15 https://api.ipify.org || true)
if [ -z "$via_pi" ] || [ "$via_pi" = "$direct" ] || ! in_isp_range "$via_pi"; then
echo "STOP: proxy not active or unexpected IP. Not contacting iCloud." >&2; exit 9
fi
append) # fresh download, append, re-check, upload
before=$(remote_stat "$REMOTE/$rel")
rclone copyto "$REMOTE/$rel" "$tmp/f.md"
printf '\n%s\n' "$add" >> "$tmp/f.md"
if [ "$before" != "$(remote_stat "$REMOTE/$rel")" ]; then
save_as_new_note; exit 3 # edited elsewhere meanwhile
fi
rclone copyto "$tmp/f.md" "$REMOTE/$rel" ;;
Who gets to touch the vault: an archivist and a human in the loop? #
Nota is the archivist for my vault. The other bots hand items to Nota, and Nota files them: Radar (my news digest), Mela (my nutrition assistant) and Pip (my general assistant) don’t write to the vault themselves. Nota searches the vault read-only and proposes changes, and I approve them.
The re-login with password and 2FA is always done by me, in a terminal, and secrets never go through a chat with a bot. So I decide, Nota proposes, and a script with the smallest set of capabilities I could give it executes.
Should an AI agent have write access to my whole vault? #
Maybe not, and there is a good counter-argument. Some people keep the private vault away from the server entirely and give the agents a separate workspace synced with Git, like in this BSWEN post. I chose iCloud for the reasons I gave at the beginning. If my notes were more sensitive, I would use the Git workspace and keep the vault out of the VM. For me the risk is acceptable because of the guard, the script and the approvals, but it is a risk, and you should decide for your own notes.
There are also Obsidian MCP servers, for example obsidian-mcp and obsidian-web-mcp. My setup has no MCP layer: the boundary is a script with a few allowed actions, and the bots don’t see the vault as a filesystem. I’m not comparing them feature by feature. For where the bots themselves run and how I limit them, I wrote running AI agent sandboxes on AWS Lambda MicroVMs.
What do I do when the trust token expires? #
Run the interactive reconnect yourself, in a terminal, from a network path that Apple already knows (for me, through the same proxy, so Apple sees the same residential IP), and approve the 2FA. Never automate 2FA, and never put the password or the code in a chat. In my setup the job stops at the first authentication error. The docs say 30 days, so a reminder a few days before the expiry is a good idea.
FAQ #
What does “HTTP error 421 Invalid global session” mean in rclone?
The session is not valid anymore. Reconnect the remote interactively with rclone config reconnect <remote>: and approve 2FA.
Why did Apple lock my Apple ID when I used rclone from a cloud VM? I can’t prove it and Apple doesn’t document its rules. My logins came from a datacenter IP, and public reports describe similar locks from cloud servers and repeated password logins.
Does Advanced Data Protection break rclone’s iCloud Drive backend? The current rclone docs say it is supported, with extra steps, while older versions failed with a 423 error.
What do I do when the trust token expires?
Log in again by hand with rclone config reconnect, from a network path Apple already knows, and approve 2FA.
Self-hosting series #
- My self-hosting setup (published).
- Caddy and Tailscale HTTPS with DNS-01 on Route 53 (planned).
- This article.
You can find the rest under the selfhosting tag, including Karakeep with Amazon Nova 2 Lite.
Are you giving your agents access to your notes, and where do you draw the line? Did you hit a locked Apple ID with rclone or another tool? Let me know in the comments, or find me on LinkedIn.