⚠️ 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.neton_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: pdsimage: ghcr.io/bluesky-social/pds:0.4network_mode: hostrestart: unless-stoppedvolumes:- type: bindsource: /Users/matt/Desktop/pds_shortcuttarget: /pdsenv_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 atPDS_HOSTNAME="icloud.mmatt.net"PDS_PORT="xxxx"# Database config - use one or the otherPDS_DATA_DIRECTORY="/pds/data"# Blobstore - filesystem location to store uploaded blobsPDS_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 stringsPDS_DPOP_SECRET="xxx"PDS_JWT_SECRET="xxx"PDS_ADMIN_PASSWORD="xxx"# Environment - example is for live networkPDS_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 ProviderPDS_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=# DebuggingNODE_TLS_REJECT_UNAUTHORIZED=1LOG_ENABLED=trueLOG_LEVEL=debugPDS_INVITE_REQUIRED=0PDS_DISABLE_SSRF_PROTECTION=0