{
"$type": "site.standard.document",
"canonicalUrl": "https:/finxol.eu/posts/embracing-atproto-pt-1-hosting-pds",
"description": "In this series of posts, I'll explore my journey into setting up my workflows and services for atproto. The first step is setting up my PDS. Let's start with a bit of explanation for all this lingo.",
"path": "/posts/embracing-atproto-pt-1-hosting-pds",
"publishedAt": "2025-09-03T00:00:00.000Z",
"site": "at://did:plc:hpmpe3pzpdtxbmvhlwrevhju/site.standard.publication/3mndozltfas27",
"tags": [
"atproto",
"self-hosting"
],
"textContent": "The Atmosphere Protocol, or atproto for short, is the protocol behind the Bluesky social network.\nIt's \"an open, decentralized network for building social applications.\"\n\n_If you are familiar with ATProto already, skip ahead._\n\nIn atproto's decentralisation model, there are multiple parts that work together and can be hosted separately.\nThis differs from other solutions like ActivityPub, which services like Mastodon implement.\nDan Abramov, who previously worked at Bluesky, made a good write-up explaining the difference.\n\nLet's go over some rough definitions for the important bits. You'll find better explanations in the atproto docs.\n\nPDS\n\nIn atproto, a Personal Data Server (PDS) is a server that hosts a user.\nThat's the place where the user's information lives, and only handles this.\nIt's essentially a user database, but it's decentralised, so it feeds its data to Relays.\n\nRelay\n\nA relay is the part of the stack that ingests all the information sent from the PDSes, and exposes it for use in AppViews.\n\nIt's an optimisation in the network to avoid many-to-many connections between PDSes and AppViews.\n\nAppView\n\nThe AppView is basically the app you use to interact with the atproto service.\nBluesky is an AppView, so are tangled.sh and Smoke Signals.\n\nThey receive all the information from the Relays, and filter out only what they need in order to display it into a usable application.\n\n<img src=\"/posts/embracing-atproto-pt1/atproto.svg\" width=\"100%\" class=\"schema\">\n\nThis means that you can also host and control only part of that stack if you want.\nThe smallest—and most common—part to self-host is the PDS, enabling you to own your data, while still using Bluesky and the same atproto apps.\n\nThat's exactly what I did.\n\nSetting up a PDS\n\nTo set up a PDS, you'll need:\n\n- A server connected to the internet running Debian or Ubuntu (a VPS, a Raspberry Pi, a laptop that's always on, whatever)\n- A domain name\n- Docker\n\nI chose to get a new UpCloud VPS, and use a pds.finxol.io subdomain of my usual domain.\nI could've used one of the other VPSes I have, but I've been meaning to migrate off of Digital Ocean for some time, mainly because it's a bit too expensive for me, but also because I prefer to use European services whenever possible.\n\nThe setup process is super easy and very well explained in their docs.\nThe script sets everything up for you, it even installs docker if it's not there already.\n\nAdapting to my setup\n\nI did have to make a couple tweaks to it to make it play well with the rest of my setup though.\n\nFirst, the script checks the OS version you're running.\nMy VPS is running the latest Debian 13 Trixie, released less than a month ago.\nSince it's not one of the required Debian 11 or 12, the script won't let me continue the install.\nI just added a clause in the script to accept Debian Trixie.\n\nI also made some changes to the compose file.\nI didn't want watchtower to update all my containers constantly, and I was running caddy externally for all my other stuff,\nso I just removed those lines in the compose file and moved the Caddy directives to my root Caddyfile.\n\nHere is the final compose file I ended up with:\n\nOnce the script finished and everything was running, I simply pinged the pds with curl https://pds.finxol.io/xrpc/_health,\ntested the websocket connection as stated in the docs, only with websocat,\nand saw everything working as expected!\n\n_Edit:_\nAlso, make sure the _time_ is right on your server.\nAn incorrect system time will lead to incorrect timestamps in OAuth tokens, getting them rejected by some clients.\nMy server time was off by a few dozen seconds, enough to prevent me from logging into Tangled...\n\nAccount Migration\n\nAnd now we get to the trickier part.\nIf you mess up your account migration, you might lose your existing data (which I'd prefer not to).\n\nI chose to go the easy way and follow Tophhie's blog post.\nThis makes use of Bluesky's very convenient goat atproto CLI tool,\nautomating most of the migration process, with only 5 commands to run.\n\nFollowing these steps, I gathered the required info, ran the migration command, and boom, I now own my atproto identity!\n\nBackups\n\nSince a PDS is basically your entire identity on atproto, it's rather important not to lose it.\nOne way to ensure this is with backups!\n\nI chose a very simple path again: use restic to throw the data into an S3 bucket periodically with crontab.\n\nRestic is a simple CLI backup tool with some cool features:\nit works with \"repositories\", so you get encrypted versioned backups on a multitude of supported storage types.\n\nI once again went with UpCloud's S3 offering.\nIt's dead simple, with a 250GB allowance for 5€/month.\nI know I won't be filling that up with backups any time soon, but I've got some other buckets in there taking up space.\n\nFirst off, I set up the backup repository with restic init and gave it a password.\nThen wrote the backup script and told crontab to run it every day.\n\nHere's my super complex backup script:\n\nI know storing the keys as raw values in there isn't very safe, but I've restricted the S3 access key as much as I can.\nI'll set up a secrets manager at some point in the future.\n\nNow my atproto identity can be restored in case of problems with the VPS!\n\nI might also back it up to something else, maybe Hetzner Object Storage, Proton Drive (through rclone), Scaleway Storage, or some other server over SFTP.\n\nBonus\n\nAs an added bonus, since your PDS stores and serves your identity on the atproto network, you can also have it lie about your age verification status,\nand bypass the age check requirements recently put in place in the UK and other places.\nThis only requires a few extra lines in the Caddyfile:",
"title": "Embracing ATProto, part 1: Setting up a PDS"
}