bluesky-social/pds: the official installer for running your own AT Protocol Personal Data Server
Bluesky PDS (Personal Data Server) container image, compose file, and documentation
At a glance
- What is it?
- Bluesky's PDS repository is not the server source code. It is a Docker Compose bundle, an interactive installer, and a runbook for one VPS with one to twenty users. The judgement: adopt it if you want a federated handle on a single host, avoid it if you already run a web server on ports 80 and 443.
- Who is it for?
- Adopt this if you want a federated AT Protocol handle on a dedicated VPS and can accept that the installer owns ports 80 and 443. Do not adopt it if that host already runs a web server, because the README states the script assumes a fresh machine.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The repository is a deployment kit, not the PDS itself
The README answers the question directly under "Where is the code?": the TypeScript implementation lives in bluesky-social/atproto under packages/pds, and the Go implementation lives in bluesky-social/indigo. What this repository holds is the container image, a compose file, and documentation for people who want to run that software rather than read it. The primary language listed for the repository is Shell, which fits: the visible artifact is installer.sh, fetched over curl and executed with sudo.
The audience is narrow and stated. The README recommends Ubuntu 24.04, 1 GB of RAM, 1 CPU core, 20 GB of SSD, and gives a user range of 1 to 20. That range is the whole design envelope. This is not infrastructure for a community of hundreds; it is a way for one person or a small group to hold their own data on hardware they control and still appear in the wider network as a normal handle. The topics on the repository, atproto, bluesky and self-hosted, describe the intent accurately.
What the installer actually does and what it assumes about your machine
The install path is two commands. First curl writes the script to disk, then bash runs it with sudo:
curl https://raw.githubusercontent.com/bluesky-social/pds/main/installer.sh > installer.sh sudo bash installer.sh
The script is interactive. According to the README it prompts for a public DNS address, an admin email address that does not need to be on the same domain, and then walks through creating a PDS user account with its own email address and handle. If you already hold an AT handle elsewhere you can skip that account creation step, and the README suggests creating a test account on your own domain first if this is your first deployment.
The constraint that matters most is buried in a note rather than a warning box. The script assumes a relatively fresh VPS that is not concurrently hosting a web server or anything else on ports 80 and 443. If you intend to run a PDS beside an existing web server on the same machine, the README says you should not use this install script. That is a hard fork in the road, and it is the single most common reason a technically capable operator would need to abandon this path and assemble the compose file by hand.
Caddy, wildcard DNS, and why the certificate story is handled for you
TLS is delegated. The README states there is no need to set up TLS or redirect port 80 to 443 because the Caddy web server included in the Docker compose file handles both. Port 80 exists in this design only for TLS certificate verification; port 443 carries all application requests. That division explains why the cloud firewall section lists exactly two inbound rules and calls misconfigured firewall ports one of the most common sources of trouble.
DNS is the other half. The README gives a two-record table: an A record for example.com and a wildcard A record for *.example.com, both pointing at the server's public IP, with a TTL of 600 described as reasonable. The wildcard is not optional decoration. The README says it is required when allowing users to create new accounts on your PDS, because each new account gets a subdomain handle. Verification is manual and explicit: check example.com, random.example.com and test123.example.com against a resolver service and confirm all three return your server's public IP. If the wildcard is missing, the installer may succeed and account creation will still fail later, which is a worse failure than a refused install.
Account creation, invite codes, and the SMTP dependency
The README documents two paths for creating accounts: a plain creation flow and a creation flow using an invite code. The invite-code path is the lever for closing an open registration surface, and it is worth deciding which one you want before the first account exists rather than after.
SMTP is a separate section with its own troubleshooting subsection, which tells you where operators get stuck. The README does not specify a provider or a set of config keys in the material available here, so the exact environment variables are something you will read from the Environment Variables section of the README on the branch you deploy. What can be said from the structure alone: mail delivery is a real dependency of the account flow, not an optional add-on, and a new domain sending mail for the first time is a familiar source of silent failures. Treat the SMTP setup as a task with its own acceptance test, not as a line item inside the install.
Logging, monitoring and metrics each get their own section, which suggests the distribution ships with some observability surface, but the material here does not name the endpoints or exporters. Verify those against the repository before you promise anyone a dashboard.
The operational work the README names: updates, migration, relay desync
Three headings in the table of contents describe ongoing work rather than setup: Updating your PDS, Migrating your PDS, and Fixing a Relay desync. The last one is the most informative. A relay desync is a state where your PDS and the relay that aggregates the network disagree about your data, and the README treats it as a known condition with a documented fix rather than an incident. That is a fair signal about the maturity of the distribution and also a fair signal about the class of problem you are signing up for: federation means your server's view of the world can drift, and correcting it is your job.
Updates are documented as their own procedure, which means they are not automatic. There are no retrieved releases for this repository, so there is no version number to pin and no changelog to read in the material available. Practically, that pushes the upgrade decision onto the ATProto Touchers Discord that the README links at the top for updates about the PDS distribution. If you need a predictable release cadence with semantic version tags before you commit, this repository does not currently give you one.
Licence status is unresolved in the repository metadata
The repository metadata reports the licence as NOASSERTION, which means GitHub could not match the licence file to a known identifier. The README has a License section, but its contents are not in the material available here, and the underlying server code lives in two other repositories with their own terms. Do not assume the container image, the installer script and the TypeScript PDS share one licence. Read the LICENSE file in this repository and the licence of whichever implementation you deploy, and if the answer matters to your organisation, ask someone qualified rather than treating a metadata field as a conclusion. This is a factual gap, not a legal opinion.
Where a self-hosted PDS is the wrong tool
The clearest wrong-tool case is stated by the project itself: a VPS that already serves something on ports 80 and 443. The installer will fight your existing web server for the ports and for the certificate, and the README tells you not to use it there. You would need to decompose the compose file and reverse-proxy the PDS behind whatever is already running, which is a different project from the one this repository documents.
The second case is scale. The recommendation table caps at 1 to 20 users on 1 GB of RAM and a single core. If your goal is to host accounts for a large group, this distribution is not sized for it, and the README does not pretend otherwise. The third case is maintenance appetite. A PDS is a federated endpoint with a database, a mail path, a TLS certificate and a relay relationship. Someone has to watch updates, handle a desync, and renew the domain. If nobody owns that, the account is better left on a hosted provider.
As an alternative approach, the Bluesky app itself is the obvious comparison and the difference is architectural rather than cosmetic. Using the hosted service means someone else operates the server, holds the data, and absorbs the update and desync work; you get a handle that is not yours to move. Running this PDS inverts that: you own the handle and the data, and you also own the SMTP failures, the wildcard DNS record, the certificate renewal and the relay desync procedure. The choice is not about features. It is about which set of failures you would rather be paged for.
Editorial conclusion
Adopt this if you want a federated AT Protocol handle on a dedicated VPS and can accept that the installer owns ports 80 and 443. Do not adopt it if that host already runs a web server, because the README states the script assumes a fresh machine. Before running anything, confirm your wildcard DNS record resolves, decide whether account creation stays open or moves to invite codes, and check whether your SMTP provider accepts mail from a new domain.
Community notes