Running the iCloud Drive PDS.

⚠️ You probably shouldn't do this.

So.. you're probably wondering how we got here.

In case you're unaware, a PDS is a "Personal Data Server" for ATProtocol. You can learn more about what a PDS is and how to host one on atproto.com . A PDS is practically just an Express webserver responsible for storing an account's data into an SQLite database. The PDS also communicates with the AppViews of ATProto applications to make actions with said applications.

Running a PDS on iCloud is, pretty silly. But... I did it.

Here's how I did it.

Requirements:

A device that can run Docker, access iCloud Drive, and accept incoming network requests.

Any computer running macOS or Windows should be able to meet these requirements.

About:

I'm simply just running the default compose.yaml Docker Compose file from the official bluesky-social/pds repository, just a bit modified. I'm using OrbStack for running Docker on my Mac.

The main trick here is binding iCloud Drive to Docker. You can see this under volumes:.

Your iCloud Drive is located at /Users/matt/Library/Mobile Documents/com~apple~CloudDocs on your Mac. As you can see, I didn't use that directory in my compose.yaml. Instead, I used a symlink. I'm unsure if this is really needed, but when I tried using the real directory, it just wasn't working.

ln -s "/Users/matt/Library/Mobile Documents/com~apple~CloudDocs/pds" ~/Desktop/pds_shortcut

I simply created a folder on my iCloud Drive called pds, in there I created a pds.env and then blobs and data folders.

For directing traffic to my Mac, I used Tailscale and Caddy. I had my Mac and my Hetzner VPS on the same Tailscale Tailnet, then used Caddy to just reverse proxy from my Hetzner VPS to my Mac through Tailscale's Tailnet. Then I just ran docker compose up on my Mac within the directory where compose.yaml was located, and it was up!

The following is the exact files I used for the whole setup. Please let me know if I missed anything!

Caddyfile

{
email matt@thisdomain.net
on_demand_tls {
ask http://matts-mac-mini:xxxx/tls-check
}
}

*.icloud.mmatt.net, icloud.mmatt.net {
tls {
on_demand
}
reverse_proxy matts-mac-mini:xxxx
}

compose.yaml

version: "3.9"
services:
pds:
container_name: pds
image: ghcr.io/bluesky-social/pds:0.4
network_mode: host
restart: unless-stopped
volumes:
- type: bind
source: /Users/matt/Desktop/pds_shortcut
target: /pds
env_file:
- "/Users/matt/Desktop/pds_shortcut/pds.env"

pds.env

# See more env options in src/config/env.ts
# Hostname - the public domain that you intend to deploy your service at
PDS_HOSTNAME="icloud.mmatt.net"
PDS_PORT="xxxx"

# Database config - use one or the other
PDS_DATA_DIRECTORY="/pds/data"

# Blobstore - filesystem location to store uploaded blobs
PDS_BLOBSTORE_DISK_LOCATION="/pds/blobs"

# Private keys - these are each expected to be 64 char hex strings (256 bit)
PDS_REPO_SIGNING_KEY_K256_PRIVATE_KEY_HEX="xxx"
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX="xxx"

# Secrets - update to secure high-entropy strings
PDS_DPOP_SECRET="xxx"
PDS_JWT_SECRET="xxx"
PDS_ADMIN_PASSWORD="xxx"

# Environment - example is for live network
PDS_DID_PLC_URL="https://plc.directory"
PDS_BSKY_APP_VIEW_URL="https://api.bsky.app"
PDS_BSKY_APP_VIEW_DID="did:web:api.bsky.app"
PDS_CRAWLERS="https://bsky.network"

# OAuth Provider
PDS_OAUTH_PROVIDER_NAME="on da icloud"
PDS_OAUTH_PROVIDER_LOGO=
PDS_OAUTH_PROVIDER_PRIMARY_COLOR="#7507e3"
PDS_OAUTH_PROVIDER_ERROR_COLOR=
PDS_OAUTH_PROVIDER_HOME_LINK=
PDS_OAUTH_PROVIDER_TOS_LINK=
PDS_OAUTH_PROVIDER_POLICY_LINK=
PDS_OAUTH_PROVIDER_SUPPORT_LINK=

# Debugging
NODE_TLS_REJECT_UNAUTHORIZED=1
LOG_ENABLED=true
LOG_LEVEL=debug
PDS_INVITE_REQUIRED=0
PDS_DISABLE_SSRF_PROTECTION=0